diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6d9ec92f3..b51c7d8a5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -61,6 +61,5 @@ jobs: - name: Build all Fabric versions run: ./gradlew :fabric:1.20.1:remapJar :fabric:1.21.1:remapJar :fabric:1.21.4:remapJar --build-cache - # Build both Sponge modules (legacy API 7 and modern API 11+) - - name: Build Sponge modules - run: ./gradlew :BanManagerSponge:shadowJar :BanManagerSponge7:shadowJar --build-cache + - name: Build Sponge module + run: ./gradlew :BanManagerSponge:shadowJar --build-cache diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index e20837b3f..1a62824b2 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -55,7 +55,6 @@ jobs: :BanManagerBungee:shadowJar :BanManagerVelocity:shadowJar :BanManagerSponge:shadowJar - :BanManagerSponge7:shadowJar :fabric:1.20.1:remapJar :fabric:1.21.1:remapJar :fabric:1.21.4:remapJar @@ -71,7 +70,6 @@ jobs: bungee/build/libs/BanManagerBungeeCord.jar velocity/build/libs/BanManagerVelocity.jar sponge/build/libs/BanManagerSponge.jar - sponge-api7/build/libs/BanManagerSponge7.jar fabric/versions/1.20.1/build/libs/BanManagerFabric-mc1.20.1.jar fabric/versions/1.21.1/build/libs/BanManagerFabric-mc1.21.1.jar fabric/versions/1.21.4/build/libs/BanManagerFabric-mc1.21.4.jar @@ -139,12 +137,6 @@ jobs: mc_version: "1.21.3" java_image: "java21" spongeversion: "1.21.3-13.0.0" - # Sponge API 7 (Legacy - MC 1.12.2, Java 8) - - platform: Sponge7-1.12.2 - task: testSponge7 - compose_dir: platforms/sponge7 - mc_version: "1.12.2" - java_image: "java8" # Velocity Proxy - platform: Velocity task: testVelocity diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 773f72801..7dbbdc063 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -48,9 +48,8 @@ jobs: - name: Build all Fabric versions run: ./gradlew :fabric:1.20.1:remapJar :fabric:1.21.1:remapJar :fabric:1.21.4:remapJar :fabric:1.21.11:remapJar --build-cache - # Build both Sponge modules (legacy API 7 and modern API 11+) - - name: Build Sponge modules - run: ./gradlew :BanManagerSponge:shadowJar :BanManagerSponge7:shadowJar --build-cache + - name: Build Sponge module + run: ./gradlew :BanManagerSponge:shadowJar --build-cache - name: Get version from tag id: version @@ -73,7 +72,6 @@ jobs: [Download BungeeCord](https://github.com/BanManagement/BanManager/releases/download/v${{ steps.version.outputs.VERSION }}/BanManagerBungeeCord.jar) [Download Velocity](https://github.com/BanManagement/BanManager/releases/download/v${{ steps.version.outputs.VERSION }}/BanManagerVelocity.jar) [Download Sponge](https://github.com/BanManagement/BanManager/releases/download/v${{ steps.version.outputs.VERSION }}/BanManagerSponge.jar) - [Download Sponge 7](https://github.com/BanManagement/BanManager/releases/download/v${{ steps.version.outputs.VERSION }}/BanManagerSponge7.jar) [Download Fabric 1.20.1](https://github.com/BanManagement/BanManager/releases/download/v${{ steps.version.outputs.VERSION }}/BanManagerFabric-mc1.20.1.jar) [Download Fabric 1.21.1](https://github.com/BanManagement/BanManager/releases/download/v${{ steps.version.outputs.VERSION }}/BanManagerFabric-mc1.21.1.jar) [Download Fabric 1.21.4](https://github.com/BanManagement/BanManager/releases/download/v${{ steps.version.outputs.VERSION }}/BanManagerFabric-mc1.21.4.jar) @@ -83,7 +81,6 @@ jobs: bungee/build/libs/BanManagerBungeeCord.jar velocity/build/libs/BanManagerVelocity.jar sponge/build/libs/BanManagerSponge.jar - sponge-api7/build/libs/BanManagerSponge7.jar fabric/versions/1.20.1/build/libs/BanManagerFabric-mc1.20.1.jar fabric/versions/1.21.1/build/libs/BanManagerFabric-mc1.21.1.jar fabric/versions/1.21.4/build/libs/BanManagerFabric-mc1.21.4.jar diff --git a/buildSrc/src/main/kotlin/CommonConfig.kt b/buildSrc/src/main/kotlin/CommonConfig.kt index f0ce03904..e8f5ab4c2 100644 --- a/buildSrc/src/main/kotlin/CommonConfig.kt +++ b/buildSrc/src/main/kotlin/CommonConfig.kt @@ -27,12 +27,12 @@ fun Project.applyCommonConfiguration() { } } - // Only set Java 1.8 for non-Fabric modules + // Set Java 17 for non-Fabric modules // Fabric uses toolchain configuration in its build.gradle.kts plugins.withId("java") { if (!plugins.hasPlugin("fabric-loom")) { - the().setSourceCompatibility("1.8") - the().setTargetCompatibility("1.8") + the().setSourceCompatibility("17") + the().setTargetCompatibility("17") } } } diff --git a/buildSrc/src/main/kotlin/LibsConfig.kt b/buildSrc/src/main/kotlin/LibsConfig.kt index 6d7670891..95f47871d 100644 --- a/buildSrc/src/main/kotlin/LibsConfig.kt +++ b/buildSrc/src/main/kotlin/LibsConfig.kt @@ -38,8 +38,8 @@ fun Project.applyLibrariesConfiguration() { } plugins.withId("java") { - the().setSourceCompatibility("1.8") - the().setTargetCompatibility("1.8") + the().setSourceCompatibility("17") + the().setTargetCompatibility("17") } group = "${rootProject.group}.BanManagerLibs" @@ -100,7 +100,7 @@ fun Project.applyLibrariesConfiguration() { attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY)) attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED)) attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements.JAR)) - attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 8) + attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) } outgoing.artifact(tasks.named("jar")) } @@ -115,7 +115,7 @@ fun Project.applyLibrariesConfiguration() { attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY)) attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED)) attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements.JAR)) - attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 8) + attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) } outgoing.artifact(tasks.named("jar")) } diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index e6a67a496..3a969842c 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -1,5 +1,5 @@ object Versions { const val JUNIT = "4.13" const val MOCKITO = "3.7.7" - const val ADVENTURE = "4.9.3" + const val ADVENTURE = "4.21.0" } diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index f037b407b..c494940b0 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -80,6 +80,9 @@ dependencies { "compileOnly"("org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT") { exclude("junit", "junit") } + "compileOnly"("net.kyori:adventure-api:${Versions.ADVENTURE}") + "compileOnly"("net.kyori:adventure-text-serializer-gson:${Versions.ADVENTURE}") + "compileOnly"("net.kyori:adventure-text-serializer-json:${Versions.ADVENTURE}") "compileOnly"("me.clip:placeholderapi:2.10.9") "shadeOnly"("org.bstats:bstats-bukkit:2.2.1") "shadeOnly"("org.slf4j:slf4j-api:1.7.36") diff --git a/bukkit/src/main/java/me/confuser/banmanager/bukkit/BMBukkitPlugin.java b/bukkit/src/main/java/me/confuser/banmanager/bukkit/BMBukkitPlugin.java index a9dc048f1..735710449 100644 --- a/bukkit/src/main/java/me/confuser/banmanager/bukkit/BMBukkitPlugin.java +++ b/bukkit/src/main/java/me/confuser/banmanager/bukkit/BMBukkitPlugin.java @@ -38,7 +38,7 @@ public class BMBukkitPlugin extends JavaPlugin { "webhooks.yml", "exemptions.yml", "geoip.yml", - "messages.yml", + "notifications.yml", "reasons.yml", "schedules.yml" }; diff --git a/bukkit/src/main/java/me/confuser/banmanager/bukkit/BukkitPlayer.java b/bukkit/src/main/java/me/confuser/banmanager/bukkit/BukkitPlayer.java index d204b3d63..b0557e077 100644 --- a/bukkit/src/main/java/me/confuser/banmanager/bukkit/BukkitPlayer.java +++ b/bukkit/src/main/java/me/confuser/banmanager/bukkit/BukkitPlayer.java @@ -4,13 +4,18 @@ import me.confuser.banmanager.common.CommonPlayer; import me.confuser.banmanager.common.CommonWorld; import me.confuser.banmanager.common.data.PlayerData; +import me.confuser.banmanager.common.kyori.text.Component; import me.confuser.banmanager.common.kyori.text.TextComponent; import me.confuser.banmanager.common.kyori.text.serializer.gson.GsonComponentSerializer; import me.confuser.banmanager.common.util.Message; +import me.confuser.banmanager.common.util.MessageRenderer; +import me.confuser.banmanager.common.util.MessageRegistry; import me.confuser.banmanager.common.util.UUIDUtils; +import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.chat.ComponentSerializer; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.Sound; import org.bukkit.entity.Player; import java.net.InetAddress; @@ -18,6 +23,18 @@ import java.util.UUID; public class BukkitPlayer implements CommonPlayer { + private static final boolean PAPER_ADVENTURE; + + static { + boolean paper = false; + try { + Class.forName("io.papermc.paper.adventure.PaperAdventure"); + paper = true; + } catch (ClassNotFoundException ignored) { + } + PAPER_ADVENTURE = paper; + } + private Player player; private final UUID uuid; private InetAddress address; @@ -44,6 +61,15 @@ public void kick(String message) { getPlayer().kickPlayer(BukkitServer.formatMessage(message)); } + @Override + public void kick(Component component) { + if (PAPER_ADVENTURE) { + PaperAdventureHelper.kick(getPlayer(), component); + } else { + kick(MessageRenderer.getInstance().toLegacy(component)); + } + } + public void sendMessage(String message) { if(message.isEmpty()) return; @@ -54,8 +80,47 @@ public void sendMessage(String message) { } } - public void sendMessage(Message message) { - sendMessage(message.toString()); + @Override + public void sendMessage(Component component) { + if (PAPER_ADVENTURE) { + PaperAdventureHelper.sendMessage(getPlayer(), component); + } else { + String json = MessageRenderer.getInstance().toJson(component); + getPlayer().spigot().sendMessage(ComponentSerializer.parse(json)); + } + } + + @Override + public void sendActionBar(Component component) { + if (PAPER_ADVENTURE) { + PaperAdventureHelper.sendActionBar(getPlayer(), component); + } else { + String json = MessageRenderer.getInstance().toJson(component); + getPlayer().spigot().sendMessage(ChatMessageType.ACTION_BAR, ComponentSerializer.parse(json)); + } + } + + @Override + public void showTitle(Component title, Component subtitle, int fadeIn, int stay, int fadeOut) { + if (PAPER_ADVENTURE) { + PaperAdventureHelper.showTitle(getPlayer(), title, subtitle, fadeIn, stay, fadeOut); + } else { + MessageRenderer renderer = MessageRenderer.getInstance(); + String legacyTitle = title != null ? renderer.toLegacy(title) : ""; + String legacySubtitle = subtitle != null ? renderer.toLegacy(subtitle) : ""; + getPlayer().sendTitle(legacyTitle, legacySubtitle, fadeIn, stay, fadeOut); + } + } + + @Override + public void playSound(String sound, float volume, float pitch) { + Player p = getPlayer(); + if (p == null) return; + try { + p.playSound(p.getLocation(), sound, volume, pitch); + } catch (IllegalArgumentException ignored) { + // Invalid sound key -- silently ignore + } } @Override @@ -125,6 +190,13 @@ public boolean isOnline() { return getPlayer() != null; } + @Override + public String getLocale() { + Player p = getPlayer(); + if (p == null) return "en"; + return MessageRegistry.normaliseLocale(p.getLocale()); + } + private Player getPlayer() { if (player != null) return player; if (isOnlineMode()) return Bukkit.getServer().getPlayer(uuid); diff --git a/bukkit/src/main/java/me/confuser/banmanager/bukkit/BukkitSender.java b/bukkit/src/main/java/me/confuser/banmanager/bukkit/BukkitSender.java index c767f29e2..1e88df583 100644 --- a/bukkit/src/main/java/me/confuser/banmanager/bukkit/BukkitSender.java +++ b/bukkit/src/main/java/me/confuser/banmanager/bukkit/BukkitSender.java @@ -35,11 +35,6 @@ public void sendMessage(String message) { sender.sendMessage(BukkitServer.formatMessage(message)); } - @Override - public void sendMessage(Message message) { - sendMessage(message.toString()); - } - @Override public boolean isConsole() { return !(sender instanceof Player); diff --git a/bukkit/src/main/java/me/confuser/banmanager/bukkit/BukkitServer.java b/bukkit/src/main/java/me/confuser/banmanager/bukkit/BukkitServer.java index e6d070ac7..a2cabe782 100644 --- a/bukkit/src/main/java/me/confuser/banmanager/bukkit/BukkitServer.java +++ b/bukkit/src/main/java/me/confuser/banmanager/bukkit/BukkitServer.java @@ -5,7 +5,6 @@ import me.confuser.banmanager.common.api.events.CommonEvent; import me.confuser.banmanager.common.commands.CommonSender; import me.confuser.banmanager.common.data.*; -import me.confuser.banmanager.common.kyori.text.TextComponent; import me.confuser.banmanager.common.util.ColorUtils; import me.confuser.banmanager.common.util.Message; import org.bukkit.Bukkit; @@ -17,7 +16,6 @@ import org.bukkit.entity.Player; import org.bukkit.permissions.Permissible; -import java.util.Arrays; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; @@ -82,13 +80,6 @@ public void broadcast(String message, String permission) { } } - @Override - public void broadcastJSON(TextComponent message, String permission) { - Arrays.stream(getOnlinePlayers()).forEach(player -> { - if (player.hasPermission(permission)) player.sendJSONMessage(message); - }); - } - @Override public void broadcast(String message, String permission, CommonSender sender) { broadcast(message, permission); diff --git a/bukkit/src/main/java/me/confuser/banmanager/bukkit/PaperAdventureHelper.java b/bukkit/src/main/java/me/confuser/banmanager/bukkit/PaperAdventureHelper.java new file mode 100644 index 000000000..632b58d35 --- /dev/null +++ b/bukkit/src/main/java/me/confuser/banmanager/bukkit/PaperAdventureHelper.java @@ -0,0 +1,74 @@ +package me.confuser.banmanager.bukkit; + +import me.confuser.banmanager.common.kyori.text.Component; +import me.confuser.banmanager.common.util.MessageRenderer; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.kyori.adventure.title.Title; +import org.bukkit.entity.Player; + +import java.time.Duration; + +/** + * Paper-only helper that uses native Adventure API for zero-overhead Component delivery. + * Paper's Player implements Audience, so we cast to Audience for Adventure methods. + * This class must only be loaded when Paper's Adventure API is on the classpath. + */ +class PaperAdventureHelper { + + private static final java.lang.reflect.Method KICK_METHOD; + + static { + java.lang.reflect.Method m = null; + try { + m = Player.class.getMethod("kick", net.kyori.adventure.text.Component.class); + } catch (NoSuchMethodException e) { + // Expected on older Paper/Spigot versions without Component-based kick + } + KICK_METHOD = m; + } + + private PaperAdventureHelper() {} + + static void sendMessage(Player player, Component component) { + ((Audience) player).sendMessage(convertToNative(component)); + } + + static void sendActionBar(Player player, Component component) { + ((Audience) player).sendActionBar(convertToNative(component)); + } + + static void showTitle(Player player, Component title, Component subtitle, + int fadeIn, int stay, int fadeOut) { + net.kyori.adventure.text.Component nativeTitle = title != null + ? convertToNative(title) : net.kyori.adventure.text.Component.empty(); + net.kyori.adventure.text.Component nativeSubtitle = subtitle != null + ? convertToNative(subtitle) : net.kyori.adventure.text.Component.empty(); + + Title.Times times = Title.Times.times( + Duration.ofMillis(fadeIn * 50L), + Duration.ofMillis(stay * 50L), + Duration.ofMillis(fadeOut * 50L) + ); + ((Audience) player).showTitle(Title.title(nativeTitle, nativeSubtitle, times)); + } + + static void kick(Player player, Component component) { + if (KICK_METHOD != null) { + try { + KICK_METHOD.invoke(player, convertToNative(component)); + return; + } catch (IllegalAccessException e) { + java.util.logging.Logger.getLogger("BanManager").warning("Failed to invoke Paper kick method, falling back to legacy: " + e.getMessage()); + } catch (java.lang.reflect.InvocationTargetException e) { + throw new IllegalStateException("Failed to kick player", e.getCause()); + } + } + player.kickPlayer(MessageRenderer.getInstance().toLegacy(component)); + } + + private static net.kyori.adventure.text.Component convertToNative(Component component) { + String json = MessageRenderer.getInstance().toJson(component); + return GsonComponentSerializer.gson().deserialize(json); + } +} diff --git a/bukkit/src/main/java/me/confuser/banmanager/bukkit/listeners/JoinListener.java b/bukkit/src/main/java/me/confuser/banmanager/bukkit/listeners/JoinListener.java index acd283dc5..4c7fbe8f3 100644 --- a/bukkit/src/main/java/me/confuser/banmanager/bukkit/listeners/JoinListener.java +++ b/bukkit/src/main/java/me/confuser/banmanager/bukkit/listeners/JoinListener.java @@ -60,14 +60,15 @@ private class BanJoinHandler implements CommonJoinHandler { @Override public void handlePlayerDeny(PlayerData player, Message message) { plugin.getServer().callEvent("PlayerDeniedEvent", player, message); - - handleDeny(message); + String locale = player.getLocale() != null ? player.getLocale() : "en"; + event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_BANNED); + event.setKickMessage(BukkitServer.formatMessage(MessageRenderer.getInstance().toLegacy(message.resolveComponent(locale)))); } @Override public void handleDeny(Message message) { event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_BANNED); - event.setKickMessage(BukkitServer.formatMessage(message.toString())); + event.setKickMessage(BukkitServer.formatMessage(MessageRenderer.getInstance().toLegacy(message.resolveComponent()))); } } @@ -82,7 +83,8 @@ public void handlePlayerDeny(PlayerData player, Message message) { @Override public void handleDeny(Message message) { - event.disallow(PlayerLoginEvent.Result.KICK_BANNED, message.toString()); + event.disallow(PlayerLoginEvent.Result.KICK_BANNED, + BukkitServer.formatMessage(MessageRenderer.getInstance().toLegacy(message.resolveComponent()))); } } } diff --git a/bungee/src/main/java/me/confuser/banmanager/bungee/BMBungeePlugin.java b/bungee/src/main/java/me/confuser/banmanager/bungee/BMBungeePlugin.java index 5e1b66d55..ea4b96d18 100755 --- a/bungee/src/main/java/me/confuser/banmanager/bungee/BMBungeePlugin.java +++ b/bungee/src/main/java/me/confuser/banmanager/bungee/BMBungeePlugin.java @@ -33,7 +33,7 @@ public class BMBungeePlugin extends Plugin { "webhooks.yml", "exemptions.yml", "geoip.yml", - "messages.yml", + "notifications.yml", "reasons.yml", "schedules.yml" }; diff --git a/bungee/src/main/java/me/confuser/banmanager/bungee/BungeePlayer.java b/bungee/src/main/java/me/confuser/banmanager/bungee/BungeePlayer.java index 1f8e7a381..2a573ce03 100755 --- a/bungee/src/main/java/me/confuser/banmanager/bungee/BungeePlayer.java +++ b/bungee/src/main/java/me/confuser/banmanager/bungee/BungeePlayer.java @@ -4,8 +4,12 @@ import me.confuser.banmanager.common.CommonWorld; import me.confuser.banmanager.common.commands.CommonCommand; import me.confuser.banmanager.common.data.PlayerData; +import me.confuser.banmanager.common.kyori.text.Component; import me.confuser.banmanager.common.kyori.text.TextComponent; import me.confuser.banmanager.common.util.Message; +import me.confuser.banmanager.common.util.MessageRenderer; +import me.confuser.banmanager.common.util.MessageRegistry; +import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.chat.ComponentSerializer; @@ -29,6 +33,12 @@ public void kick(String message) { player.disconnect(BungeeServer.formatMessage(message)); } + @Override + public void kick(Component component) { + String json = MessageRenderer.getInstance().toJson(component); + player.disconnect(ComponentSerializer.parse(json)); + } + @Override public void sendMessage(String message) { if(message.isEmpty()) return; @@ -41,8 +51,15 @@ public void sendMessage(String message) { } @Override - public void sendMessage(Message message) { - sendMessage(message.toString()); + public void sendMessage(Component component) { + String json = MessageRenderer.getInstance().toJson(component); + player.sendMessage(ComponentSerializer.parse(json)); + } + + @Override + public void sendActionBar(Component component) { + String json = MessageRenderer.getInstance().toJson(component); + player.sendMessage(ChatMessageType.ACTION_BAR, ComponentSerializer.parse(json)); } @Override @@ -110,6 +127,13 @@ public boolean canSee(CommonPlayer player) { return true; } + @Override + public String getLocale() { + java.util.Locale locale = player.getLocale(); + if (locale == null) return "en"; + return MessageRegistry.normaliseLocale(locale.toString()); + } + private ProxiedPlayer getPlayer() { return ProxyServer.getInstance().getPlayer(uuid); } diff --git a/bungee/src/main/java/me/confuser/banmanager/bungee/BungeeSender.java b/bungee/src/main/java/me/confuser/banmanager/bungee/BungeeSender.java index 9eb5beba0..7c5c46992 100755 --- a/bungee/src/main/java/me/confuser/banmanager/bungee/BungeeSender.java +++ b/bungee/src/main/java/me/confuser/banmanager/bungee/BungeeSender.java @@ -4,7 +4,6 @@ import me.confuser.banmanager.common.commands.CommonCommand; import me.confuser.banmanager.common.commands.CommonSender; import me.confuser.banmanager.common.data.PlayerData; -import me.confuser.banmanager.common.util.Message; import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.connection.ProxiedPlayer; @@ -33,11 +32,6 @@ public void sendMessage(String message) { sender.sendMessage(BungeeServer.formatMessage(message)); } - @Override - public void sendMessage(Message message) { - sendMessage(message.toString()); - } - @Override public boolean isConsole() { return !(sender instanceof ProxiedPlayer); diff --git a/bungee/src/main/java/me/confuser/banmanager/bungee/BungeeServer.java b/bungee/src/main/java/me/confuser/banmanager/bungee/BungeeServer.java index a325a374c..496a47786 100755 --- a/bungee/src/main/java/me/confuser/banmanager/bungee/BungeeServer.java +++ b/bungee/src/main/java/me/confuser/banmanager/bungee/BungeeServer.java @@ -5,7 +5,7 @@ import me.confuser.banmanager.common.api.events.CommonEvent; import me.confuser.banmanager.common.commands.CommonSender; import me.confuser.banmanager.common.data.*; -import me.confuser.banmanager.common.kyori.text.TextComponent; +import me.confuser.banmanager.common.kyori.text.Component; import me.confuser.banmanager.common.kyori.text.serializer.gson.GsonComponentSerializer; import me.confuser.banmanager.common.util.ColorUtils; import me.confuser.banmanager.common.util.Message; @@ -69,15 +69,6 @@ public void broadcast(String message, String permission) { } } - @Override - public void broadcastJSON(TextComponent message, String permission) { - for (ProxiedPlayer player : ProxyServer.getInstance().getPlayers()) { - if (player != null && player.hasPermission(permission)) { - player.sendMessage(formatMessage(message)); - } - } - } - @Override public void broadcast(String message, String permission, CommonSender sender) { broadcast(message, permission); @@ -237,7 +228,7 @@ public static BaseComponent[] formatMessage(String message) { return ComponentSerializer.parse(json); } - public static BaseComponent[] formatMessage(TextComponent message) { + public static BaseComponent[] formatMessage(Component message) { return ComponentSerializer.parse(GsonComponentSerializer.gson().serialize(message)); } diff --git a/bungee/src/main/java/me/confuser/banmanager/bungee/listeners/JoinListener.java b/bungee/src/main/java/me/confuser/banmanager/bungee/listeners/JoinListener.java index 3b35e4a09..43f3f861d 100755 --- a/bungee/src/main/java/me/confuser/banmanager/bungee/listeners/JoinListener.java +++ b/bungee/src/main/java/me/confuser/banmanager/bungee/listeners/JoinListener.java @@ -58,14 +58,15 @@ private class BanJoinHandler implements CommonJoinHandler { @Override public void handlePlayerDeny(PlayerData player, Message message) { plugin.getServer().callEvent("PlayerDeniedEvent", player, message); - - handleDeny(message); + String locale = player.getLocale() != null ? player.getLocale() : "en"; + event.setCancelled(true); + event.setCancelReason(BungeeServer.formatMessage(message.resolveComponent(locale))); } @Override public void handleDeny(Message message) { event.setCancelled(true); - event.setCancelReason(BungeeServer.formatMessage(message.toString())); + event.setCancelReason(BungeeServer.formatMessage(message.resolveComponent())); } } @@ -80,7 +81,7 @@ public void handlePlayerDeny(PlayerData player, Message message) { @Override public void handleDeny(Message message) { - event.getPlayer().disconnect(BungeeServer.formatMessage(message.toString())); + event.getPlayer().disconnect(BungeeServer.formatMessage(message.resolveComponent())); } } } diff --git a/common/src/main/java/me/confuser/banmanager/common/BanManagerPlugin.java b/common/src/main/java/me/confuser/banmanager/common/BanManagerPlugin.java index ac0c8a452..b0fa85e7c 100644 --- a/common/src/main/java/me/confuser/banmanager/common/BanManagerPlugin.java +++ b/common/src/main/java/me/confuser/banmanager/common/BanManagerPlugin.java @@ -14,6 +14,7 @@ import me.confuser.banmanager.common.ormlite.logger.LocalLog; import me.confuser.banmanager.common.ormlite.support.ConnectionSource; import me.confuser.banmanager.common.ormlite.support.DatabaseConnection; +import me.confuser.banmanager.common.configuration.file.YamlConfiguration; import me.confuser.banmanager.common.runnables.Runner; import me.confuser.banmanager.common.storage.*; import me.confuser.banmanager.common.storage.global.*; @@ -21,16 +22,42 @@ import me.confuser.banmanager.common.storage.mariadb.MariaDBDatabase; import me.confuser.banmanager.common.storage.mysql.MySQLDatabase; import me.confuser.banmanager.common.util.DriverManagerUtil; +import me.confuser.banmanager.common.util.Message; +import me.confuser.banmanager.common.util.MessageRegistry; +import me.confuser.banmanager.common.util.MessageRenderer; -import java.io.File; -import java.io.IOException; +import java.io.*; +import java.nio.file.Files; import java.sql.SQLException; +import java.util.*; import static java.lang.Long.parseLong; public class BanManagerPlugin { private static BanManagerPlugin self; + // Token names used by commands/listeners via Message.set(). Hardcoded because these are + // defined across many source files and not available at runtime as a registry. Used only + // to warn admins when a static token in messages.yml collides with a built-in name. + private static final Set BUILTIN_TOKENS; + + static { + String[] rawNames = {"player", "playerId", "actor", "reason", "expires", "id", + "message", "displayName", "ip", "players", "name", "type", "created", + "amount", "bans", "mutes", "warns", "warnPoints", "kicks", "notes", + "reports", "count", "page", "maxPage", "state", "from", "to", + "from_ip", "to_ip", "index", "uuid", "size", "remaining", + "firstSeen", "lastSeen", "updated", "country", "countryIso", "city", + "meta", "file", "rows", "command", "comment", "world", "x", "y", "z", + "hashtag", "points", "join", "leave", "lastChecked", "types", + "rangebans", "action"}; + Set normalised = new HashSet<>(); + for (String name : rawNames) { + normalised.add(MessageRenderer.normaliseTagName(name)); + } + BUILTIN_TOKENS = Collections.unmodifiableSet(normalised); + } + /* * This block prevents the Maven Shade plugin to remove the specified classes */ @@ -64,6 +91,8 @@ public class BanManagerPlugin { private GeoIpConfig geoIpConfig; @Getter private WebhookConfig webhookConfig; + @Getter + private NotificationsConfig notificationsConfig; // Connections @Getter @@ -153,6 +182,9 @@ public class BanManagerPlugin { @Getter private PlaceholderResolver placeholderResolver; + @Getter + private MessageRegistry messageRegistry; + public BanManagerPlugin(PluginInfo pluginInfo, CommonLogger logger, File dataFolder, CommonScheduler scheduler, CommonServer server, CommonMetrics metrics) { this.pluginInfo = pluginInfo; this.logger = logger; @@ -268,11 +300,6 @@ public final void disable() { } public void setupConfigs() { - MessagesConfig newMessagesConfig = new MessagesConfig(dataFolder, logger); - if (!newMessagesConfig.load()) { - logger.warning("Failed to reload messages.yml, keeping previous messages"); - } - config = reloadConfig(new DefaultConfig(dataFolder, logger), config, "config.yml"); consoleConfig = reloadConfig(new ConsoleConfig(dataFolder, logger), consoleConfig, "console.yml"); schedulesConfig = reloadConfig(new SchedulesConfig(dataFolder, logger), schedulesConfig, "schedules.yml"); @@ -280,6 +307,160 @@ public void setupConfigs() { reasonsConfig = reloadConfig(new ReasonsConfig(dataFolder, logger), reasonsConfig, "reasons.yml"); geoIpConfig = reloadConfig(new GeoIpConfig(dataFolder, logger), geoIpConfig, "geoip.yml"); webhookConfig = reloadConfig(new WebhookConfig(dataFolder, logger), webhookConfig, "webhooks.yml"); + notificationsConfig = reloadConfig(new NotificationsConfig(dataFolder, logger), notificationsConfig, "notifications.yml"); + + loadMessages(); + } + + private void loadMessages() { + String defaultLocale = config != null ? config.getDefaultLocale() : "en"; + MessageRegistry newRegistry = new MessageRegistry(defaultLocale); + + // Clear static tokens before loading so removed tokens don't persist across reloads + MessageRenderer renderer = MessageRenderer.getInstance(); + renderer.loadStaticTokens(Collections.emptyMap()); + + copyMessagesDirectory(); + + File messagesDir = new File(dataFolder, "messages"); + if (messagesDir.exists() && messagesDir.isDirectory()) { + File[] files = messagesDir.listFiles((dir, name) -> + name.startsWith("messages_") && name.endsWith(".yml")); + + if (files != null) { + for (File file : files) { + String fileName = file.getName(); + String locale = fileName.substring("messages_".length(), fileName.length() - ".yml".length()); + loadLocaleFile(newRegistry, file, locale); + } + } + } + + File legacyMessages = new File(dataFolder, "messages.yml"); + if (legacyMessages.exists()) { + logger.warning("Found legacy messages.yml in your data folder. BanManager v8 uses messages/messages_" + defaultLocale + ".yml. Please migrate your customisations to that file and delete messages.yml. The legacy file will continue to be loaded for now to preserve your customisations."); + loadLocaleFile(newRegistry, legacyMessages, defaultLocale); + } + + if (!newRegistry.hasAnyMessages()) { + if (messageRegistry != null) { + logger.warning("No messages loaded, keeping previous messages"); + return; + } + } + + if (messageRegistry != null) { + messageRegistry.atomicSwap(newRegistry); + } else { + messageRegistry = newRegistry; + } + + Message.init(messageRegistry, logger); + + if (renderer.getStaticTokens() != null) { + for (String tokenName : renderer.getStaticTokens().keySet()) { + if (BUILTIN_TOKENS.contains(tokenName)) { + logger.warning("Static token '" + tokenName + "' collides with a built-in token and will be overridden at runtime"); + } + } + } + + logLocaleInfo(); + } + + private void logLocaleInfo() { + if (messageRegistry == null) return; + + Set locales = messageRegistry.getAvailableLocales(); + logger.info("Loaded " + locales.size() + " locale(s): " + String.join(", ", locales)); + + String defaultLocale = messageRegistry.getDefaultLocale(); + for (String locale : locales) { + if (locale.equals(defaultLocale)) continue; + int missing = messageRegistry.getMissingKeyCount(locale); + if (missing > 0) { + logger.info("Locale '" + locale + "' is missing " + missing + " key(s) (will fall back to '" + defaultLocale + "')"); + } + } + } + + private void loadLocaleFile(MessageRegistry registry, File file, String locale) { + try { + YamlConfiguration conf = new YamlConfiguration(); + conf.load(file); + + if (conf.getConfigurationSection("messages") == null) { + logger.warning("Messages section not found in " + file.getName() + ", skipping"); + return; + } + + Map messages = new HashMap<>(); + MessageRenderer renderer = MessageRenderer.getInstance(); + int rejectedCount = 0; + + for (String key : conf.getConfigurationSection("messages").getKeys(true)) { + String value = conf.getString("messages." + key); + if (value != null) { + String processed = value.replace("\\n", "\n").replaceAll("(?<=\\n)(?=\\n)", " "); + if (renderer.isLegacyFormat(processed)) { + logger.severe("Message '" + key + "' in " + file.getName() + " contains legacy &-code formatting and has been skipped. Please convert to MiniMessage format: https://docs.advntr.dev/minimessage/format.html"); + rejectedCount++; + continue; + } + messages.put(key, processed); + } + } + + if (rejectedCount > 0) { + logger.severe(rejectedCount + " message(s) in " + file.getName() + " were rejected due to legacy formatting. Bundled defaults will be used for those keys."); + } + + if (!messages.isEmpty()) { + Map existing = registry.getMessages(locale); + if (!existing.isEmpty()) { + Map merged = new HashMap<>(existing); + merged.putAll(messages); + registry.loadLocale(locale, merged); + } else { + registry.loadLocale(locale, messages); + } + } + + if (conf.getConfigurationSection("tokens") != null) { + Map tokens = new HashMap<>(); + for (String key : conf.getConfigurationSection("tokens").getKeys(false)) { + String value = conf.getString("tokens." + key); + if (value != null) { + tokens.put(key, value); + } + } + if (!tokens.isEmpty()) { + Map existing = new HashMap<>(renderer.getStaticTokens()); + existing.putAll(tokens); + renderer.loadStaticTokens(existing); + } + } + } catch (Exception e) { + logger.warning("Failed to load " + file.getName(), e); + } + } + + private void copyMessagesDirectory() { + File messagesDir = new File(dataFolder, "messages"); + if (!messagesDir.exists()) { + messagesDir.mkdirs(); + } + + File defaultMessages = new File(messagesDir, "messages_en.yml"); + if (!defaultMessages.exists()) { + try (InputStream in = getClass().getClassLoader().getResourceAsStream("messages/messages_en.yml")) { + if (in != null) { + Files.copy(in, defaultMessages.toPath()); + } + } catch (IOException e) { + logger.warning("Failed to copy default messages_en.yml", e); + } + } } /** @@ -482,7 +663,8 @@ public CommonCommand[] getCommands() { new UnmuteCommand(this), new UnmuteIpCommand(this), new UtilsCommand(this), - new WarnCommand(this) + new WarnCommand(this), + new BmCommand(this) }; } diff --git a/common/src/main/java/me/confuser/banmanager/common/CommonPlayer.java b/common/src/main/java/me/confuser/banmanager/common/CommonPlayer.java index 338ffe1c3..769b7ba74 100644 --- a/common/src/main/java/me/confuser/banmanager/common/CommonPlayer.java +++ b/common/src/main/java/me/confuser/banmanager/common/CommonPlayer.java @@ -2,8 +2,10 @@ import me.confuser.banmanager.common.commands.CommonSender; import me.confuser.banmanager.common.data.PlayerData; +import me.confuser.banmanager.common.kyori.text.Component; import me.confuser.banmanager.common.kyori.text.TextComponent; import me.confuser.banmanager.common.util.Message; +import me.confuser.banmanager.common.util.MessageRenderer; import java.net.InetAddress; import java.util.UUID; @@ -12,9 +14,36 @@ public interface CommonPlayer extends CommonSender { void kick(String message); + default void kick(Message message) { + kick(message.resolveComponentFor(this)); + } + + default void kick(Component component) { + kick(MessageRenderer.getInstance().toLegacy(component)); + } + void sendMessage(String message); - void sendMessage(Message message); + @Override + default void sendMessage(Message message) { + sendMessage(message.resolveComponentFor(this)); + } + + @Override + default void sendMessage(Component component) { + sendMessage(MessageRenderer.getInstance().toLegacy(component)); + } + + default void sendActionBar(Component component) { + sendMessage(component); + } + + default void showTitle(Component title, Component subtitle, int fadeIn, int stay, int fadeOut) { + if (title != null) sendMessage(title); + if (subtitle != null) sendMessage(subtitle); + } + + default void playSound(String sound, float volume, float pitch) { } void sendJSONMessage(TextComponent jsonString); @@ -43,4 +72,6 @@ public interface CommonPlayer extends CommonSender { boolean teleport(CommonWorld world, double x, double y, double z, float pitch, float yaw); boolean canSee(CommonPlayer player); + + String getLocale(); } diff --git a/common/src/main/java/me/confuser/banmanager/common/CommonServer.java b/common/src/main/java/me/confuser/banmanager/common/CommonServer.java index 74af21dd2..4fc39b669 100644 --- a/common/src/main/java/me/confuser/banmanager/common/CommonServer.java +++ b/common/src/main/java/me/confuser/banmanager/common/CommonServer.java @@ -2,7 +2,9 @@ import me.confuser.banmanager.common.api.events.CommonEvent; import me.confuser.banmanager.common.commands.CommonSender; -import me.confuser.banmanager.common.kyori.text.TextComponent; +import me.confuser.banmanager.common.kyori.text.Component; +import me.confuser.banmanager.common.util.Message; +import me.confuser.banmanager.common.util.MessageRenderer; import java.util.UUID; @@ -17,7 +19,24 @@ public interface CommonServer { void broadcast(String message, String permission); - void broadcastJSON(TextComponent message, String permission); + default void broadcast(Message message, String permission) { + for (CommonPlayer player : getOnlinePlayers()) { + if (player.hasPermission(permission)) { + player.sendMessage(message.resolveComponentFor(player)); + } + } + getConsoleSender().sendMessage(MessageRenderer.getInstance().toPlainText(message.resolveComponent())); + } + + // Console receives plain text since it cannot render Components with hover/click events + default void broadcast(Component message, String permission) { + for (CommonPlayer player : getOnlinePlayers()) { + if (player.hasPermission(permission)) { + player.sendMessage(message); + } + } + getConsoleSender().sendMessage(MessageRenderer.getInstance().toPlainText(message)); + } void broadcast(String message, String permission, CommonSender sender); diff --git a/common/src/main/java/me/confuser/banmanager/common/api/BmAPI.java b/common/src/main/java/me/confuser/banmanager/common/api/BmAPI.java index 37e808a0b..6808bd251 100644 --- a/common/src/main/java/me/confuser/banmanager/common/api/BmAPI.java +++ b/common/src/main/java/me/confuser/banmanager/common/api/BmAPI.java @@ -615,7 +615,7 @@ public static String getPlayerNameAt(UUID uuid, long timestamp) throws SQLExcept /** * @param key The message config node within messages.yml, e.g. "ban.notify" - * @return String + * @return A Message instance that can be resolved to a Component via resolveComponent() */ public static Message getMessage(String key) { return Message.get(key); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/ActivityCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/ActivityCommand.java index d567b643d..fb81a73b5 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/ActivityCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/ActivityCommand.java @@ -55,7 +55,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { } if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", parser.args[1]).toString()); + Message.get("sender.error.notFound").set("player", parser.args[1]).sendTo(sender); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/AddNoteCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/AddNoteCommand.java index 1e2a876a0..ba8e6bea3 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/AddNoteCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/AddNoteCommand.java @@ -39,7 +39,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final PlayerData player = getPlayer(sender, playerName, true); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return; } @@ -49,7 +49,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { getPlugin().getPlayerNoteStorage().addNote(warning); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute addnote command", e); } }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/BanCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/BanCommand.java index 275e28b15..2bf32dcfd 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/BanCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/BanCommand.java @@ -4,6 +4,7 @@ import me.confuser.banmanager.common.CommonPlayer; import me.confuser.banmanager.common.data.PlayerBanData; import me.confuser.banmanager.common.data.PlayerData; +import me.confuser.banmanager.common.util.DateUtils; import me.confuser.banmanager.common.util.Message; import java.sql.SQLException; @@ -40,12 +41,12 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { final TargetResolver.TargetResult target = TargetResolver.resolveTarget(getPlugin().getServer(), playerName); if (target.getStatus() == TargetResolver.TargetStatus.NOT_FOUND) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return true; } if (target.getStatus() == TargetResolver.TargetStatus.AMBIGUOUS) { - sender.sendMessage(Message.get("sender.error.ambiguousPlayer").set("player", playerName).toString()); + Message.get("sender.error.ambiguousPlayer").set("player", playerName).sendTo(sender); return true; } @@ -64,7 +65,7 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { try { isBanned = getPlugin().getPlayerBanStorage().isBanned(UUID.fromString(playerName)); } catch (IllegalArgumentException e) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return true; } } else { @@ -75,7 +76,7 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { Message message = Message.get("ban.error.exists"); message.set("player", targetName); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -93,12 +94,12 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { final PlayerData player = getPlayer(sender, targetName, true); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", targetName).toString()); + Message.get("sender.error.notFound").set("player", targetName).sendTo(sender); return; } if (getPlugin().getExemptionsConfig().isExempt(player, "ban")) { - sender.sendMessage(Message.get("sender.error.exempt").set("player", targetName).toString()); + Message.get("sender.error.exempt").set("player", targetName).sendTo(sender); return; } @@ -108,7 +109,7 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { return; } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute ban command", e); return; } @@ -130,7 +131,7 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { try { getPlugin().getPlayerBanStorage().unban(ban, actor); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute ban command", e); return; } @@ -142,12 +143,14 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { Message kickMessage = null; if (onlinePlayer != null) { + String dateTimeFormat = Message.getString("ban.player.dateTimeFormat"); kickMessage = Message.get("ban.player.kick") .set("displayName", onlinePlayer.getDisplayName()) .set("player", player.getName()) .set("playerId", player.getUUID().toString()) .set("reason", ban.getReason()) - .set("actor", actor.getName()); + .set("actor", actor.getName()) + .set("created", DateUtils.format(dateTimeFormat != null ? dateTimeFormat : "yyyy-MM-dd HH:mm:ss", ban.getCreated())); } try { @@ -167,7 +170,7 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { if (onlinePlayer != null) { final Message finalKickMessage = kickMessage; getPlugin().getScheduler().runSync(() -> { - onlinePlayer.kick(finalKickMessage.toString()); + onlinePlayer.kick(finalKickMessage); }); } }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/BanIpCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/BanIpCommand.java index f5cb640e8..f4669779d 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/BanIpCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/BanIpCommand.java @@ -48,7 +48,7 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { Message message = Message.get("sender.error.invalidIp"); message.set("ip", ipStr); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -66,7 +66,7 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { final IPAddress ip = getIp(ipStr); if (ip == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", ipStr).toString()); + Message.get("sender.error.notFound").set("player", ipStr).sendTo(sender); return; } @@ -76,7 +76,7 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { Message message = Message.get("banip.error.exists"); message.set("ip", ipStr); - sender.sendMessage(message.toString()); + message.sendTo(sender); return; } @@ -86,7 +86,7 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { return; } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute banip command", e); return; } @@ -100,7 +100,7 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { try { getPlugin().getIpBanStorage().unban(ban, actor); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute banip command", e); return; } @@ -130,7 +130,7 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { for (CommonPlayer onlinePlayer : getPlugin().getServer().getOnlinePlayers()) { if (IPUtils.toIPAddress(onlinePlayer.getAddress()).equals(ip)) { - onlinePlayer.kick(kickMessage.toString()); + onlinePlayer.kick(kickMessage); } } }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/BanIpRangeCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/BanIpRangeCommand.java index 5c7428c73..4725fb019 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/BanIpRangeCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/BanIpRangeCommand.java @@ -82,7 +82,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { for (CommonPlayer onlinePlayer : getPlugin().getServer().getOnlinePlayers()) { if (ban.inRange(IPUtils.toIPAddress(onlinePlayer.getAddress()))) { - onlinePlayer.kick(kickMessage.toString()); + onlinePlayer.kick(kickMessage); } } }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/BanListCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/BanListCommand.java index 398284b1f..50df49260 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/BanListCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/BanListCommand.java @@ -4,7 +4,12 @@ import me.confuser.banmanager.common.data.IpBanData; import me.confuser.banmanager.common.data.IpRangeBanData; import me.confuser.banmanager.common.data.PlayerBanData; +import me.confuser.banmanager.common.kyori.text.Component; import me.confuser.banmanager.common.util.Message; +import me.confuser.banmanager.common.util.PaginatedView; + +import java.util.ArrayList; +import java.util.List; public class BanListCommand extends CommonCommand { @@ -14,16 +19,23 @@ public BanListCommand(BanManagerPlugin plugin) { @Override public boolean onCommand(CommonSender sender, CommandParser parser) { - if (parser.args.length > 1) return false; + if (parser.args.length > 2) return false; String type = "players"; + int page = 1; - if (parser.args.length == 1) { + if (parser.args.length >= 1) { type = parser.args[0]; } + if (parser.args.length == 2) { + try { + page = Integer.parseInt(parser.args[1]); + } catch (NumberFormatException e) { + return false; + } + } - StringBuilder list = new StringBuilder(); - int total = 0; + List items = new ArrayList<>(); if (type.startsWith("play")) { if (!sender.hasPermission(getPermission() + ".players")) { @@ -32,10 +44,10 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { } for (PlayerBanData ban : getPlugin().getPlayerBanStorage().getBans().values()) { - list.append(ban.getPlayer().getName()); - list.append(", "); - - total++; + items.add(Message.get("banlist.row.player") + .set("name", ban.getPlayer().getName()) + .set("reason", ban.getReason()) + .resolveComponent()); } } else if (type.startsWith("ipr")) { if (!sender.hasPermission(getPermission() + ".ipranges")) { @@ -44,12 +56,11 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { } for (IpRangeBanData ban : getPlugin().getIpRangeBanStorage().getBans().values()) { - list.append(ban.getFromIp().toString()); - list.append(" - "); - list.append(ban.getToIp().toString()); - list.append(", "); - - total++; + items.add(Message.get("banlist.row.iprange") + .set("from_ip", ban.getFromIp().toString()) + .set("to_ip", ban.getToIp().toString()) + .set("reason", ban.getReason()) + .resolveComponent()); } } else if (type.startsWith("ip")) { if (!sender.hasPermission(getPermission() + ".ips")) { @@ -58,19 +69,18 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { } for (IpBanData ban : getPlugin().getIpBanStorage().getBans().values()) { - list.append(ban.getIp().toString()); - list.append(", "); - - total++; + items.add(Message.get("banlist.row.ip") + .set("ip", ban.getIp().toString()) + .set("reason", ban.getReason()) + .resolveComponent()); } } else { return false; } - if (list.length() >= 2) list.setLength(list.length() - 2); - - Message.get("banlist.header").set("bans", total).set("type", type).sendTo(sender); - if (list.length() > 0) sender.sendMessage(list.toString()); + Component header = Message.get("banlist.header").set("bans", items.size()).set("type", type).resolveComponent(); + PaginatedView view = new PaginatedView(items, "/banlist " + type); + view.send(sender, page, header, null); return true; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/BanNameCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/BanNameCommand.java index 954c2896d..2b03357db 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/BanNameCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/BanNameCommand.java @@ -44,7 +44,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("banname.error.exists"); message.set("name", name); - sender.sendMessage(message.toString()); + message.sendTo(sender); return; } @@ -59,7 +59,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { getPlugin().getNameBanStorage().unban(ban, actor); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute banname command", e); return; } @@ -91,7 +91,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { for (CommonPlayer onlinePlayer : getPlugin().getServer().getOnlinePlayers()) { if (onlinePlayer.getName().equalsIgnoreCase(name)) { - onlinePlayer.kick(kickMessage.toString()); + onlinePlayer.kick(kickMessage); } } }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/BmCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/BmCommand.java new file mode 100644 index 000000000..c4a845129 --- /dev/null +++ b/common/src/main/java/me/confuser/banmanager/common/commands/BmCommand.java @@ -0,0 +1,16 @@ +package me.confuser.banmanager.common.commands; + +import me.confuser.banmanager.common.BanManagerPlugin; + +public class BmCommand extends MultiCommonCommand { + + public BmCommand(BanManagerPlugin plugin) { + super(plugin, "bm"); + registerCommands(); + } + + @Override + public void registerCommands() { + registerCommonSubCommand(new DashboardSubCommand(getPlugin())); + } +} diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/ClearCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/ClearCommand.java index f31ac4e28..e2439d7b8 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/ClearCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/ClearCommand.java @@ -38,7 +38,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final PlayerData player = getPlayer(sender, playerName, true); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return; } @@ -96,7 +96,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { break; } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute clear command", e); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/CommonCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/CommonCommand.java index d75997b83..2ce90c6a7 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/CommonCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/CommonCommand.java @@ -89,7 +89,7 @@ public static PlayerData getPlayer(CommonSender sender, String playerName, boole try { player = BanManagerPlugin.getInstance().getPlayerStorage().queryForId(UUIDUtils.toBytes(UUID.fromString(playerName))); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); BanManagerPlugin.getInstance().getLogger().warning("Failed to execute command", e); } } else { @@ -171,6 +171,8 @@ public CommandParser getParser(List args) throws NoSuchMethodException, return getParser(args.toArray(new String[0])); } + private static final String[] DURATION_PRESETS = {"1h", "6h", "12h", "1d", "3d", "7d", "14d", "30d", "90d", "1y"}; + public List handlePlayerNameTabComplete(CommonSender sender, String[] args) { ArrayList mostLike = new ArrayList<>(); if(args.length == 1) { @@ -199,8 +201,6 @@ public List handlePlayerNameTabComplete(CommonSender sender, String[] ar } } if(args.length > 1) { - // Reasons? - // TODO: Only allow reasons for valid commands. String lookup = args[args.length - 1]; if(lookup.startsWith("#")) { return plugin.getReasonsConfig().getReasons().keySet().stream().map(k -> "#" + k) @@ -213,6 +213,21 @@ public List handlePlayerNameTabComplete(CommonSender sender, String[] ar return mostLike; } + public List handleDurationTabComplete(CommonSender sender, String[] args, int durationArgIndex) { + ArrayList completions = new ArrayList<>(handlePlayerNameTabComplete(sender, args)); + + if (args.length == durationArgIndex + 1) { + String partial = args[durationArgIndex].toLowerCase(); + for (String preset : DURATION_PRESETS) { + if (preset.startsWith(partial)) { + completions.add(preset); + } + } + } + + return completions; + } + public long getCooldown() { return plugin.getConfig().getCooldownsConfig().getCommand(getCommandName()); } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/CommonSender.java b/common/src/main/java/me/confuser/banmanager/common/commands/CommonSender.java index 81f919361..305c0862d 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/CommonSender.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/CommonSender.java @@ -1,13 +1,22 @@ package me.confuser.banmanager.common.commands; import me.confuser.banmanager.common.data.PlayerData; +import me.confuser.banmanager.common.kyori.text.Component; import me.confuser.banmanager.common.util.Message; +import me.confuser.banmanager.common.util.MessageRenderer; public interface CommonSender { String getName(); boolean hasPermission(String permission); void sendMessage(String message); - void sendMessage(Message message); boolean isConsole(); PlayerData getData(); + + default void sendMessage(Message message) { + sendMessage(message.resolveComponent()); + } + + default void sendMessage(Component component) { + sendMessage(MessageRenderer.getInstance().toLegacy(component)); + } } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/DashboardSubCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/DashboardSubCommand.java new file mode 100644 index 000000000..458512877 --- /dev/null +++ b/common/src/main/java/me/confuser/banmanager/common/commands/DashboardSubCommand.java @@ -0,0 +1,61 @@ +package me.confuser.banmanager.common.commands; + +import me.confuser.banmanager.common.BanManagerPlugin; +import me.confuser.banmanager.common.util.Message; +import me.confuser.banmanager.common.util.ReportList; + +import java.sql.SQLException; + +public class DashboardSubCommand extends CommonSubCommand { + + private static final String COUNT_TOKEN = "count"; + + public DashboardSubCommand(BanManagerPlugin plugin) { + super(plugin, "dashboard"); + } + + @Override + public boolean onCommand(CommonSender sender, CommandParser args) { + BanManagerPlugin plugin = getPlugin(); + + int activeBans = plugin.getPlayerBanStorage().getBans().size(); + int activeMutes = plugin.getPlayerMuteStorage().getMutes().size(); + int openReports; + + try { + ReportList reports = plugin.getPlayerReportStorage().getReports(1, 1); + openReports = reports != null ? (int) reports.getCount() : 0; + } catch (SQLException e) { + plugin.getLogger().warning("Failed to fetch report count for dashboard", e); + openReports = 0; + } + + Message.get("dashboard.header").sendTo(sender); + + Message.get("dashboard.activeBans") + .set(COUNT_TOKEN, activeBans) + .sendTo(sender); + + Message.get("dashboard.activeMutes") + .set(COUNT_TOKEN, activeMutes) + .sendTo(sender); + + Message.get("dashboard.openReports") + .set(COUNT_TOKEN, openReports) + .sendTo(sender); + + Message.get("dashboard.footer").sendTo(sender); + + return true; + } + + @Override + public String getHelp() { + return "- View staff dashboard summary"; + } + + @Override + public String getPermission() { + return "command.bm.dashboard"; + } +} diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/DeleteCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/DeleteCommand.java index bb117fce1..7d47ff5d9 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/DeleteCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/DeleteCommand.java @@ -90,7 +90,7 @@ public void run() { break; } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute delete command", e); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/DeleteLastWarningCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/DeleteLastWarningCommand.java index 3116e5b6a..70dad35bb 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/DeleteLastWarningCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/DeleteLastWarningCommand.java @@ -27,7 +27,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final PlayerData player = getPlayer(sender, playerName, true); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/ExportCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/ExportCommand.java index 113d5be29..3cf44b69c 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/ExportCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/ExportCommand.java @@ -49,7 +49,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { exportPlayers(fileName); } catch (IOException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute export command", e); return; } @@ -64,7 +64,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { exportIps(fileName); } catch (IOException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute export command", e); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/FindAltsCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/FindAltsCommand.java index d87fa2e37..e7f5940d3 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/FindAltsCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/FindAltsCommand.java @@ -13,7 +13,7 @@ import me.confuser.banmanager.common.kyori.text.format.TextColor; import me.confuser.banmanager.common.util.IPUtils; import me.confuser.banmanager.common.util.Message; - +import me.confuser.banmanager.common.util.MessageRenderer; import java.sql.SQLException; import java.util.*; @@ -38,7 +38,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("sender.error.invalidIp"); message.set("ip", ipStr); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -46,18 +46,18 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final IPAddress ip = getIp(ipStr); if (ip == null) { - sender.sendMessage(Message.get("alts.header")); - sender.sendMessage(Message.get("none").toString()); + Message.get("alts.header").sendTo(sender); + Message.get("none").sendTo(sender); return; } List players = getPlugin().getPlayerStorage().getDuplicatesInTime(ip, getPlugin().getConfig().getTimeAssociatedAlts()); if (!sender.isConsole()) { - sender.sendMessage(Message.get("alts.header").set("ip", ipStr).toString()); + Message.get("alts.header").set("ip", ipStr).sendTo(sender); if (players.isEmpty()) { - sender.sendMessage(Message.get("none").toString()); + Message.get("none").sendTo(sender); return; } @@ -69,10 +69,10 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { names.add(player.getName()); } - sender.sendMessage(Message.get("alts.header").set("ip", ipStr).toString()); + Message.get("alts.header").set("ip", ipStr).sendTo(sender); if (names.isEmpty()) { - sender.sendMessage(Message.get("none").toString()); + Message.get("none").sendTo(sender); return; } @@ -121,19 +121,28 @@ public static TextComponent alts(List players) { } } + boolean hasEntryTemplate = Message.getRawTemplate("alts.entry") != null; + String separatorRaw = Message.getRawTemplate("alts.separator"); + MessageRenderer renderer = MessageRenderer.getInstance(); + Component separator = separatorRaw != null ? renderer.render(separatorRaw) : Component.text(", "); + int index = 0; for (PlayerData player : players) { TextColor colour = colours.getOrDefault(player.getUUID(), NamedTextColor.GREEN); - message - .append( - Component.text(player.getName()) - .color(colour) - .clickEvent(ClickEvent.runCommand("/bminfo " + player.getName()))); + if (hasEntryTemplate) { + Component entry = Message.get("alts.entry").set("name", player.getName()).resolveComponent(); + message.append(Component.text().color(colour).append(entry)); + } else { + message.append( + Component.text(player.getName()) + .color(colour) + .clickEvent(ClickEvent.runCommand("/bminfo " + player.getName()))); + } if (index != players.size() - 1) { - message.append(Component.text(", ")); + message.append(separator); } index++; diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/InfoCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/InfoCommand.java index 31168c1c8..3e3c2aeb2 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/InfoCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/InfoCommand.java @@ -8,7 +8,7 @@ import me.confuser.banmanager.common.kyori.text.Component; import me.confuser.banmanager.common.kyori.text.TextComponent; import me.confuser.banmanager.common.kyori.text.event.ClickEvent; -import me.confuser.banmanager.common.kyori.text.format.NamedTextColor; + import me.confuser.banmanager.common.maxmind.db.model.CountryResponse; import me.confuser.banmanager.common.ormlite.dao.CloseableIterator; import me.confuser.banmanager.common.ormlite.field.SqlType; @@ -19,6 +19,7 @@ import me.confuser.banmanager.common.util.DateUtils; import me.confuser.banmanager.common.util.IPUtils; import me.confuser.banmanager.common.util.Message; + import me.confuser.banmanager.common.util.StringUtils; import me.confuser.banmanager.common.util.parsers.InfoCommandParser; @@ -98,7 +99,7 @@ public void ipInfo(CommonSender sender, IPAddress ip, InfoCommandParser parser) try { since = DateUtils.parseDateDiff(parser.getTime(), false); } catch (Exception e1) { - sender.sendMessage(Message.get("time.error.invalid").toString()); + Message.get("time.error.invalid").sendTo(sender); return; } } @@ -284,7 +285,7 @@ public void playerInfo(CommonSender sender, String name, Integer index, InfoComm List players = getPlugin().getPlayerStorage().retrieve(name); if (players == null || players.size() == 0) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", name).toString()); + Message.get("sender.error.notFound").set("player", name).sendTo(sender); return; } @@ -324,7 +325,7 @@ public void playerInfo(CommonSender sender, String name, Integer index, InfoComm try { since = DateUtils.parseDateDiff(parser.getTime(), false); } catch (Exception e1) { - sender.sendMessage(Message.get("time.error.invalid").toString()); + Message.get("time.error.invalid").sendTo(sender); return; } } @@ -693,29 +694,6 @@ private void handleIpHistory(ArrayList messages, PlayerData player, long } private TextComponent buildNamesComponent(List names, String dateTimeFormat) { - TextComponent.Builder message = Component.text(); - int index = 0; - - for (PlayerNameSummary nameData : names) { - String hoverText = Message.get("names.row") - .set("name", nameData.getName()) - .set("firstSeen", DateUtils.format(dateTimeFormat, nameData.getFirstSeen())) - .set("lastSeen", DateUtils.format(dateTimeFormat, nameData.getLastSeen())) - .toString(); - - message.append( - Component.text(nameData.getName()) - .color(NamedTextColor.YELLOW) - .clickEvent(ClickEvent.runCommand("/bminfo " + nameData.getName())) - .hoverEvent(Component.text(hoverText))); - - if (index != names.size() - 1) { - message.append(Component.text(", ").color(NamedTextColor.GRAY)); - } - - index++; - } - - return message.build(); + return NamesCommand.buildNamesComponent(names, dateTimeFormat); } } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/KickAllCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/KickAllCommand.java index 7e937db67..eb7e0e446 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/KickAllCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/KickAllCommand.java @@ -64,7 +64,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { return null; }); } catch (Exception e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute kickall command", e); } } @@ -94,14 +94,14 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { .set("playerId", player.getUniqueId().toString()) .set("actor", actor.getName()); - player.kick(kickMessage.toString()); + player.kick(kickMessage); } if (isSilent || !sender.hasPermission("bm.notify.kick")) { message.sendTo(sender); } - if (!isSilent) getPlugin().getServer().broadcast(message.toString(), "bm.notify.kick"); + if (!isSilent) getPlugin().getServer().broadcast(message, "bm.notify.kick"); }); }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/KickCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/KickCommand.java index 0736fdc1a..9a6b563c0 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/KickCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/KickCommand.java @@ -82,13 +82,13 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get(reason.isEmpty() ? "kick.notify.noReason" : "kick.notify.reason"); message.set("player", player.getName()).set("actor", actor.getName()).set("reason", reason); - player.kick(kickMessage.toString()); + player.kick(kickMessage); if (isSilent || !sender.hasPermission("bm.notify.kick")) { message.sendTo(sender); } - if (!isSilent) getPlugin().getServer().broadcast(message.toString(), "bm.notify.kick"); + if (!isSilent) getPlugin().getServer().broadcast(message, "bm.notify.kick"); }); if (getPlugin().getConfig().isKickLoggingEnabled()) { @@ -103,7 +103,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { created = getPlugin().getPlayerKickStorage().addKick(data, isSilent); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute kick command", e); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/LoglessKickAllCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/LoglessKickAllCommand.java index 182fd3660..36d07e644 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/LoglessKickAllCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/LoglessKickAllCommand.java @@ -57,14 +57,14 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { .set("playerId", player.getUniqueId().toString()) .set("actor", actor.getName()); - player.kick(kickMessage.toString()); + player.kick(kickMessage); } if (isSilent || !sender.hasPermission("bm.notify.kick")) { message.sendTo(sender); } - if (!isSilent) getPlugin().getServer().broadcast(message.toString(), "bm.notify.kick"); + if (!isSilent) getPlugin().getServer().broadcast(message, "bm.notify.kick"); }); }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/LoglessKickCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/LoglessKickCommand.java index 699de15e9..666661390 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/LoglessKickCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/LoglessKickCommand.java @@ -79,13 +79,13 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get(reason.isEmpty() ? "kick.notify.noReason" : "kick.notify.reason"); message.set("player", player.getName()).set("actor", actor.getName()).set("reason", reason); - player.kick(kickMessage.toString()); + player.kick(kickMessage); if (isSilent || !sender.hasPermission("bm.notify.kick")) { message.sendTo(sender); } - if (!isSilent) getPlugin().getServer().broadcast(message.toString(), "bm.notify.kick"); + if (!isSilent) getPlugin().getServer().broadcast(message, "bm.notify.kick"); }); }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/MuteCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/MuteCommand.java index 12d07829b..e12a389a8 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/MuteCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/MuteCommand.java @@ -47,12 +47,12 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { TargetResolver.TargetResult target = TargetResolver.resolveTarget(getPlugin().getServer(), playerName); if (target.getStatus() == TargetResolver.TargetStatus.NOT_FOUND) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return true; } if (target.getStatus() == TargetResolver.TargetStatus.AMBIGUOUS) { - sender.sendMessage(Message.get("sender.error.ambiguousPlayer").set("player", playerName).toString()); + Message.get("sender.error.ambiguousPlayer").set("player", playerName).sendTo(sender); return true; } @@ -73,7 +73,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { isMuted = getPlugin().getPlayerMuteStorage().isMuted(UUID.fromString(playerName)); } catch (IllegalArgumentException e) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return true; } } else { @@ -84,7 +84,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("mute.error.exists"); message.set("player", targetName); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -104,12 +104,12 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final PlayerData player = getPlayer(sender, targetName, true); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", targetName).toString()); + Message.get("sender.error.notFound").set("player", targetName).sendTo(sender); return; } if (getPlugin().getExemptionsConfig().isExempt(player, "mute")) { - sender.sendMessage(Message.get("sender.error.exempt").set("player", targetName).toString()); + Message.get("sender.error.exempt").set("player", targetName).sendTo(sender); return; } @@ -119,7 +119,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { return; } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute mute command", e); return; } @@ -139,7 +139,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { getPlugin().getPlayerMuteStorage().unmute(mute, actor); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute mute command", e); return; } @@ -175,7 +175,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { .set("id", mute.getId()) .set("actor", actor.getName()); - commonPlayer.sendMessage(muteMessage.toString()); + muteMessage.sendTo(commonPlayer); }); return true; diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/MuteIpCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/MuteIpCommand.java index f7023189b..d523aab5f 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/MuteIpCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/MuteIpCommand.java @@ -56,7 +56,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("sender.error.invalidIp"); message.set("ip", ipStr); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -76,7 +76,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final IPAddress ip = getIp(ipStr); if (ip == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", ipStr).toString()); + Message.get("sender.error.notFound").set("player", ipStr).sendTo(sender); return; } @@ -86,7 +86,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("muteip.error.exists"); message.set("ip", ipStr); - sender.sendMessage(message.toString()); + message.sendTo(sender); return; } @@ -101,7 +101,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { getPlugin().getIpMuteStorage().unmute(mute, actor); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute muteip command", e); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/NamesCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/NamesCommand.java index ecfacdc42..92c36e977 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/NamesCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/NamesCommand.java @@ -10,6 +10,7 @@ import me.confuser.banmanager.common.kyori.text.format.NamedTextColor; import me.confuser.banmanager.common.util.DateUtils; import me.confuser.banmanager.common.util.Message; +import me.confuser.banmanager.common.util.MessageRenderer; import java.sql.SQLException; import java.util.List; @@ -31,7 +32,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { if (playerName.length() > 16) { Message message = Message.get("sender.error.invalidPlayer"); message.set("player", playerName); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -39,7 +40,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { PlayerData player = getPlugin().getPlayerStorage().retrieve(playerName, true); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return; } @@ -47,29 +48,29 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { names = getPlugin().getPlayerHistoryStorage().getNamesSummary(player); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute names command", e); return; } - sender.sendMessage(Message.get("names.header").set("player", player.getName()).toString()); + Message.get("names.header").set("player", player.getName()).sendTo(sender); if (names.isEmpty()) { - sender.sendMessage(Message.get("names.none").toString()); + Message.get("names.none").sendTo(sender); return; } - String dateTimeFormat = Message.getString("names.dateTimeFormat"); + String dateTimeFormat = Message.getRawTemplate("names.dateTimeFormat"); if (!sender.isConsole()) { ((CommonPlayer) sender).sendJSONMessage(buildNamesComponent(names, dateTimeFormat)); } else { for (PlayerNameSummary nameData : names) { - sender.sendMessage(Message.get("names.row") + Message.get("names.row") .set("name", nameData.getName()) .set("firstSeen", DateUtils.format(dateTimeFormat, nameData.getFirstSeen())) .set("lastSeen", DateUtils.format(dateTimeFormat, nameData.getLastSeen())) - .toString()); + .sendTo(sender); } } }); @@ -77,25 +78,39 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { return true; } - private TextComponent buildNamesComponent(List names, String dateTimeFormat) { + static TextComponent buildNamesComponent(List names, String dateTimeFormat) { TextComponent.Builder message = Component.text(); + boolean hasInteractiveTemplate = Message.getRawTemplate("names.interactive") != null; + String separatorRaw = Message.getRawTemplate("names.separator"); + MessageRenderer renderer = MessageRenderer.getInstance(); + Component separator = separatorRaw != null ? renderer.render(separatorRaw) : Component.text(", ").color(NamedTextColor.GRAY); + int index = 0; for (PlayerNameSummary nameData : names) { - String hoverText = Message.get("names.row") - .set("name", nameData.getName()) - .set("firstSeen", DateUtils.format(dateTimeFormat, nameData.getFirstSeen())) - .set("lastSeen", DateUtils.format(dateTimeFormat, nameData.getLastSeen())) - .toString(); - - message.append( - Component.text(nameData.getName()) - .color(NamedTextColor.YELLOW) - .clickEvent(ClickEvent.runCommand("/bminfo " + nameData.getName())) - .hoverEvent(Component.text(hoverText))); + if (hasInteractiveTemplate) { + Component entry = Message.get("names.interactive") + .set("name", nameData.getName()) + .set("firstSeen", DateUtils.format(dateTimeFormat, nameData.getFirstSeen())) + .set("lastSeen", DateUtils.format(dateTimeFormat, nameData.getLastSeen())) + .resolveComponent(); + message.append(entry); + } else { + String hoverText = Message.get("names.row") + .set("name", nameData.getName()) + .set("firstSeen", DateUtils.format(dateTimeFormat, nameData.getFirstSeen())) + .set("lastSeen", DateUtils.format(dateTimeFormat, nameData.getLastSeen())) + .toString(); + + message.append( + Component.text(nameData.getName()) + .color(NamedTextColor.YELLOW) + .clickEvent(ClickEvent.runCommand("/bminfo " + nameData.getName())) + .hoverEvent(Component.text(hoverText))); + } if (index != names.size() - 1) { - message.append(Component.text(", ").color(NamedTextColor.GRAY)); + message.append(separator); } index++; diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/NotesCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/NotesCommand.java index d981267e2..523d85a82 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/NotesCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/NotesCommand.java @@ -4,6 +4,7 @@ import me.confuser.banmanager.common.CommonPlayer; import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.data.PlayerNoteData; +import me.confuser.banmanager.common.kyori.text.Component; import me.confuser.banmanager.common.kyori.text.TextComponent; import me.confuser.banmanager.common.kyori.text.event.ClickEvent; import me.confuser.banmanager.common.kyori.text.serializer.legacy.LegacyComponentSerializer; @@ -41,7 +42,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { PlayerData player = getPlugin().getPlayerStorage().retrieve(name, false); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", name).toString()); + Message.get("sender.error.notFound").set("player", name).sendTo(sender); return; } @@ -140,9 +141,7 @@ public void run() { return true; } - public static TextComponent notesAmountMessage(String playerName, Message text) { - return LegacyComponentSerializer.legacy('&').deserialize( - text.set("player", playerName).toString()) - .clickEvent(ClickEvent.runCommand("/notes " + playerName)); + public static Component notesAmountMessage(String playerName, Message text) { + return text.set("player", playerName).resolveComponent(); } } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/ReloadCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/ReloadCommand.java index f8ad114cb..278a98dd9 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/ReloadCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/ReloadCommand.java @@ -15,7 +15,7 @@ public boolean onCommand(CommonSender sender, CommandParser parser) { getPlugin().getServer().callEvent("PluginReloadedEvent", sender.getData()); - sender.sendMessage(Message.get("configReloaded").toString()); + Message.get("configReloaded").sendTo(sender); return true; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/ReportCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/ReportCommand.java index faa4eefd4..bc2f63b9d 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/ReportCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/ReportCommand.java @@ -38,12 +38,12 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final TargetResolver.TargetResult target = TargetResolver.resolveTarget(getPlugin().getServer(), playerName); if (target.getStatus() == TargetResolver.TargetStatus.NOT_FOUND) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return true; } if (target.getStatus() == TargetResolver.TargetStatus.AMBIGUOUS) { - sender.sendMessage(Message.get("sender.error.ambiguousPlayer").set("player", playerName).toString()); + Message.get("sender.error.ambiguousPlayer").set("player", playerName).sendTo(sender); return true; } @@ -72,12 +72,12 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final PlayerData player = getPlayer(sender, targetName, false); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", targetName).toString()); + Message.get("sender.error.notFound").set("player", targetName).sendTo(sender); return; } if (getPlugin().getExemptionsConfig().isExempt(player, "report")) { - sender.sendMessage(Message.get("sender.error.exempt").set("player", targetName).toString()); + Message.get("sender.error.exempt").set("player", targetName).sendTo(sender); return; } @@ -87,7 +87,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { return; } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute report command", e); return; } @@ -101,7 +101,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { .queryForId(1)); getPlugin().getPlayerReportStorage().report(report, isSilent); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute report command", e); } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/RollbackCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/RollbackCommand.java index 19e43ddb1..2ee473314 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/RollbackCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/RollbackCommand.java @@ -49,7 +49,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { expiresCheck = DateUtils.parseDateDiff(parser.args[1], false); } catch (Exception e) { - sender.sendMessage(Message.get("time.error.invalid").toString()); + Message.get("time.error.invalid").sendTo(sender); return true; } @@ -67,7 +67,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final PlayerData player = getPlayer(sender, playerName, false); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return; } @@ -266,7 +266,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { .sendTo(sender); } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute rollback command", e); } }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/TempBanCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/TempBanCommand.java index b7e848eab..2cc313d9b 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/TempBanCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/TempBanCommand.java @@ -42,12 +42,12 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final TargetResolver.TargetResult target = TargetResolver.resolveTarget(getPlugin().getServer(), playerName); if (target.getStatus() == TargetResolver.TargetStatus.NOT_FOUND) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return true; } if (target.getStatus() == TargetResolver.TargetStatus.AMBIGUOUS) { - sender.sendMessage(Message.get("sender.error.ambiguousPlayer").set("player", playerName).toString()); + Message.get("sender.error.ambiguousPlayer").set("player", playerName).sendTo(sender); return true; } @@ -66,7 +66,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { isBanned = getPlugin().getPlayerBanStorage().isBanned(UUID.fromString(playerName)); } catch (IllegalArgumentException e) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return true; } } else { @@ -77,7 +77,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("ban.error.exists"); message.set("player", targetName); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -96,7 +96,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { expiresCheck = DateUtils.parseDateDiff(parser.args[1], true); } catch (Exception e1) { - sender.sendMessage(Message.get("time.error.invalid").toString()); + Message.get("time.error.invalid").sendTo(sender); return true; } @@ -115,12 +115,12 @@ public void run() { final PlayerData player = getPlayer(sender, targetName, true); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", targetName).toString()); + Message.get("sender.error.notFound").set("player", targetName).sendTo(sender); return; } if (getPlugin().getExemptionsConfig().isExempt(player, "tempban")) { - sender.sendMessage(Message.get("sender.error.exempt").set("player", targetName).toString()); + Message.get("sender.error.exempt").set("player", targetName).sendTo(sender); return; } @@ -130,7 +130,7 @@ public void run() { return; } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute tempban command", e); return; } @@ -152,7 +152,7 @@ public void run() { try { getPlugin().getPlayerBanStorage().unban(ban, actor); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute tempban command", e); return; } @@ -164,13 +164,15 @@ public void run() { Message kickMessage = null; if (onlinePlayer != null) { + String dateTimeFormat = Message.getString("tempban.player.dateTimeFormat"); kickMessage = Message.get("tempban.player.kick") .set("displayName", onlinePlayer.getDisplayName()) .set("player", player.getName()) .set("playerId", player.getUUID().toString()) .set("reason", ban.getReason()) .set("actor", actor.getName()) - .set("expires", DateUtils.getDifferenceFormat(ban.getExpires())); + .set("expires", DateUtils.getDifferenceFormat(ban.getExpires())) + .set("created", DateUtils.format(dateTimeFormat != null ? dateTimeFormat : "yyyy-MM-dd HH:mm:ss", ban.getCreated())); } try { @@ -190,7 +192,7 @@ public void run() { if (onlinePlayer != null) { final Message finalKickMessage = kickMessage; getPlugin().getScheduler().runSync(() -> { - onlinePlayer.kick(finalKickMessage.toString()); + onlinePlayer.kick(finalKickMessage); }); } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/TempIpBanCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/TempIpBanCommand.java index 9d24ab14a..adab6626a 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/TempIpBanCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/TempIpBanCommand.java @@ -45,7 +45,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("sender.error.invalidIp"); message.set("ip", ipStr); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -64,7 +64,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { expiresCheck = DateUtils.parseDateDiff(parser.args[1], true); } catch (Exception e1) { - sender.sendMessage(Message.get("time.error.invalid").toString()); + Message.get("time.error.invalid").sendTo(sender); return true; } @@ -80,7 +80,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final IPAddress ip = getIp(ipStr); if (ip == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", ipStr).toString()); + Message.get("sender.error.notFound").set("player", ipStr).sendTo(sender); return; } @@ -90,7 +90,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("banip.error.exists"); message.set("ip", ipStr); - sender.sendMessage(message.toString()); + message.sendTo(sender); return; } @@ -100,7 +100,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { return; } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute tempbanip command", e); return; } @@ -116,7 +116,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { getPlugin().getIpBanStorage().unban(ban, actor); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute tempbanip command", e); return; } @@ -148,7 +148,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { for (CommonPlayer onlinePlayer : getPlugin().getServer().getOnlinePlayers()) { if (IPUtils.toIPAddress(onlinePlayer.getAddress()).equals(ip)) { - onlinePlayer.kick(kickMessage.toString()); + onlinePlayer.kick(kickMessage); } } }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/TempIpMuteCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/TempIpMuteCommand.java index f986727c1..6a33ec419 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/TempIpMuteCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/TempIpMuteCommand.java @@ -57,7 +57,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("sender.error.invalidIp"); message.set("ip", ipStr); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -76,7 +76,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { expiresCheck = DateUtils.parseDateDiff(parser.args[1], true); } catch (Exception e1) { - sender.sendMessage(Message.get("time.error.invalid").toString()); + Message.get("time.error.invalid").sendTo(sender); return true; } @@ -92,7 +92,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final IPAddress ip = getIp(ipStr); if (ip == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", ipStr).toString()); + Message.get("sender.error.notFound").set("player", ipStr).sendTo(sender); return; } @@ -102,7 +102,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("muteip.error.exists"); message.set("ip", ipStr); - sender.sendMessage(message.toString()); + message.sendTo(sender); return; } @@ -116,7 +116,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { getPlugin().getIpMuteStorage().unmute(mute, actor); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute tempmuteip command", e); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/TempIpRangeBanCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/TempIpRangeBanCommand.java index 3c069e320..9da0fcd19 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/TempIpRangeBanCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/TempIpRangeBanCommand.java @@ -62,7 +62,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { expiresCheck = DateUtils.parseDateDiff(parser.args[1], true); } catch (Exception e1) { - sender.sendMessage(Message.get("time.error.invalid").toString()); + Message.get("time.error.invalid").sendTo(sender); return true; } @@ -101,7 +101,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { for (CommonPlayer onlinePlayer : getPlugin().getServer().getOnlinePlayers()) { if (ban.inRange(IPUtils.toIPAddress((onlinePlayer.getAddress())))) { - onlinePlayer.kick(kickMessage.toString()); + onlinePlayer.kick(kickMessage); } } }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/TempMuteCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/TempMuteCommand.java index 7b9c90bcb..440ae02b0 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/TempMuteCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/TempMuteCommand.java @@ -57,12 +57,12 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { TargetResolver.TargetResult target = TargetResolver.resolveTarget(getPlugin().getServer(), playerName); if (target.getStatus() == TargetResolver.TargetStatus.NOT_FOUND) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return true; } if (target.getStatus() == TargetResolver.TargetStatus.AMBIGUOUS) { - sender.sendMessage(Message.get("sender.error.ambiguousPlayer").set("player", playerName).toString()); + Message.get("sender.error.ambiguousPlayer").set("player", playerName).sendTo(sender); return true; } @@ -83,7 +83,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { isMuted = getPlugin().getPlayerMuteStorage().isMuted(UUID.fromString(playerName)); } catch (IllegalArgumentException e) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return true; } } else { @@ -94,7 +94,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("mute.error.exists"); message.set("player", targetName); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -114,7 +114,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { expiresCheck = DateUtils.parseDateDiff(parser.args[1], true); } catch (Exception e1) { - sender.sendMessage(Message.get("time.error.invalid").toString()); + Message.get("time.error.invalid").sendTo(sender); return true; } @@ -130,12 +130,12 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final PlayerData player = getPlayer(sender, targetName, true); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", targetName).toString()); + Message.get("sender.error.notFound").set("player", targetName).sendTo(sender); return; } if (getPlugin().getExemptionsConfig().isExempt(player, "tempmute")) { - sender.sendMessage(Message.get("sender.error.exempt").set("player", targetName).toString()); + Message.get("sender.error.exempt").set("player", targetName).sendTo(sender); return; } @@ -145,7 +145,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { return; } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute tempmute command", e); return; } @@ -167,7 +167,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { getPlugin().getPlayerMuteStorage().unmute(mute, actor); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute tempmute command", e); return; } @@ -220,7 +220,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { muteMessage.set("expires", DateUtils.getDifferenceFormat(mute.getExpires())); } - onlinePlayer1.sendMessage(muteMessage.toString()); + muteMessage.sendTo(onlinePlayer1); }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/TempNameBanCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/TempNameBanCommand.java index 888c9cf4e..6e3e1011f 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/TempNameBanCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/TempNameBanCommand.java @@ -42,7 +42,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { expiresCheck = DateUtils.parseDateDiff(parser.args[1], true); } catch (Exception e1) { - sender.sendMessage(Message.get("time.error.invalid").toString()); + Message.get("time.error.invalid").sendTo(sender); return true; } @@ -65,7 +65,7 @@ public void run() { Message message = Message.get("banname.error.exists"); message.set("name", name); - sender.sendMessage(message.toString()); + message.sendTo(sender); return; } @@ -80,7 +80,7 @@ public void run() { try { getPlugin().getNameBanStorage().unban(ban, actor); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute tempnameban command", e); return; } @@ -112,7 +112,7 @@ public void run() { for (CommonPlayer onlinePlayer : getPlugin().getServer().getOnlinePlayers()) { if (onlinePlayer.getName().equalsIgnoreCase(name)) { - onlinePlayer.kick(kickMessage.toString()); + onlinePlayer.kick(kickMessage); } } }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/TempWarnCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/TempWarnCommand.java index ac830c16b..6d3b2cf71 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/TempWarnCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/TempWarnCommand.java @@ -52,12 +52,12 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser TargetResolver.TargetResult target = TargetResolver.resolveTarget(getPlugin().getServer(), playerName); if (target.getStatus() == TargetResolver.TargetStatus.NOT_FOUND) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return true; } if (target.getStatus() == TargetResolver.TargetStatus.AMBIGUOUS) { - sender.sendMessage(Message.get("sender.error.ambiguousPlayer").set("player", playerName).toString()); + Message.get("sender.error.ambiguousPlayer").set("player", playerName).sendTo(sender); return true; } @@ -86,7 +86,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser try { expiresCheck = DateUtils.parseDateDiff(parsedArgs[1], true); } catch (Exception e1) { - sender.sendMessage(Message.get("time.error.invalid").toString()); + Message.get("time.error.invalid").sendTo(sender); return true; } @@ -102,12 +102,12 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser final PlayerData player = getPlayer(sender, targetName, true); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", targetName).toString()); + Message.get("sender.error.notFound").set("player", targetName).sendTo(sender); return; } if (getPlugin().getExemptionsConfig().isExempt(player, "tempwarn")) { - sender.sendMessage(Message.get("sender.error.exempt").set("player", targetName).toString()); + Message.get("sender.error.exempt").set("player", targetName).sendTo(sender); return; } @@ -117,7 +117,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser return; } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute tempwarn command", e); return; } @@ -134,7 +134,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser try { created = getPlugin().getPlayerWarnStorage().addWarning(warning, isSilent); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute tempwarn command", e); return; } @@ -156,7 +156,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser .set("id", warning.getId()) .set("points", parser.getPoints()); - onlinePlayer.sendMessage(warningMessage.toString()); + warningMessage.sendTo(onlinePlayer); } Message message = Message.get("tempwarn.notify") @@ -172,7 +172,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser message.sendTo(sender); } - if (!isSilent) getPlugin().getServer().broadcast(message.toString(), "bm.notify.tempwarn"); + if (!isSilent) getPlugin().getServer().broadcast(message, "bm.notify.tempwarn"); final List actionCommands; diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/UnbanCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/UnbanCommand.java index ce53ca001..ff236504f 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/UnbanCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/UnbanCommand.java @@ -39,7 +39,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser try { isBanned = getPlugin().getPlayerBanStorage().isBanned(UUID.fromString(playerName)); } catch (IllegalArgumentException e) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return true; } } else { @@ -50,7 +50,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser Message message = Message.get("unban.error.noExists"); message.set("player", playerName); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -68,7 +68,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser } if (ban == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return; } @@ -84,7 +84,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser try { unbanned = getPlugin().getPlayerBanStorage().unban(ban, actor, reason, isDelete, parser.isSilent()); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute unban command", e); return; } @@ -106,7 +106,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser } if (!parser.isSilent()) { - getPlugin().getServer().broadcast(message.toString(), "bm.notify.unban"); + getPlugin().getServer().broadcast(message, "bm.notify.unban"); } }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/UnbanIpCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/UnbanIpCommand.java index 8ff8a4def..df804d5a8 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/UnbanIpCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/UnbanIpCommand.java @@ -39,7 +39,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser Message message = Message.get("sender.error.invalidIp"); message.set("ip", ipStr); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -51,8 +51,8 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser if (isName) { PlayerData player = getPlugin().getPlayerStorage().retrieve(ipStr, false); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", ipStr) - .toString()); + Message.get("sender.error.notFound").set("player", ipStr) + .sendTo(sender); return; } @@ -61,7 +61,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser try { ip = new IPAddressString(ipStr).toAddress(); } catch (AddressStringException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute unbanip command", e); return; } @@ -71,7 +71,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser Message message = Message.get("unbanip.error.noExists"); message.set("ip", ipStr); - sender.sendMessage(message.toString()); + message.sendTo(sender); return; } @@ -89,7 +89,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser try { unbanned = getPlugin().getIpBanStorage().unban(ban, actor, reason, isDelete, parser.isSilent()); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute unbanip command", e); return; } @@ -110,7 +110,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser } if (!parser.isSilent()) { - getPlugin().getServer().broadcast(message.toString(), "bm.notify.unbanip"); + getPlugin().getServer().broadcast(message, "bm.notify.unbanip"); } }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/UnbanIpRangeCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/UnbanIpRangeCommand.java index c7afb178e..17e4c6242 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/UnbanIpRangeCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/UnbanIpRangeCommand.java @@ -47,8 +47,8 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { if (isName) { PlayerData player = getPlugin().getPlayerStorage().retrieve(parser.args[0], false); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", parser.args[0]) - .toString()); + Message.get("sender.error.notFound").set("player", parser.args[0]) + .sendTo(sender); return; } @@ -61,7 +61,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("unbanip.error.noExists"); message.set("ip", parser.args[0]); - sender.sendMessage(message.toString()); + message.sendTo(sender); return; } @@ -76,7 +76,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { unbanned = getPlugin().getIpRangeBanStorage().unban(ban, actor, reason, parser.isSilent()); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute unbaniprange command", e); return; } @@ -98,7 +98,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { } if (!parser.isSilent()) { - getPlugin().getServer().broadcast(message.toString(), "bm.notify.unbaniprange"); + getPlugin().getServer().broadcast(message, "bm.notify.unbaniprange"); } }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/UnbanNameCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/UnbanNameCommand.java index af43d9861..c2c41fe1d 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/UnbanNameCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/UnbanNameCommand.java @@ -39,7 +39,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("unbanname.error.noExists"); message.set("name", name); - sender.sendMessage(message.toString()); + message.sendTo(sender); return; } @@ -53,7 +53,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { unbanned = getPlugin().getNameBanStorage().unban(ban, actor, reason, false, parser.isSilent()); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute unbanname command", e); return; } @@ -74,7 +74,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { } if (!parser.isSilent()) { - getPlugin().getServer().broadcast(message.toString(), "bm.notify.unbanname"); + getPlugin().getServer().broadcast(message, "bm.notify.unbanname"); } }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/UnmuteCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/UnmuteCommand.java index 1d46002be..6b458f77d 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/UnmuteCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/UnmuteCommand.java @@ -40,7 +40,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser try { isMuted = getPlugin().getPlayerMuteStorage().isMuted(UUID.fromString(playerName)); } catch (IllegalArgumentException e) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return true; } } else { @@ -51,7 +51,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser Message message = Message.get("unmute.error.noExists"); message.set("player", playerName); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -72,8 +72,7 @@ public void run() { } if (mute == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString - ()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return; } @@ -89,7 +88,7 @@ public void run() { try { unmuted = getPlugin().getPlayerMuteStorage().unmute(mute, actor, reason, isDelete, parser.isSilent()); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute unmute command", e); return; } @@ -111,7 +110,7 @@ public void run() { } if (!parser.isSilent()) { - getPlugin().getServer().broadcast(message.toString(), "bm.notify.unmute"); + getPlugin().getServer().broadcast(message, "bm.notify.unmute"); } getPlugin().getScheduler().runSync(() -> { diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/UnmuteIpCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/UnmuteIpCommand.java index 7bd7162eb..ad9a260c6 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/UnmuteIpCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/UnmuteIpCommand.java @@ -29,7 +29,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("sender.error.invalidIp"); message.set("ip", ipStr); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -50,7 +50,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final IPAddress ip = getIp(ipStr); if (ip == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", ipStr).toString()); + Message.get("sender.error.notFound").set("player", ipStr).sendTo(sender); return; } @@ -58,7 +58,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("unmuteip.error.noExists"); message.set("ip", ipStr); - sender.sendMessage(message.toString()); + message.sendTo(sender); return; } @@ -77,7 +77,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { unmuted = getPlugin().getIpMuteStorage().unmute(mute, actor, reason, parser.isSilent()); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute unmuteip command", e); return; } @@ -98,7 +98,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { } if (!parser.isSilent()) { - getPlugin().getServer().broadcast(message.toString(), "bm.notify.unmuteip"); + getPlugin().getServer().broadcast(message, "bm.notify.unmuteip"); } }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/WarnCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/WarnCommand.java index 30ad696a9..074b336c6 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/WarnCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/WarnCommand.java @@ -51,12 +51,12 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser TargetResolver.TargetResult target = TargetResolver.resolveTarget(getPlugin().getServer(), playerName); if (target.getStatus() == TargetResolver.TargetStatus.NOT_FOUND) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return true; } if (target.getStatus() == TargetResolver.TargetStatus.AMBIGUOUS) { - sender.sendMessage(Message.get("sender.error.ambiguousPlayer").set("player", playerName).toString()); + Message.get("sender.error.ambiguousPlayer").set("player", playerName).sendTo(sender); return true; } @@ -83,12 +83,12 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser final PlayerData player = getPlayer(sender, targetName, true); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", targetName).toString()); + Message.get("sender.error.notFound").set("player", targetName).sendTo(sender); return; } if (getPlugin().getExemptionsConfig().isExempt(player, "warn")) { - sender.sendMessage(Message.get("sender.error.exempt").set("player", targetName).toString()); + Message.get("sender.error.exempt").set("player", targetName).sendTo(sender); return; } @@ -98,7 +98,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser return; } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute warn command", e); return; } @@ -115,7 +115,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser try { created = getPlugin().getPlayerWarnStorage().addWarning(warning, isSilent); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute warn command", e); return; } @@ -136,7 +136,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser .set("id", warning.getId()) .set("points", parser.getPoints()); - onlinePlayer.sendMessage(warningMessage.toString()); + warningMessage.sendTo(onlinePlayer); } Message message = Message.get("warn.notify") @@ -151,7 +151,7 @@ public boolean onCommand(final CommonSender sender, CommandParser originalParser message.sendTo(sender); } - if (!isSilent) getPlugin().getServer().broadcast(message.toString(), "bm.notify.warn"); + if (!isSilent) getPlugin().getServer().broadcast(message, "bm.notify.warn"); final List actionCommands; diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/global/AddNoteAllCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/global/AddNoteAllCommand.java index aaa5c1f6d..0970d3120 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/global/AddNoteAllCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/global/AddNoteAllCommand.java @@ -44,7 +44,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final PlayerData player = getPlayer(sender, playerName, true); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return; } @@ -61,7 +61,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { new GlobalLocalApplyHelper(getPlugin()).applyNote(note, false); } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute addnoteall command", e); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/global/BanAllCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/global/BanAllCommand.java index 369c9ff4e..06b4a5830 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/global/BanAllCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/global/BanAllCommand.java @@ -44,7 +44,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final PlayerData player = getPlayer(sender, playerName, true); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return; } @@ -61,7 +61,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { new GlobalLocalApplyHelper(getPlugin()).applyBan(ban, false); } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute banall command", e); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/global/BanIpAllCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/global/BanIpAllCommand.java index 72c96f060..4877efd96 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/global/BanIpAllCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/global/BanIpAllCommand.java @@ -40,7 +40,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("sender.error.invalidIp"); message.set("ip", ipStr); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -59,7 +59,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { new GlobalLocalApplyHelper(getPlugin()).applyIpBan(ban, false); } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute banipall command", e); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/global/MuteAllCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/global/MuteAllCommand.java index 9f3ce9d7f..bfefe9612 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/global/MuteAllCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/global/MuteAllCommand.java @@ -51,7 +51,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final PlayerData player = getPlayer(sender, playerName, true); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return; } @@ -68,7 +68,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { new GlobalLocalApplyHelper(getPlugin()).applyMute(ban, false); } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute muteall command", e); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/global/TempBanAllCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/global/TempBanAllCommand.java index 2455961e8..6780cb25e 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/global/TempBanAllCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/global/TempBanAllCommand.java @@ -45,7 +45,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { expiresCheck = DateUtils.parseDateDiff(parser.getArgs()[1], true); } catch (Exception e1) { - sender.sendMessage(Message.get("time.error.invalid").toString()); + Message.get("time.error.invalid").sendTo(sender); return true; } @@ -62,7 +62,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final PlayerData player = getPlayer(sender, playerName, true); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return; } @@ -79,7 +79,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { new GlobalLocalApplyHelper(getPlugin()).applyBan(ban, false); } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute tempbanall command", e); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/global/TempBanIpAllCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/global/TempBanIpAllCommand.java index f00ce4102..ae543a812 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/global/TempBanIpAllCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/global/TempBanIpAllCommand.java @@ -42,7 +42,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("sender.error.invalidIp"); message.set("ip", ipStr); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -51,7 +51,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { expiresCheck = DateUtils.parseDateDiff(parser.getArgs()[1], true); } catch (Exception e1) { - sender.sendMessage(Message.get("time.error.invalid").toString()); + Message.get("time.error.invalid").sendTo(sender); return true; } @@ -77,7 +77,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { new GlobalLocalApplyHelper(getPlugin()).applyIpBan(ban, false); } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute tempbanipall command", e); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/global/TempMuteAllCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/global/TempMuteAllCommand.java index aef1d2ddf..aad91289b 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/global/TempMuteAllCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/global/TempMuteAllCommand.java @@ -52,7 +52,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { try { expiresCheck = DateUtils.parseDateDiff(parser.getArgs()[1], true); } catch (Exception e1) { - sender.sendMessage(Message.get("invalidTime").toString()); + Message.get("invalidTime").sendTo(sender); return true; } @@ -69,7 +69,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { final PlayerData player = getPlayer(sender, playerName, true); if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return; } @@ -83,7 +83,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { new GlobalLocalApplyHelper(getPlugin()).applyMute(mute, false); } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute tempmuteall command", e); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/global/UnbanAllCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/global/UnbanAllCommand.java index d6f5128e4..870b32aa5 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/global/UnbanAllCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/global/UnbanAllCommand.java @@ -41,7 +41,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("unban.error.noExists"); message.set("player", playerName); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -55,7 +55,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { } if (ban == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return; } @@ -70,7 +70,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { new GlobalLocalApplyHelper(getPlugin()).applyUnban(record, false); } } catch (SQLException e) { - sender.sendMessage(Message.get("errorOccurred").toString()); + Message.get("errorOccurred").sendTo(sender); getPlugin().getLogger().warning("Failed to execute unbanall command", e); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/global/UnbanIpAllCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/global/UnbanIpAllCommand.java index 29fc7f9ae..6f1bd75c7 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/global/UnbanIpAllCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/global/UnbanIpAllCommand.java @@ -35,7 +35,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("invalidIp"); message.set("ip", ipStr); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -48,7 +48,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("unbanip.error.noExists"); message.set("ip", ipStr); - sender.sendMessage(message.toString()); + message.sendTo(sender); return; } @@ -63,7 +63,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { new GlobalLocalApplyHelper(getPlugin()).applyIpUnban(record, false); } } catch (SQLException e) { - sender.sendMessage(Message.get("errorOccurred").toString()); + Message.get("errorOccurred").sendTo(sender); getPlugin().getLogger().warning("Failed to execute unbanipall command", e); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/global/UnmuteAllCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/global/UnmuteAllCommand.java index 2fb79e043..5cb278363 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/global/UnmuteAllCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/global/UnmuteAllCommand.java @@ -41,7 +41,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { Message message = Message.get("unmute.error.noExists"); message.set("player", playerName); - sender.sendMessage(message.toString()); + message.sendTo(sender); return true; } @@ -55,7 +55,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { } if (mute == null) { - sender.sendMessage(Message.get("sender.error.notFound").set("player", playerName).toString()); + Message.get("sender.error.notFound").set("player", playerName).sendTo(sender); return; } @@ -70,7 +70,7 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { new GlobalLocalApplyHelper(getPlugin()).applyUnmute(record, false); } } catch (SQLException e) { - sender.sendMessage(Message.get("errorOccurred").toString()); + Message.get("errorOccurred").sendTo(sender); getPlugin().getLogger().warning("Failed to execute unmuteall command", e); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/report/AssignSubCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/report/AssignSubCommand.java index c120a7c84..18ec0eb02 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/report/AssignSubCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/report/AssignSubCommand.java @@ -68,7 +68,7 @@ public boolean onCommand(final CommonSender sender, final CommandParser parser) } if (player == null) { - sender.sendMessage(Message.get("sender.error.notFound").toString()); + Message.get("sender.error.notFound").sendTo(sender); return; } @@ -88,22 +88,25 @@ public boolean onCommand(final CommonSender sender, final CommandParser parser) .set("player", player.getName()) .sendTo(sender); - getPlugin().getScheduler().runSync(new Runnable() { - - @Override - public void run() { - CommonPlayer bukkitPlayer = getPlugin().getServer().getPlayer(player.getUUID()); - - if (bukkitPlayer == null || !bukkitPlayer.isOnline()) return; + getPlugin().getScheduler().runSync(() -> { + CommonPlayer assignee = getPlugin().getServer().getPlayer(player.getUUID()); + if (assignee != null && assignee.isOnline()) { Message.get("report.assign.notify") .set("id", data.getId()) - .set("displayName", bukkitPlayer.getDisplayName()) + .set("displayName", assignee.getDisplayName()) .set("player", player.getName()) .set("playerId", player.getUUID().toString()) .set("reason", data.getReason()) - .set("actor", sender.getName()).sendTo(bukkitPlayer); + .set("actor", sender.getName()).sendTo(assignee); + } + CommonPlayer reporter = getPlugin().getServer().getPlayer(data.getActor().getUUID()); + if (reporter != null && reporter.isOnline()) { + Message.get("report.actions.feedback.assigned") + .set("id", data.getId()) + .set("actor", player.getName()) + .sendTo(reporter); } }); }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/report/CloseSubCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/report/CloseSubCommand.java index dc33873a7..8adc5b190 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/report/CloseSubCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/report/CloseSubCommand.java @@ -58,6 +58,8 @@ public boolean onCommand(final CommonSender sender, final CommandParser parser) return; } + notifyReporter(data, sender.getName()); + if (parser.getArgs().length == 1) { String message = Message.get("report.close.notify.closed") .set("actor", sender.getName()) @@ -127,6 +129,19 @@ public boolean onCommand(final CommonSender sender, final CommandParser parser) return true; } + private void notifyReporter(PlayerReportData data, String actorName) { + getPlugin().getScheduler().runSync(() -> { + me.confuser.banmanager.common.CommonPlayer reporter = + getPlugin().getServer().getPlayer(data.getActor().getUUID()); + if (reporter != null && reporter.isOnline()) { + Message.get("report.actions.feedback.closed") + .set("id", data.getId()) + .set("actor", actorName) + .sendTo(reporter); + } + }); + } + @Override public String getHelp() { return " [/command || comment]"; diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/report/InfoSubCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/report/InfoSubCommand.java index 9960d8149..c35bba0f5 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/report/InfoSubCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/report/InfoSubCommand.java @@ -67,14 +67,22 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { return; } - if (location == null) return; + if (location != null) { + Message.get("report.info.notify.location") + .set("world", location.getWorld()) + .set("x", location.getX()) + .set("y", location.getY()) + .set("z", location.getZ()) + .sendTo(sender); + } - Message.get("report.info.notify.location") - .set("world", location.getWorld()) - .set("x", location.getX()) - .set("y", location.getY()) - .set("z", location.getZ()) - .sendTo(sender); + if (!sender.isConsole()) { + Message.get("report.actions.assign").set("id", data.getId()).sendTo(sender); + Message.get("report.actions.close").set("id", data.getId()).sendTo(sender); + if (location != null) { + Message.get("report.actions.tp").set("id", data.getId()).sendTo(sender); + } + } }); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/report/ListSubCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/report/ListSubCommand.java index 47afedfec..91d885a36 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/report/ListSubCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/report/ListSubCommand.java @@ -45,7 +45,7 @@ public boolean onCommand(final CommonSender sender, final CommandParser parser) state = states.get(0).getId(); } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute report list", e); return; } @@ -61,7 +61,7 @@ public boolean onCommand(final CommonSender sender, final CommandParser parser) .getReports(page, state, sender.getData().getUUID()); } } catch (SQLException e) { - sender.sendMessage(Message.get("sender.error.exception").toString()); + Message.get("sender.error.exception").sendTo(sender); getPlugin().getLogger().warning("Failed to execute report list", e); return; } diff --git a/common/src/main/java/me/confuser/banmanager/common/configs/DefaultConfig.java b/common/src/main/java/me/confuser/banmanager/common/configs/DefaultConfig.java index ab5021310..926b6e4e3 100644 --- a/common/src/main/java/me/confuser/banmanager/common/configs/DefaultConfig.java +++ b/common/src/main/java/me/confuser/banmanager/common/configs/DefaultConfig.java @@ -76,6 +76,10 @@ public class DefaultConfig extends Config { @Getter private UUIDFetcher uuidFetcher; @Getter + private String defaultLocale; + @Getter + private boolean perPlayerLocale; + @Getter private String geyserPrefix; public DefaultConfig(File dataFolder, CommonLogger logger) { @@ -140,6 +144,8 @@ public void afterLoad() { uuidFetcher = new UUIDFetcher(idToName, nameToId); geyserPrefix = conf.getString("geyserPrefix", ""); + defaultLocale = conf.getString("locale.default", "en"); + perPlayerLocale = conf.getBoolean("locale.perPlayer", true); } public void handleBlockedCommands(BanManagerPlugin plugin, HashSet set) { diff --git a/common/src/main/java/me/confuser/banmanager/common/configs/MessagesConfig.java b/common/src/main/java/me/confuser/banmanager/common/configs/MessagesConfig.java deleted file mode 100644 index 804f6b5f2..000000000 --- a/common/src/main/java/me/confuser/banmanager/common/configs/MessagesConfig.java +++ /dev/null @@ -1,23 +0,0 @@ -package me.confuser.banmanager.common.configs; - - -import me.confuser.banmanager.common.CommonLogger; -import me.confuser.banmanager.common.util.Message; - -import java.io.File; - -public class MessagesConfig extends Config { - - public MessagesConfig(File dataFolder, CommonLogger logger) { - super(dataFolder, "messages.yml", logger); - } - - public void afterLoad() { - Message.load(this); - } - - public void onSave() { - - } - -} diff --git a/common/src/main/java/me/confuser/banmanager/common/configs/NotificationsConfig.java b/common/src/main/java/me/confuser/banmanager/common/configs/NotificationsConfig.java new file mode 100644 index 000000000..838d3eda2 --- /dev/null +++ b/common/src/main/java/me/confuser/banmanager/common/configs/NotificationsConfig.java @@ -0,0 +1,101 @@ +package me.confuser.banmanager.common.configs; + +import lombok.Getter; +import me.confuser.banmanager.common.CommonLogger; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +public class NotificationsConfig extends Config { + + @Getter + private Map staffChannels = new HashMap<>(); + @Getter + private boolean mutedActionBar = true; + @Getter + private String warnedSound = "entity.villager.no"; + @Getter + private float warnedSoundVolume = 1.0f; + @Getter + private float warnedSoundPitch = 1.0f; + + public NotificationsConfig(File dataFolder, CommonLogger logger) { + super(dataFolder, "notifications.yml", logger); + } + + @Override + public void afterLoad() { + staffChannels.clear(); + + if (conf.getConfigurationSection("staff") != null) { + for (String key : conf.getConfigurationSection("staff").getKeys(false)) { + String path = "staff." + key; + NotificationChannel channel = new NotificationChannel( + conf.getBoolean(path + ".chat", true), + conf.getBoolean(path + ".actionbar", false), + conf.getBoolean(path + ".title", false), + conf.getString(path + ".sound", ""), + (float) conf.getDouble(path + ".soundVolume", 1.0), + (float) conf.getDouble(path + ".soundPitch", 1.0), + conf.getInt(path + ".titleFadeIn", 10), + conf.getInt(path + ".titleStay", 70), + conf.getInt(path + ".titleFadeOut", 20) + ); + staffChannels.put(key, channel); + } + } + + if (conf.getConfigurationSection("player") != null) { + if (conf.getConfigurationSection("player.muted") != null) { + mutedActionBar = conf.getBoolean("player.muted.actionbar", true); + } + if (conf.getConfigurationSection("player.warned") != null) { + warnedSound = conf.getString("player.warned.sound", "entity.villager.no"); + warnedSoundVolume = (float) conf.getDouble("player.warned.soundVolume", 1.0); + warnedSoundPitch = (float) conf.getDouble("player.warned.soundPitch", 1.0); + } + } + } + + @Override + public void onSave() { + } + + public NotificationChannel getStaffChannel(String event) { + return staffChannels.getOrDefault(event, NotificationChannel.CHAT_ONLY); + } + + @Getter + public static class NotificationChannel { + static final NotificationChannel CHAT_ONLY = new NotificationChannel(true, false, false, "", 1.0f, 1.0f, 10, 70, 20); + + private final boolean chat; + private final boolean actionbar; + private final boolean title; + private final String sound; + private final float soundVolume; + private final float soundPitch; + private final int titleFadeIn; + private final int titleStay; + private final int titleFadeOut; + + public NotificationChannel(boolean chat, boolean actionbar, boolean title, + String sound, float soundVolume, float soundPitch, + int titleFadeIn, int titleStay, int titleFadeOut) { + this.chat = chat; + this.actionbar = actionbar; + this.title = title; + this.sound = sound; + this.soundVolume = soundVolume; + this.soundPitch = soundPitch; + this.titleFadeIn = titleFadeIn; + this.titleStay = titleStay; + this.titleFadeOut = titleFadeOut; + } + + public boolean hasSound() { + return sound != null && !sound.isEmpty(); + } + } +} diff --git a/common/src/main/java/me/confuser/banmanager/common/configs/WebhookConfig.java b/common/src/main/java/me/confuser/banmanager/common/configs/WebhookConfig.java index 42baf85b3..b4c2ded74 100644 --- a/common/src/main/java/me/confuser/banmanager/common/configs/WebhookConfig.java +++ b/common/src/main/java/me/confuser/banmanager/common/configs/WebhookConfig.java @@ -191,16 +191,6 @@ public List getHooks(String type) { return hooks != null ? hooks : Collections.emptyList(); } - /** - * @deprecated Use {@link #getHooks(String)} instead for multi-webhook support. - * This method returns the first webhook config for backwards compatibility. - */ - @Deprecated - public WebhookHookConfig getType(String type) { - List hooks = hookTypes.get(type); - return (hooks != null && !hooks.isEmpty()) ? hooks.get(0) : null; - } - @AllArgsConstructor public static class WebhookHookConfig { @Getter diff --git a/common/src/main/java/me/confuser/banmanager/common/data/PlayerData.java b/common/src/main/java/me/confuser/banmanager/common/data/PlayerData.java index 24802a5a1..b3c37f7b9 100644 --- a/common/src/main/java/me/confuser/banmanager/common/data/PlayerData.java +++ b/common/src/main/java/me/confuser/banmanager/common/data/PlayerData.java @@ -32,6 +32,11 @@ public class PlayerData { @DatabaseField(columnDefinition = "BIGINT UNSIGNED NOT NULL") private long lastSeen = System.currentTimeMillis() / 1000L; + @DatabaseField(width = 16, columnDefinition = "VARCHAR(16)") + @Getter + @Setter + private String locale; + private UUID uuid = null; PlayerData() { diff --git a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonBanListener.java b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonBanListener.java index e0e2d758e..c764bfc84 100755 --- a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonBanListener.java +++ b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonBanListener.java @@ -5,6 +5,7 @@ import me.confuser.banmanager.common.data.*; import me.confuser.banmanager.common.util.DateUtils; import me.confuser.banmanager.common.util.Message; +import me.confuser.banmanager.common.util.NotificationUtils; import java.util.List; @@ -17,13 +18,16 @@ public CommonBanListener(BanManagerPlugin plugin) { public void notifyOnBan(PlayerBanData data, boolean silent) { String broadcastPermission; + String event; Message message; if (data.getExpires() == 0) { broadcastPermission = "bm.notify.ban"; + event = "ban"; message = Message.get("ban.notify"); } else { broadcastPermission = "bm.notify.tempban"; + event = "tempban"; message = Message.get("tempban.notify"); message.set("expires", DateUtils.getDifferenceFormat(data.getExpires())); } @@ -36,14 +40,12 @@ public void notifyOnBan(PlayerBanData data, boolean silent) { .set("reason", data.getReason()); if (!silent) { - plugin.getServer().broadcast(message.toString(), broadcastPermission); + NotificationUtils.notifyStaff(plugin, event, message, broadcastPermission); } else if (plugin.getPlayerStorage().getConsole().getUUID().equals(data.getActor().getUUID())) { plugin.getServer().getConsoleSender().sendMessage(message); return; } - // Check if the sender is online and does not have the - // broadcastPermission CommonPlayer player = plugin.getServer().getPlayer(data.getActor().getUUID()); if (player == null || !player.isOnline()) { @@ -57,13 +59,16 @@ public void notifyOnBan(PlayerBanData data, boolean silent) { public void notifyOnBan(IpBanData data, boolean silent) { String broadcastPermission; + String event; Message message; if (data.getExpires() == 0) { broadcastPermission = "bm.notify.banip"; + event = "ban"; message = Message.get("banip.notify"); } else { broadcastPermission = "bm.notify.tempbanip"; + event = "tempban"; message = Message.get("tempbanip.notify"); message.set("expires", DateUtils.getDifferenceFormat(data.getExpires())); } @@ -86,14 +91,12 @@ public void notifyOnBan(IpBanData data, boolean silent) { .set("players", playerNames.toString()); if (!silent) { - plugin.getServer().broadcast(message.toString(), broadcastPermission); + NotificationUtils.notifyStaff(plugin, event, message, broadcastPermission); } else if (plugin.getPlayerStorage().getConsole().getUUID().equals(data.getActor().getUUID())) { plugin.getServer().getConsoleSender().sendMessage(message); return; } - // Check if the sender is online and does not have the - // broadcastPermission CommonPlayer player = plugin.getServer().getPlayer(data.getActor().getUUID()); if (player == null || !player.isOnline()) { @@ -107,13 +110,16 @@ public void notifyOnBan(IpBanData data, boolean silent) { public void notifyOnBan(IpRangeBanData data, boolean silent) { String broadcastPermission; + String event; Message message; if (data.getExpires() == 0) { broadcastPermission = "bm.notify.baniprange"; + event = "ban"; message = Message.get("baniprange.notify"); } else { broadcastPermission = "bm.notify.tempbaniprange"; + event = "tempban"; message = Message.get("tempbaniprange.notify"); message.set("expires", DateUtils.getDifferenceFormat(data.getExpires())); } @@ -126,14 +132,12 @@ public void notifyOnBan(IpRangeBanData data, boolean silent) { .set("reason", data.getReason()); if (!silent) { - plugin.getServer().broadcast(message.toString(), broadcastPermission); + NotificationUtils.notifyStaff(plugin, event, message, broadcastPermission); } else if (plugin.getPlayerStorage().getConsole().getUUID().equals(data.getActor().getUUID())) { plugin.getServer().getConsoleSender().sendMessage(message); return; } - // Check if the sender is online and does not have the - // broadcastPermission CommonPlayer player = plugin.getServer().getPlayer(data.getActor().getUUID()); if (player == null || !player.isOnline()) { @@ -147,13 +151,16 @@ public void notifyOnBan(IpRangeBanData data, boolean silent) { public void notifyOnBan(NameBanData data, boolean silent) { String broadcastPermission; + String event; Message message; if (data.getExpires() == 0) { broadcastPermission = "bm.notify.banname"; + event = "ban"; message = Message.get("banname.notify"); } else { broadcastPermission = "bm.notify.tempbanname"; + event = "tempban"; message = Message.get("tempbanname.notify"); message.set("expires", DateUtils.getDifferenceFormat(data.getExpires())); } @@ -165,14 +172,12 @@ public void notifyOnBan(NameBanData data, boolean silent) { .set("reason", data.getReason()); if (!silent) { - plugin.getServer().broadcast(message.toString(), broadcastPermission); + NotificationUtils.notifyStaff(plugin, event, message, broadcastPermission); } else if (plugin.getPlayerStorage().getConsole().getUUID().equals(data.getActor().getUUID())) { plugin.getServer().getConsoleSender().sendMessage(message); return; } - // Check if the sender is online and does not have the - // broadcastPermission CommonPlayer player = plugin.getServer().getPlayer(data.getActor().getUUID()); if (player == null || !player.isOnline()) { diff --git a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonChatListener.java b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonChatListener.java index 289f72965..b7c71da50 100755 --- a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonChatListener.java +++ b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonChatListener.java @@ -7,6 +7,7 @@ import me.confuser.banmanager.common.data.PlayerWarnData; import me.confuser.banmanager.common.util.DateUtils; import me.confuser.banmanager.common.util.Message; +import me.confuser.banmanager.common.util.NotificationUtils; import java.net.InetAddress; import java.sql.SQLException; @@ -32,6 +33,8 @@ public boolean onPlayerChat(CommonPlayer player, CommonChatHandler handler, Stri } else { Message.get("warn.player.disallowed.header").sendTo(player); Message.get("warn.player.disallowed.reason").set("reason", warning.getReason()).sendTo(player); + + NotificationUtils.playWarnedSound(plugin, player); } return true; @@ -63,7 +66,7 @@ public boolean onPlayerChat(CommonPlayer player, CommonChatHandler handler, Stri .set("id", mute.getId()) .set("actor", mute.getActor().getName()); - plugin.getServer().broadcast(broadcast.toString(), "bm.notify.muted"); + plugin.getServer().broadcast(broadcast, "bm.notify.muted"); if (mute.isSoft()) { handler.handleSoftMute(); @@ -88,6 +91,10 @@ public boolean onPlayerChat(CommonPlayer player, CommonChatHandler handler, Stri player.sendMessage(message); + if (plugin.getNotificationsConfig().isMutedActionBar()) { + player.sendActionBar(message.resolveComponentFor(player)); + } + return true; } @@ -121,7 +128,7 @@ public boolean onIpChat(CommonPlayer player, InetAddress address, CommonChatHand .set("id", mute.getId()) .set("actor", mute.getActor().getName()); - plugin.getServer().broadcast(broadcast.toString(), "bm.notify.mutedip"); + plugin.getServer().broadcast(broadcast, "bm.notify.mutedip"); if (mute.isSoft()) { handler.handleSoftMute(); @@ -145,7 +152,7 @@ public boolean onIpChat(CommonPlayer player, InetAddress address, CommonChatHand .set("id", mute.getId()) .set("ip", mute.getIp().toString()); - player.sendMessage(message.toString()); + message.sendTo(player); return true; } diff --git a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonCommandListener.java b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonCommandListener.java index 6a149aae2..1e0394d8c 100755 --- a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonCommandListener.java +++ b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonCommandListener.java @@ -45,7 +45,7 @@ public boolean onCommand(CommonPlayer player, String cmd, String[] args) { if (!shouldCancel) return false; } - if (!isSoft) player.sendMessage(Message.get("mute.player.blocked").set("command", cmd).toString()); + if (!isSoft) Message.get("mute.player.blocked").set("command", cmd).sendTo(player); return true; } diff --git a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonJoinListener.java b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonJoinListener.java index 21ce94a2c..376130c05 100755 --- a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonJoinListener.java +++ b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonJoinListener.java @@ -216,24 +216,25 @@ public void banCheck(UUID id, String name, IPAddress address, CommonJoinHandler return; } + String locale = data.getPlayer().getLocale(); String dateTimeFormat; Message message; if (data.getExpires() == 0) { message = Message.get("ban.player.disallowed"); - dateTimeFormat = Message.getString("ban.player.dateTimeFormat"); + dateTimeFormat = Message.getString("ban.player.dateTimeFormat", locale); } else { message = Message.get("tempban.player.disallowed"); - message.set("expires", DateUtils.getDifferenceFormat(data.getExpires())); + message.set("expires", DateUtils.getDifferenceFormat(data.getExpires(), locale)); - dateTimeFormat = Message.getString("tempban.player.dateTimeFormat"); + dateTimeFormat = Message.getString("tempban.player.dateTimeFormat", locale); } message.set("id", data.getId()); message.set("player", data.getPlayer().getName()); message.set("reason", data.getReason()); message.set("actor", data.getActor().getName()); - message.set("created", DateUtils.format(dateTimeFormat, data.getCreated())); + message.set("created", DateUtils.format(dateTimeFormat != null ? dateTimeFormat : "dd-MM-yyyy kk:mm:ss", data.getCreated())); handler.handlePlayerDeny(data.getPlayer(), message); handleJoinDeny(data.getPlayer(), data.getActor(), data.getReason()); @@ -265,6 +266,21 @@ public void onJoin(final CommonPlayer player) { UUID id = player.getUniqueId(); + if (plugin.getConfig().isPerPlayerLocale()) { + try { + PlayerData playerData = plugin.getPlayerStorage().queryForId(UUIDUtils.toBytes(id)); + if (playerData != null) { + String locale = player.getLocale(); + if (locale != null && !locale.equals(playerData.getLocale())) { + playerData.setLocale(locale); + plugin.getPlayerStorage().update(playerData); + } + } + } catch (SQLException e) { + plugin.getLogger().warning("Failed to update player locale", e); + } + } + PlayerMuteData mute = plugin.getPlayerMuteStorage().getMute(id); if (mute != null && mute.isOnlineOnly() && mute.isPaused()) { try { @@ -278,7 +294,7 @@ public void onJoin(final CommonPlayer player) { try { notesItr = plugin.getPlayerNoteStorage().getNotes(id); - ArrayList notes = new ArrayList<>(); + ArrayList notes = new ArrayList<>(); String dateTimeFormat = Message.getString("notes.dateTimeFormat"); while (notesItr != null && notesItr.hasNext()) { @@ -290,7 +306,7 @@ public void onJoin(final CommonPlayer player) { .set("id", note.getId()) .set("created", DateUtils.format(dateTimeFormat, note.getCreated())); - notes.add(noteMessage.toString()); + notes.add(noteMessage); } if (notes.size() != 0) { @@ -298,15 +314,14 @@ public void onJoin(final CommonPlayer player) { .set("amount", notes.size()) .set("player", player.getName()); - plugin.getServer().broadcastJSON(NotesCommand.notesAmountMessage(player.getName(), noteJoinMessage), "bm.notify.notes.joinAmount"); + plugin.getServer().broadcast(NotesCommand.notesAmountMessage(player.getName(), noteJoinMessage), "bm.notify.notes.joinAmount"); - String header = Message.get("notes.header") - .set("player", player.getName()) - .toString(); + Message header = Message.get("notes.header") + .set("player", player.getName()); plugin.getServer().broadcast(header, "bm.notify.notes.join"); - for (String message : notes) { + for (Message message : notes) { plugin.getServer().broadcast(message, "bm.notify.notes.join"); } @@ -464,7 +479,7 @@ public void onPlayerLogin(final CommonPlayer player, CommonJoinHandler handler) message.set("player", player.getName()); message.set("players", sb.toString()); - plugin.getServer().broadcast(message.toString(), "bm.notify.duplicateips"); + plugin.getServer().broadcast(message, "bm.notify.duplicateips"); }, Duration.ofSeconds(1)); plugin.getScheduler().runAsyncLater(() -> { @@ -498,7 +513,7 @@ public void onPlayerLogin(final CommonPlayer player, CommonJoinHandler handler) message.set("player", player.getName()); message.set("players", sb.toString()); - plugin.getServer().broadcast(message.toString(), "bm.notify.alts"); + plugin.getServer().broadcast(message, "bm.notify.alts"); }, Duration.ofSeconds(1)); } @@ -512,7 +527,7 @@ private void handleJoinDeny(PlayerData player, PlayerData actor, String reason) .set("reason", reason) .set("actor", actor.getName()); - plugin.getServer().broadcast(message.toString(), "bm.notify.denied.player"); + plugin.getServer().broadcast(message, "bm.notify.denied.player"); } private void handleJoinDeny(String ip, PlayerData actor, String reason) { @@ -524,7 +539,7 @@ private void handleJoinDeny(String ip, PlayerData actor, String reason) { .set("reason", reason) .set("actor", actor.getName()); - plugin.getServer().broadcast(message.toString(), "bm.notify.denied.ip"); + plugin.getServer().broadcast(message, "bm.notify.denied.ip"); } private void denyAlts(List duplicates, final UUID uuid) { @@ -552,7 +567,7 @@ private void denyAlts(List duplicates, final UUID uuid) { .set("id", ban.getId()) .set("actor", ban.getActor().getName()); - bukkitPlayer.kick(kickMessage.toString()); + bukkitPlayer.kick(kickMessage); }); } } @@ -586,14 +601,16 @@ private void punishAlts(List duplicates, UUID uuid) throws SQLExcept plugin.getScheduler().runSync(() -> { CommonPlayer bukkitPlayer = plugin.getServer().getPlayer(newBan.getPlayer().getUUID()); + String kickDateTimeFormat = Message.getString("ban.player.dateTimeFormat"); Message kickMessage = Message.get("ban.player.kick") .set("displayName", bukkitPlayer.getDisplayName()) .set("player", newBan.getPlayer().getName()) .set("reason", newBan.getReason()) .set("id", newBan.getId()) - .set("actor", newBan.getActor().getName()); + .set("actor", newBan.getActor().getName()) + .set("created", DateUtils.format(kickDateTimeFormat != null ? kickDateTimeFormat : "yyyy-MM-dd HH:mm:ss", newBan.getCreated())); - bukkitPlayer.kick(kickMessage.toString()); + bukkitPlayer.kick(kickMessage); }); } } else if (!plugin.getPlayerMuteStorage().isMuted(uuid)) { diff --git a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonMuteListener.java b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonMuteListener.java index a26e9a137..59596a10f 100755 --- a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonMuteListener.java +++ b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonMuteListener.java @@ -7,6 +7,7 @@ import me.confuser.banmanager.common.data.PlayerMuteData; import me.confuser.banmanager.common.util.DateUtils; import me.confuser.banmanager.common.util.Message; +import me.confuser.banmanager.common.util.NotificationUtils; import java.util.List; @@ -19,13 +20,16 @@ public CommonMuteListener(BanManagerPlugin plugin) { public void notifyOnMute(PlayerMuteData data, boolean silent) { String broadcastPermission; + String event; Message message; if (data.getExpires() == 0 && !data.isOnlineOnly()) { broadcastPermission = "bm.notify.mute"; + event = "mute"; message = Message.get("mute.notify"); } else if (data.isOnlineOnly()) { broadcastPermission = "bm.notify.tempmute"; + event = "tempmute"; message = Message.get("tempmute.notifyOnline"); if (data.isPaused()) { message.set("expires", DateUtils.formatDifference(data.getPausedRemaining())); @@ -34,6 +38,7 @@ public void notifyOnMute(PlayerMuteData data, boolean silent) { } } else { broadcastPermission = "bm.notify.tempmute"; + event = "tempmute"; message = Message.get("tempmute.notify"); message.set("expires", DateUtils.getDifferenceFormat(data.getExpires())); } @@ -46,14 +51,12 @@ public void notifyOnMute(PlayerMuteData data, boolean silent) { .set("reason", data.getReason()); if (!silent) { - plugin.getServer().broadcast(message.toString(), broadcastPermission); + NotificationUtils.notifyStaff(plugin, event, message, broadcastPermission); } else if (plugin.getPlayerStorage().getConsole().getUUID().equals(data.getActor().getUUID())) { plugin.getServer().getConsoleSender().sendMessage(message); return; } - // Check if the sender is online and does not have the - // broadcastPermission CommonPlayer player = plugin.getServer().getPlayer(data.getActor().getUUID()); if (player == null || !player.isOnline()) { @@ -67,13 +70,16 @@ public void notifyOnMute(PlayerMuteData data, boolean silent) { public void notifyOnMute(IpMuteData data, boolean silent) { String broadcastPermission; + String event; Message message; if (data.getExpires() == 0) { broadcastPermission = "bm.notify.muteip"; + event = "mute"; message = Message.get("muteip.notify"); } else { broadcastPermission = "bm.notify.tempmuteip"; + event = "tempmute"; message = Message.get("tempmuteip.notify"); message.set("expires", DateUtils.getDifferenceFormat(data.getExpires())); } @@ -97,14 +103,12 @@ public void notifyOnMute(IpMuteData data, boolean silent) { .set("players", playerNames.toString()); if (!silent) { - plugin.getServer().broadcast(message.toString(), broadcastPermission); + NotificationUtils.notifyStaff(plugin, event, message, broadcastPermission); } else if (plugin.getPlayerStorage().getConsole().getUUID().equals(data.getActor().getUUID())) { plugin.getServer().getConsoleSender().sendMessage(message); return; } - // Check if the sender is online and does not have the - // broadcastPermission CommonPlayer player = plugin.getServer().getPlayer(data.getActor().getUUID()); if (player == null || !player.isOnline()) { diff --git a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonNoteListener.java b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonNoteListener.java index 43743a4eb..2771b6c8a 100755 --- a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonNoteListener.java +++ b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonNoteListener.java @@ -27,7 +27,7 @@ public void notifyOnNote(PlayerNoteData data, boolean silent) { .set("message", data.getMessage()); if (!silent) { - plugin.getServer().broadcast(message.toString(), broadcastPermission); + plugin.getServer().broadcast(message, broadcastPermission); } else if (plugin.getPlayerStorage().getConsole().getUUID().equals(data.getActor().getUUID())) { plugin.getServer().getConsoleSender().sendMessage(message); return; diff --git a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonReportListener.java b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonReportListener.java index f63a601fc..11c3db18f 100755 --- a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonReportListener.java +++ b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonReportListener.java @@ -24,7 +24,7 @@ public void notifyOnReport(PlayerReportData data) { .set("reason", data.getReason()) .set("id", data.getId()); - plugin.getServer().broadcast(message.toString(), "bm.notify.report"); + plugin.getServer().broadcast(message, "bm.notify.report"); // Check if the sender is online and does not have the // broadcastPermission diff --git a/common/src/main/java/me/confuser/banmanager/common/runnables/BanSync.java b/common/src/main/java/me/confuser/banmanager/common/runnables/BanSync.java index eef8825e7..54ec7d60a 100644 --- a/common/src/main/java/me/confuser/banmanager/common/runnables/BanSync.java +++ b/common/src/main/java/me/confuser/banmanager/common/runnables/BanSync.java @@ -52,21 +52,25 @@ private void newBans() { if (bukkitPlayer == null || !bukkitPlayer.isOnline()) return; Message kickMessage; + String dateTimeFormat; if (ban.getExpires() == 0) { kickMessage = Message.get("ban.player.kick"); + dateTimeFormat = Message.getString("ban.player.dateTimeFormat"); } else { kickMessage = Message.get("tempban.player.kick"); kickMessage.set("expires", DateUtils.getDifferenceFormat(ban.getExpires())); + dateTimeFormat = Message.getString("tempban.player.dateTimeFormat"); } kickMessage .set("displayName", bukkitPlayer.getDisplayName()) .set("player", ban.getPlayer().getName()) .set("reason", ban.getReason()) - .set("actor", ban.getActor().getName()); + .set("actor", ban.getActor().getName()) + .set("created", DateUtils.format(dateTimeFormat != null ? dateTimeFormat : "yyyy-MM-dd HH:mm:ss", ban.getCreated())); - bukkitPlayer.kick(kickMessage.toString()); + bukkitPlayer.kick(kickMessage); }); } diff --git a/common/src/main/java/me/confuser/banmanager/common/runnables/GlobalBanSync.java b/common/src/main/java/me/confuser/banmanager/common/runnables/GlobalBanSync.java index 1f0735934..7ada6be76 100644 --- a/common/src/main/java/me/confuser/banmanager/common/runnables/GlobalBanSync.java +++ b/common/src/main/java/me/confuser/banmanager/common/runnables/GlobalBanSync.java @@ -77,21 +77,25 @@ private void kickPlayer(PlayerBanData globalBan) { if (bukkitPlayer == null || !bukkitPlayer.isOnline()) return; Message kickMessage; + String dateTimeFormat; if (globalBan.getExpires() == 0) { kickMessage = Message.get("ban.player.kick"); + dateTimeFormat = Message.getString("ban.player.dateTimeFormat"); } else { kickMessage = Message.get("tempban.player.kick"); kickMessage.set("expires", DateUtils.getDifferenceFormat(globalBan.getExpires())); + dateTimeFormat = Message.getString("tempban.player.dateTimeFormat"); } kickMessage .set("displayName", bukkitPlayer.getDisplayName()) .set("player", globalBan.getPlayer().getName()) .set("reason", globalBan.getReason()) - .set("actor", globalBan.getActor().getName()); + .set("actor", globalBan.getActor().getName()) + .set("created", DateUtils.format(dateTimeFormat != null ? dateTimeFormat : "yyyy-MM-dd HH:mm:ss", globalBan.getCreated())); - bukkitPlayer.kick(kickMessage.toString()); + bukkitPlayer.kick(kickMessage); }); } diff --git a/common/src/main/java/me/confuser/banmanager/common/runnables/GlobalIpSync.java b/common/src/main/java/me/confuser/banmanager/common/runnables/GlobalIpSync.java index 66d95681c..e79fd73a2 100644 --- a/common/src/main/java/me/confuser/banmanager/common/runnables/GlobalIpSync.java +++ b/common/src/main/java/me/confuser/banmanager/common/runnables/GlobalIpSync.java @@ -77,7 +77,7 @@ private void kickPlayers(IpBanData globalBan) { for (CommonPlayer onlinePlayer : plugin.getServer().getOnlinePlayers()) { if (IPUtils.toIPAddress(onlinePlayer.getAddress()).equals(globalBan.getIp())) { - onlinePlayer.kick(kickMessage.toString()); + onlinePlayer.kick(kickMessage); } } }); diff --git a/common/src/main/java/me/confuser/banmanager/common/runnables/NameSync.java b/common/src/main/java/me/confuser/banmanager/common/runnables/NameSync.java index 2da425b74..401a6be70 100644 --- a/common/src/main/java/me/confuser/banmanager/common/runnables/NameSync.java +++ b/common/src/main/java/me/confuser/banmanager/common/runnables/NameSync.java @@ -48,21 +48,25 @@ private void newBans() { if (bukkitPlayer == null || !bukkitPlayer.isOnline()) return; Message kickMessage; + String dateTimeFormat; if (ban.getExpires() == 0) { kickMessage = Message.get("ban.player.kick"); + dateTimeFormat = Message.getString("ban.player.dateTimeFormat"); } else { kickMessage = Message.get("tempban.player.kick"); kickMessage.set("expires", DateUtils.getDifferenceFormat(ban.getExpires())); + dateTimeFormat = Message.getString("tempban.player.dateTimeFormat"); } kickMessage .set("displayName", bukkitPlayer.getDisplayName()) .set("player", ban.getName()) .set("reason", ban.getReason()) - .set("actor", ban.getActor().getName()); + .set("actor", ban.getActor().getName()) + .set("created", DateUtils.format(dateTimeFormat != null ? dateTimeFormat : "yyyy-MM-dd HH:mm:ss", ban.getCreated())); - bukkitPlayer.kick(kickMessage.toString()); + bukkitPlayer.kick(kickMessage); }); } diff --git a/common/src/main/java/me/confuser/banmanager/common/util/ColorUtils.java b/common/src/main/java/me/confuser/banmanager/common/util/ColorUtils.java index d6fba1559..185e7aa3a 100644 --- a/common/src/main/java/me/confuser/banmanager/common/util/ColorUtils.java +++ b/common/src/main/java/me/confuser/banmanager/common/util/ColorUtils.java @@ -28,7 +28,7 @@ public class ColorUtils { // Outputs JSON with NO hex colors - safe for pre-1.16 clients private static final GsonComponentSerializer DOWNSAMPLING_JSON = - GsonComponentSerializer.colorDownsamplingGson(); + GsonComponentSerializer.builder().downsampleColors().build(); /** * Convert Spigot-style &x&r&r&g&g&b&b to &#rrggbb format @@ -97,6 +97,6 @@ public static String toDownsampledJson(String message) { */ public static String toJson(String message) { Component component = parse(message); - return GsonComponentSerializer.gson().serialize(component); + return GsonComponentSerializer.builder().build().serialize(component); } } diff --git a/common/src/main/java/me/confuser/banmanager/common/util/DateUtils.java b/common/src/main/java/me/confuser/banmanager/common/util/DateUtils.java index f43c50608..7a3e32911 100644 --- a/common/src/main/java/me/confuser/banmanager/common/util/DateUtils.java +++ b/common/src/main/java/me/confuser/banmanager/common/util/DateUtils.java @@ -29,8 +29,12 @@ public class DateUtils { .compile("(?:([0-9]+)\\s*y[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*mo[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*w[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*d[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*h[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*m[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*(?:s[a-z]*)?)?", Pattern.CASE_INSENSITIVE); public static String formatDifference(long time) { + return formatDifference(time, null); + } + + public static String formatDifference(long time, String locale) { if (time == 0) { - return Message.getString("never"); + return locale != null ? Message.getString("never", locale) : Message.getString("never"); } StringBuilder diff = new StringBuilder(); @@ -69,24 +73,32 @@ public static String formatDifference(long time) { String key = timesString.get(i); if (duration > 1) key += "s"; - diff.append(Message.get("time." + key)); + if (locale != null) { + diff.append(Message.get("time." + key).resolve(locale)); + } else { + diff.append(Message.get("time." + key)); + } } - // Hack to avoid async error if ((field == Calendar.SECOND) && (duration == 59)) { - return formatDifference(time + 1); + return formatDifference(time + 1, locale); } } - return diff.length() == 0 ? Message.getString("time.now") : diff.toString(); + String nowStr = locale != null ? Message.getString("time.now", locale) : Message.getString("time.now"); + return diff.length() == 0 ? nowStr : diff.toString(); } public static String getDifferenceFormat(long timestamp) { return formatDifference(timestamp - (System.currentTimeMillis() / 1000L)); } + public static String getDifferenceFormat(long timestamp, String locale) { + return formatDifference(timestamp - (System.currentTimeMillis() / 1000L), locale); + } + // Copyright essentials, all credits to them for this. public static long parseDateDiff(String time, boolean future) throws Exception { // Support raw timestamps diff --git a/common/src/main/java/me/confuser/banmanager/common/util/Message.java b/common/src/main/java/me/confuser/banmanager/common/util/Message.java index 88b26b0cf..3c78bdf30 100644 --- a/common/src/main/java/me/confuser/banmanager/common/util/Message.java +++ b/common/src/main/java/me/confuser/banmanager/common/util/Message.java @@ -1,115 +1,213 @@ package me.confuser.banmanager.common.util; -import lombok.EqualsAndHashCode; import lombok.Getter; import me.confuser.banmanager.common.BanManagerPlugin; import me.confuser.banmanager.common.CommonLogger; import me.confuser.banmanager.common.CommonPlayer; import me.confuser.banmanager.common.PlaceholderResolver; import me.confuser.banmanager.common.commands.CommonSender; -import me.confuser.banmanager.common.configs.Config; -import me.confuser.banmanager.common.configuration.file.YamlConfiguration; +import me.confuser.banmanager.common.kyori.text.Component; -import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; -@EqualsAndHashCode public class Message { - private static HashMap messages = new HashMap<>(10); - private static CommonLogger logger; + private static volatile MessageRegistry registry; + private static volatile CommonLogger logger; + // Matches PlaceholderAPI %placeholder% tokens. May also match non-PAPI patterns like %100%, + // but the resolver's no-op return for unrecognised placeholders makes this harmless. + private static final Pattern PAPI_PATTERN = Pattern.compile("%([^%]+)%"); + + private static final String REPLACE_PREFIX = "__replace__"; @Getter private String key; - private String message; + private final LinkedHashMap replacements = new LinkedHashMap<>(); public Message(String key) { this.key = key; - this.message = messages.get(key); - if (this.message == null) { + if (registry != null && registry.getMessage(key) == null && logger != null) { logger.warning("Missing " + key + " message"); - this.message = ""; } } public Message(String key, String message) { - if (messages.containsKey(key)) { - logger.warning(key + " message already exists"); - return; - } - this.key = key; - this.message = message; - messages.put(key, message); + if (registry != null) { + if (registry.getMessage(key) != null) { + if (logger != null) logger.warning(key + " message already exists"); + return; + } + registry.putMessage(key, message); + } + } + + public static void init(MessageRegistry messageRegistry, CommonLogger commonLogger) { + registry = messageRegistry; + logger = commonLogger; } public static Message get(String key) { return new Message(key); } - public static String getString(String key) { - return messages.get(key); + /** + * Resolve a message template to a Component using the default locale. + * Convenience for static messages with no dynamic tokens. + */ + public static Component component(String key) { + return get(key).resolveComponent(); } - public static void load(YamlConfiguration config, CommonLogger commonLogger) { - logger = commonLogger; + /** + * Resolve a message template to a Component using the specified locale. + */ + public static Component component(String key, String locale) { + return get(key).resolveComponent(locale); + } - if (config.getConfigurationSection("messages") == null) { - commonLogger.warning("Messages section not found in messages.yml, keeping previous messages"); - return; - } + public static String getString(String key) { + if (registry == null) return null; + String template = registry.getMessage(key); + if (template == null) return null; + MessageRenderer renderer = MessageRenderer.getInstance(); + return renderer.toLegacy(renderer.render(template)); + } - HashMap newMessages = new HashMap<>(10); - for (String key : config.getConfigurationSection("messages").getKeys(true)) { - String value = config.getString("messages." + key); - if (value != null) { - newMessages.put(key, value.replace("\\n", "\n").replaceAll("(?<=\\n)(?=\\n)", " ")); - } - } + public static String getString(String key, String locale) { + if (registry == null) return null; + String template = registry.getMessage(key, locale); + if (template == null) return null; + MessageRenderer renderer = MessageRenderer.getInstance(); + return renderer.toLegacy(renderer.render(template)); + } - if (!newMessages.isEmpty()) { - messages.clear(); - messages.putAll(newMessages); - } else { - commonLogger.warning("No messages loaded from messages.yml, keeping previous messages"); - } + /** + * Get the raw, unrendered template string for a message key. + * Use this when you need to check for key existence or render + * the template separately with dynamic context. + */ + public static String getRawTemplate(String key) { + if (registry == null) return null; + return registry.getMessage(key); } - public static void load(Config config) { - load(config.conf, config.getLogger()); + /** + * Get the raw, unrendered template string for this message's key. + */ + public String getRawTemplate() { + return getRawTemplate(this.key); } public Message replace(CharSequence oldChar, CharSequence newChar) { - message = this.message.replace(oldChar, newChar); - + replacements.put(REPLACE_PREFIX + replacements.size(), new String[]{oldChar.toString(), newChar.toString()}); return this; } public Message set(String token, String replace) { - return replace("[" + token + "]", replace); + replacements.put(token, new String[]{token, replace}); + return this; } public Message set(String token, Integer replace) { - return replace("[" + token + "]", replace.toString()); + return set(token, replace.toString()); } public Message set(String token, Double replace) { - return replace("[" + token + "]", replace.toString()); + return set(token, replace.toString()); } public Message set(String token, Long replace) { - return replace("[" + token + "]", replace.toString()); + return set(token, replace.toString()); } public Message set(String token, Float replace) { - return replace("[" + token + "]", replace.toString()); + return set(token, replace.toString()); + } + + /** + * Resolve the message template to a legacy &-code string using the specified locale. + */ + public String resolve(String locale) { + Component component = resolveComponent(locale); + return MessageRenderer.getInstance().toLegacy(component); + } + + /** + * Resolve the message template to a Component using the default locale. + */ + public Component resolveComponent() { + return resolveComponent(getDefaultLocale()); + } + + /** + * Resolve the message template to a Component using MiniMessage. + * Pipeline: raw template -> .replace() subs -> PAPI -> token replacement -> MiniMessage parse + */ + public Component resolveComponent(String locale) { + return resolveComponent(locale, null); + } + + /** + * Resolve the message template to a Component using MiniMessage, with optional PAPI resolution. + */ + public Component resolveComponent(String locale, CommonPlayer player) { + if (registry == null) return Component.empty(); + + String template = registry.getMessage(key, locale); + if (template == null) return Component.empty(); + + MessageRenderer renderer = MessageRenderer.getInstance(); + + // Step 1: Apply .replace() substitutions on the raw string + template = applyRawReplacements(template); + + // Step 2: Resolve PAPI placeholders individually, escaping MiniMessage tags in output + if (player != null && BanManagerPlugin.getInstance() != null) { + PlaceholderResolver papiResolver = BanManagerPlugin.getInstance().getPlaceholderResolver(); + if (papiResolver != null) { + template = resolvePapiSafe(papiResolver, player, template); + } + } + + // Step 3: Apply static and dynamic tokens as raw string replacements so they + // resolve correctly inside click/hover arguments (MiniMessage TagResolvers + // produce Components which can't be used as click event string values) + template = applyTokenReplacements(template, renderer); + + // Step 4: Parse with MiniMessage (standard tags only, tokens already replaced) + return renderer.render(template); + } + + /** + * Resolve the Component for a specific player, respecting per-player locale. + */ + public Component resolveComponentFor(CommonPlayer player) { + if (player == null) return resolveComponent(getDefaultLocale()); + + BanManagerPlugin plugin = BanManagerPlugin.getInstance(); + String locale = getDefaultLocale(); + if (plugin != null && plugin.getConfig() != null && plugin.getConfig().isPerPlayerLocale()) { + locale = player.getLocale(); + } + return resolveComponent(locale, player); + } + + public String resolveFor(CommonPlayer player) { + Component component = resolveComponentFor(player); + return MessageRenderer.getInstance().toLegacy(component); } public boolean sendTo(CommonSender sender) { if (sender == null) return false; - sender.sendMessage(message); + Component component = resolveComponent(getDefaultLocale()); + sender.sendMessage(component); return true; } @@ -118,13 +216,8 @@ public boolean sendTo(CommonPlayer player) { if (player == null) return false; if (!player.isOnline()) return false; - String resolved = message; - PlaceholderResolver resolver = BanManagerPlugin.getInstance().getPlaceholderResolver(); - if (resolver != null) { - resolved = resolver.resolve(player, message); - } - - player.sendMessage(resolved); + Component component = resolveComponentFor(player); + player.sendMessage(component); return true; } @@ -135,6 +228,66 @@ public static boolean isJSONMessage(String message) { @Override public String toString() { - return message; + return resolve(getDefaultLocale()); + } + + /** + * Apply .replace() raw substitutions on the template string before MiniMessage parsing. + */ + private String applyRawReplacements(String template) { + String result = template; + for (Map.Entry entry : replacements.entrySet()) { + if (entry.getKey().startsWith(REPLACE_PREFIX)) { + String[] pair = entry.getValue(); + result = result.replace(pair[0], pair[1]); + } + } + return result; + } + + /** + * Resolve PAPI placeholders individually, escaping MiniMessage tags in each resolved value + * to prevent injection of formatting/click/hover tags from external placeholder plugins. + */ + private static String resolvePapiSafe(PlaceholderResolver resolver, CommonPlayer player, String template) { + MessageRenderer renderer = MessageRenderer.getInstance(); + Matcher matcher = PAPI_PATTERN.matcher(template); + StringBuffer sb = new StringBuffer(); + while (matcher.find()) { + String placeholder = matcher.group(0); + String resolved = resolver.resolve(player, placeholder); + if (!resolved.equals(placeholder)) { + matcher.appendReplacement(sb, Matcher.quoteReplacement(renderer.escapeTags(resolved))); + } + } + matcher.appendTail(sb); + return sb.toString(); + } + + /** + * Apply static and dynamic token replacements as raw string substitutions. + * Values are tag-escaped to prevent MiniMessage injection. + */ + private String applyTokenReplacements(String template, MessageRenderer renderer) { + String result = template; + + for (Map.Entry entry : renderer.getStaticTokens().entrySet()) { + result = result.replace("<" + entry.getKey() + ">", renderer.escapeTags(entry.getValue())); + } + + for (Map.Entry entry : replacements.entrySet()) { + if (!entry.getKey().startsWith(REPLACE_PREFIX)) { + String tokenName = MessageRenderer.normaliseTagName(entry.getKey()); + String value = entry.getValue()[1]; + result = result.replace("<" + tokenName + ">", renderer.escapeTags(value)); + } + } + + return result; + } + + private static String getDefaultLocale() { + if (registry == null) return "en"; + return registry.getDefaultLocale(); } } diff --git a/common/src/main/java/me/confuser/banmanager/common/util/MessageRegistry.java b/common/src/main/java/me/confuser/banmanager/common/util/MessageRegistry.java new file mode 100644 index 000000000..341946a65 --- /dev/null +++ b/common/src/main/java/me/confuser/banmanager/common/util/MessageRegistry.java @@ -0,0 +1,139 @@ +package me.confuser.banmanager.common.util; + +import java.util.*; + +public class MessageRegistry { + + private static final class Snapshot { + final String defaultLocale; + final Map> locales; + + Snapshot(String defaultLocale, Map> locales) { + this.defaultLocale = defaultLocale; + this.locales = locales; + } + } + + private volatile Snapshot snapshot; + + public MessageRegistry(String defaultLocale) { + this.snapshot = new Snapshot(normaliseLocale(defaultLocale), new HashMap<>()); + } + + public static String normaliseLocale(String locale) { + if (locale == null || locale.isEmpty()) return "en"; + return locale.toLowerCase(Locale.ROOT).replace('-', '_'); + } + + public String getDefaultLocale() { + return snapshot.defaultLocale; + } + + public void loadLocale(String locale, Map messages) { + String normalised = normaliseLocale(locale); + Snapshot s = this.snapshot; + Map> copy = new HashMap<>(s.locales); + copy.put(normalised, Collections.unmodifiableMap(new HashMap<>(messages))); + this.snapshot = new Snapshot(s.defaultLocale, copy); + } + + public String getMessage(String key, String locale) { + String normalised = normaliseLocale(locale); + Snapshot s = this.snapshot; + + String value = getFromLocale(s.locales, key, normalised); + if (value != null) return value; + + int underscore = normalised.indexOf('_'); + if (underscore > 0) { + String baseLanguage = normalised.substring(0, underscore); + value = getFromLocale(s.locales, key, baseLanguage); + if (value != null) return value; + } + + if (!normalised.equals(s.defaultLocale)) { + value = getFromLocale(s.locales, key, s.defaultLocale); + if (value != null) return value; + } + + return null; + } + + public String getMessage(String key) { + return getMessage(key, snapshot.defaultLocale); + } + + public void putMessage(String key, String message) { + putMessage(key, message, snapshot.defaultLocale); + } + + public void putMessage(String key, String message, String locale) { + String normalised = normaliseLocale(locale); + Snapshot s = this.snapshot; + Map> copy = new HashMap<>(s.locales); + Map localeMessages = copy.get(normalised); + + if (localeMessages == null) { + localeMessages = new HashMap<>(); + } else { + localeMessages = new HashMap<>(localeMessages); + } + + localeMessages.put(key, message); + copy.put(normalised, Collections.unmodifiableMap(localeMessages)); + this.snapshot = new Snapshot(s.defaultLocale, copy); + } + + public Set getAvailableLocales() { + return Collections.unmodifiableSet(new HashSet<>(snapshot.locales.keySet())); + } + + public Set getKeys(String locale) { + Map localeMessages = snapshot.locales.get(normaliseLocale(locale)); + if (localeMessages == null) return Collections.emptySet(); + return Collections.unmodifiableSet(localeMessages.keySet()); + } + + public Map getMessages(String locale) { + Map localeMessages = snapshot.locales.get(normaliseLocale(locale)); + if (localeMessages == null) return Collections.emptyMap(); + return localeMessages; + } + + public boolean hasAnyMessages() { + Snapshot s = this.snapshot; + for (Map msgs : s.locales.values()) { + if (!msgs.isEmpty()) return true; + } + return false; + } + + public int getMissingKeyCount(String locale) { + Snapshot s = this.snapshot; + Set defaultKeys = getKeysFromSnapshot(s, s.defaultLocale); + Set localeKeys = getKeysFromSnapshot(s, normaliseLocale(locale)); + int missing = 0; + + for (String key : defaultKeys) { + if (!localeKeys.contains(key)) missing++; + } + + return missing; + } + + public void atomicSwap(MessageRegistry newRegistry) { + this.snapshot = newRegistry.snapshot; + } + + private static Set getKeysFromSnapshot(Snapshot s, String locale) { + Map messages = s.locales.get(locale); + if (messages == null) return Collections.emptySet(); + return messages.keySet(); + } + + private static String getFromLocale(Map> locales, String key, String locale) { + Map messages = locales.get(locale); + if (messages == null) return null; + return messages.get(key); + } +} diff --git a/common/src/main/java/me/confuser/banmanager/common/util/MessageRenderer.java b/common/src/main/java/me/confuser/banmanager/common/util/MessageRenderer.java new file mode 100644 index 000000000..ad8481a74 --- /dev/null +++ b/common/src/main/java/me/confuser/banmanager/common/util/MessageRenderer.java @@ -0,0 +1,284 @@ +package me.confuser.banmanager.common.util; + +import me.confuser.banmanager.common.kyori.text.Component; +import me.confuser.banmanager.common.kyori.text.minimessage.MiniMessage; +import me.confuser.banmanager.common.kyori.text.minimessage.tag.Tag; +import me.confuser.banmanager.common.kyori.text.minimessage.tag.resolver.Placeholder; +import me.confuser.banmanager.common.kyori.text.minimessage.tag.resolver.TagResolver; +import me.confuser.banmanager.common.kyori.text.serializer.gson.GsonComponentSerializer; +import me.confuser.banmanager.common.kyori.text.serializer.legacy.LegacyComponentSerializer; +import me.confuser.banmanager.common.kyori.text.serializer.plain.PlainTextComponentSerializer; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +public class MessageRenderer { + + private static MessageRenderer instance; // guarded by class-level synchronization + + private final MiniMessage miniMessage; + private final LegacyComponentSerializer legacySerializer; + private final PlainTextComponentSerializer plainTextSerializer; + private volatile GsonComponentSerializer gsonSerializer; + private volatile TagResolver staticTokenResolver = TagResolver.empty(); + private volatile Map staticTokens = Collections.emptyMap(); + + private static final Pattern LEGACY_COLOR_PATTERN = Pattern.compile("&[0-9a-fk-or]", Pattern.CASE_INSENSITIVE); + private static final Pattern LEGACY_HEX_PATTERN = Pattern.compile("&#[0-9a-fA-F]{6}"); + + private static final Map LEGACY_CODE_MAP = new HashMap<>(); + + static { + LEGACY_CODE_MAP.put('0', ""); + LEGACY_CODE_MAP.put('1', ""); + LEGACY_CODE_MAP.put('2', ""); + LEGACY_CODE_MAP.put('3', ""); + LEGACY_CODE_MAP.put('4', ""); + LEGACY_CODE_MAP.put('5', ""); + LEGACY_CODE_MAP.put('6', ""); + LEGACY_CODE_MAP.put('7', ""); + LEGACY_CODE_MAP.put('8', ""); + LEGACY_CODE_MAP.put('9', ""); + LEGACY_CODE_MAP.put('a', ""); + LEGACY_CODE_MAP.put('b', ""); + LEGACY_CODE_MAP.put('c', ""); + LEGACY_CODE_MAP.put('d', ""); + LEGACY_CODE_MAP.put('e', ""); + LEGACY_CODE_MAP.put('f', ""); + LEGACY_CODE_MAP.put('k', ""); + LEGACY_CODE_MAP.put('l', ""); + LEGACY_CODE_MAP.put('m', ""); + LEGACY_CODE_MAP.put('n', ""); + LEGACY_CODE_MAP.put('o', ""); + LEGACY_CODE_MAP.put('r', ""); + } + + public MessageRenderer() { + this.miniMessage = MiniMessage.miniMessage(); + this.legacySerializer = LegacyComponentSerializer.builder() + .character('&') + .hexColors() + .build(); + this.plainTextSerializer = PlainTextComponentSerializer.plainText(); + } + + public static synchronized MessageRenderer getInstance() { + if (instance == null) { + instance = new MessageRenderer(); + } + return instance; + } + + public static synchronized void setInstance(MessageRenderer renderer) { + instance = renderer; + } + + /** + * Reset the singleton instance. Intended for test teardown. + */ + public static synchronized void reset() { + instance = null; + } + + /** + * Render a MiniMessage template with additional tag resolvers. + */ + public Component render(String template, TagResolver... extraResolvers) { + if (template == null || template.isEmpty()) { + return Component.empty(); + } + + TagResolver combined = buildResolver(extraResolvers); + return miniMessage.deserialize(template, combined); + } + + /** + * Render a MiniMessage template with string placeholder replacements. + * Values are inserted as literal text (safe from injection). + */ + public Component render(String template, Map placeholders) { + if (placeholders == null || placeholders.isEmpty()) { + return render(template); + } + + List resolvers = new ArrayList<>(); + for (Map.Entry entry : placeholders.entrySet()) { + resolvers.add(Placeholder.unparsed(entry.getKey(), entry.getValue())); + } + return render(template, TagResolver.resolver(resolvers)); + } + + /** + * Serialize a Component to legacy &-code string. + */ + public String toLegacy(Component component) { + if (component == null) return ""; + return legacySerializer.serialize(component); + } + + /** + * Serialize a Component to JSON string. + */ + public String toJson(Component component) { + if (component == null) return "{}"; + return getGsonSerializer().serialize(component); + } + + private GsonComponentSerializer getGsonSerializer() { + if (gsonSerializer == null) { + synchronized (this) { + if (gsonSerializer == null) { + gsonSerializer = GsonComponentSerializer.builder().build(); + } + } + } + return gsonSerializer; + } + + /** + * Serialize a Component to plain text (no formatting). + */ + public String toPlainText(Component component) { + if (component == null) return ""; + return plainTextSerializer.serialize(component); + } + + /** + * Detect whether a string uses legacy &-code formatting. + */ + public boolean isLegacyFormat(String template) { + if (template == null) return false; + return LEGACY_COLOR_PATTERN.matcher(template).find() + || LEGACY_HEX_PATTERN.matcher(template).find(); + } + + /** + * Convert a legacy &-code string to MiniMessage format. + * Only converts color/formatting codes, not [token] placeholders. + */ + public String convertLegacyToMiniMessage(String legacy) { + if (legacy == null) return ""; + + String result = legacy; + + // Convert &#rrggbb to <#rrggbb> + result = result.replaceAll("&#([0-9a-fA-F]{6})", "<#$1>"); + + // Convert &x&r&r&g&g&b&b (Spigot-style) to <#rrggbb> + result = result.replaceAll( + "&x&([0-9a-fA-F])&([0-9a-fA-F])&([0-9a-fA-F])&([0-9a-fA-F])&([0-9a-fA-F])&([0-9a-fA-F])", + "<#$1$2$3$4$5$6>" + ); + + // Convert &0-&f, &k-&o, &r to MiniMessage tags + StringBuilder sb = new StringBuilder(); + int i = 0; + while (i < result.length()) { + if (result.charAt(i) == '&' && i + 1 < result.length()) { + char code = Character.toLowerCase(result.charAt(i + 1)); + String replacement = LEGACY_CODE_MAP.get(code); + if (replacement != null) { + sb.append(replacement); + i += 2; + continue; + } + } + sb.append(result.charAt(i)); + i++; + } + + return sb.toString(); + } + + /** + * Load user-defined static tokens from the messages file tokens section. + */ + public void loadStaticTokens(Map tokens) { + if (tokens == null || tokens.isEmpty()) { + this.staticTokens = Collections.emptyMap(); + this.staticTokenResolver = TagResolver.empty(); + return; + } + + Map normalised = new HashMap<>(); + List resolvers = new ArrayList<>(); + for (Map.Entry entry : tokens.entrySet()) { + String key = normaliseTagName(entry.getKey()); + normalised.put(key, entry.getValue()); + resolvers.add(Placeholder.unparsed(key, entry.getValue())); + } + this.staticTokens = Collections.unmodifiableMap(normalised); + this.staticTokenResolver = TagResolver.resolver(resolvers); + } + + /** + * Get the current static tokens map (for collision detection). + */ + public Map getStaticTokens() { + return staticTokens; + } + + /** + * Build a combined TagResolver with proper priority: + * 1. Dynamic tokens (from extraResolvers) -- highest priority + * 2. Static user-defined tokens + * 3. MiniMessage standard tags (colors, formatting, etc.) + */ + private TagResolver buildResolver(TagResolver... extraResolvers) { + if (extraResolvers == null || extraResolvers.length == 0) { + return TagResolver.resolver(staticTokenResolver, TagResolver.standard()); + } + + TagResolver[] all = new TagResolver[extraResolvers.length + 2]; + System.arraycopy(extraResolvers, 0, all, 0, extraResolvers.length); + all[extraResolvers.length] = staticTokenResolver; + all[extraResolvers.length + 1] = TagResolver.standard(); + return TagResolver.resolver(all); + } + + /** + * Escape MiniMessage tags in a string so it renders as literal text. + */ + public String escapeTags(String input) { + if (input == null) return ""; + return miniMessage.escapeTags(input); + } + + /** + * Convert a relocated Component to a JSON string suitable for native Adventure deserialization. + * Platform adapters can use this for JSON-based bridging to native Adventure. + */ + public String toNativeJson(Component component) { + return toJson(component); + } + + /** + * Normalise a tag name to match MiniMessage's [a-z0-9_-]* pattern. + * Handles acronyms correctly: "playerIP" -> "player_ip", "serverURL" -> "server_url", + * "firstName" -> "first_name", "HTMLParser" -> "html_parser". + */ + public static String normaliseTagName(String name) { + StringBuilder sb = new StringBuilder(name.length() + 4); + for (int i = 0; i < name.length(); i++) { + char c = name.charAt(i); + if (Character.isUpperCase(c)) { + boolean prevUpper = i > 0 && Character.isUpperCase(name.charAt(i - 1)); + boolean nextLower = i + 1 < name.length() && Character.isLowerCase(name.charAt(i + 1)); + if (i > 0 && (!prevUpper || nextLower)) { + sb.append('_'); + } + sb.append(Character.toLowerCase(c)); + } else if (c == ' ') { + sb.append('_'); + } else { + sb.append(c); + } + } + return sb.toString(); + } + +} diff --git a/common/src/main/java/me/confuser/banmanager/common/util/NotificationUtils.java b/common/src/main/java/me/confuser/banmanager/common/util/NotificationUtils.java new file mode 100644 index 000000000..54a370d8f --- /dev/null +++ b/common/src/main/java/me/confuser/banmanager/common/util/NotificationUtils.java @@ -0,0 +1,55 @@ +package me.confuser.banmanager.common.util; + +import me.confuser.banmanager.common.BanManagerPlugin; +import me.confuser.banmanager.common.CommonPlayer; +import me.confuser.banmanager.common.configs.NotificationsConfig; +import me.confuser.banmanager.common.kyori.text.Component; + +public class NotificationUtils { + + private NotificationUtils() {} + + public static void notifyStaff(BanManagerPlugin plugin, String event, Message message, String permission) { + if (!plugin.getConfig().isDisplayNotificationsEnabled()) return; + + NotificationsConfig.NotificationChannel channel = plugin.getNotificationsConfig().getStaffChannel(event); + + for (CommonPlayer player : plugin.getServer().getOnlinePlayers()) { + if (!player.hasPermission(permission)) continue; + + Component resolved = message.resolveComponentFor(player); + + if (channel.isChat()) { + player.sendMessage(resolved); + } + if (channel.isActionbar()) { + player.sendActionBar(resolved); + } + if (channel.isTitle()) { + player.showTitle(resolved, Component.empty(), + channel.getTitleFadeIn(), channel.getTitleStay(), channel.getTitleFadeOut()); + } + if (channel.hasSound()) { + player.playSound(channel.getSound(), channel.getSoundVolume(), channel.getSoundPitch()); + } + } + + plugin.getServer().getConsoleSender().sendMessage( + MessageRenderer.getInstance().toPlainText(message.resolveComponent())); + } + + public static void notifyPlayer(CommonPlayer player, Message message) { + message.sendTo(player); + } + + /** + * Play the warned sound for a player without re-sending the message. + */ + public static void playWarnedSound(BanManagerPlugin plugin, CommonPlayer player) { + NotificationsConfig config = plugin.getNotificationsConfig(); + String sound = config.getWarnedSound(); + if (sound != null && !sound.isEmpty()) { + player.playSound(sound, config.getWarnedSoundVolume(), config.getWarnedSoundPitch()); + } + } +} diff --git a/common/src/main/java/me/confuser/banmanager/common/util/PaginatedView.java b/common/src/main/java/me/confuser/banmanager/common/util/PaginatedView.java new file mode 100644 index 000000000..486156fcb --- /dev/null +++ b/common/src/main/java/me/confuser/banmanager/common/util/PaginatedView.java @@ -0,0 +1,82 @@ +package me.confuser.banmanager.common.util; + +import me.confuser.banmanager.common.commands.CommonSender; +import me.confuser.banmanager.common.kyori.text.Component; + +import java.util.List; + +public class PaginatedView { + + private static final int DEFAULT_PAGE_SIZE = 8; + + private final List items; + private final int pageSize; + private final String command; + + public PaginatedView(List items, String command) { + this(items, command, DEFAULT_PAGE_SIZE); + } + + public PaginatedView(List items, String command, int pageSize) { + this.items = items; + this.command = command; + this.pageSize = pageSize; + } + + public int getTotalPages() { + return Math.max(1, (int) Math.ceil((double) items.size() / pageSize)); + } + + public void send(CommonSender sender, int page) { + send(sender, page, null, null); + } + + public void send(CommonSender sender, int page, Component header, Component footer) { + int totalPages = getTotalPages(); + int safePage = Math.max(1, Math.min(page, totalPages)); + int start = (safePage - 1) * pageSize; + int end = Math.min(start + pageSize, items.size()); + + if (header != null) { + sender.sendMessage(header); + } + + for (int i = start; i < end; i++) { + sender.sendMessage(items.get(i)); + } + + if (totalPages > 1 && !sender.isConsole()) { + sender.sendMessage(buildNavigation(safePage, totalPages)); + } else if (totalPages > 1) { + // Console doesn't support click events, so send a plain legacy string instead + sender.sendMessage(MessageRenderer.getInstance().toLegacy( + MessageRenderer.getInstance().render("Page " + safePage + " of " + totalPages + ""))); + } + + if (footer != null) { + sender.sendMessage(footer); + } + } + + private Component buildNavigation(int currentPage, int totalPages) { + MessageRenderer renderer = MessageRenderer.getInstance(); + String escapedCommand = renderer.escapeTags(command); + + StringBuilder nav = new StringBuilder(); + + if (currentPage > 1) { + nav.append("Previous page\">« "); + } + + nav.append("Page ").append(currentPage).append(" of ") + .append(totalPages).append(""); + + if (currentPage < totalPages) { + nav.append(" Next page\">»"); + } + + return renderer.render(nav.toString()); + } +} diff --git a/common/src/main/java/me/confuser/banmanager/common/util/ReportList.java b/common/src/main/java/me/confuser/banmanager/common/util/ReportList.java index 1e1ea38e7..721fa8bd8 100644 --- a/common/src/main/java/me/confuser/banmanager/common/util/ReportList.java +++ b/common/src/main/java/me/confuser/banmanager/common/util/ReportList.java @@ -1,12 +1,11 @@ package me.confuser.banmanager.common.util; import lombok.Getter; -import me.confuser.banmanager.common.CommonPlayer; import me.confuser.banmanager.common.commands.CommonSender; import me.confuser.banmanager.common.data.PlayerReportData; -import me.confuser.banmanager.common.kyori.text.event.ClickEvent; -import me.confuser.banmanager.common.kyori.text.serializer.legacy.LegacyComponentSerializer; +import me.confuser.banmanager.common.kyori.text.Component; +import java.util.ArrayList; import java.util.List; public class ReportList { @@ -25,32 +24,31 @@ public ReportList(List list, long count, long maxPage) { } public void send(CommonSender sender, int page) { - String dateTimeFormat = Message.getString("report.list.row.dateTimeFormat"); + String dateTimeFormat = Message.getRawTemplate("report.list.row.dateTimeFormat"); - Message.get("report.list.row.header") + Component header = Message.get("report.list.row.header") .set("page", page) .set("maxPage", getMaxPage()) .set("count", getCount()) - .sendTo(sender); + .resolveComponent(); + + List items = new ArrayList<>(); for (PlayerReportData report : getList()) { - String message = Message.get("report.list.row.all") + Component row = Message.get("report.list.row.all") .set("id", report.getId()) .set("state", report.getState().getName()) .set("player", report.getPlayer().getName()) .set("actor", report.getActor().getName()) .set("reason", report.getReason()) .set("created", DateUtils.format(dateTimeFormat, report.getCreated())) - .set("updated", DateUtils.format(dateTimeFormat, report.getUpdated())).toString(); - - if (sender.isConsole()) { - sender.sendMessage(message); - } else { - ((CommonPlayer) sender).sendJSONMessage( - LegacyComponentSerializer.legacy('&').deserialize( - message).clickEvent(ClickEvent.runCommand("/reports info " + report.getId() - ))); - } + .set("updated", DateUtils.format(dateTimeFormat, report.getUpdated())) + .resolveComponent(); + + items.add(row); } + + PaginatedView view = new PaginatedView(items, "/reports list"); + view.send(sender, page, header, null); } } diff --git a/common/src/main/resources/config.yml b/common/src/main/resources/config.yml index 50f49665d..a1de75a53 100644 --- a/common/src/main/resources/config.yml +++ b/common/src/main/resources/config.yml @@ -1,3 +1,7 @@ +locale: + default: en + perPlayer: true + debug: false databases: # Local Database is always required. If not enabled, plugin will disable on startup. diff --git a/common/src/main/resources/db/local/V2__add_player_locale.sql b/common/src/main/resources/db/local/V2__add_player_locale.sql new file mode 100644 index 000000000..f725c3df5 --- /dev/null +++ b/common/src/main/resources/db/local/V2__add_player_locale.sql @@ -0,0 +1 @@ +ALTER TABLE ${players} ADD COLUMN `locale` VARCHAR(16) NULL; diff --git a/common/src/main/resources/db/local/migrations.list b/common/src/main/resources/db/local/migrations.list index a43ed9c9a..43cde01af 100644 --- a/common/src/main/resources/db/local/migrations.list +++ b/common/src/main/resources/db/local/migrations.list @@ -1 +1,2 @@ V1__baseline.sql lenient +V2__add_player_locale.sql lenient diff --git a/common/src/main/resources/messages.yml b/common/src/main/resources/messages.yml deleted file mode 100644 index 205a94c13..000000000 --- a/common/src/main/resources/messages.yml +++ /dev/null @@ -1,448 +0,0 @@ -# Variables -# [reason] = Ban/Mute reason -# [player] = The name of the player -# [ip] = The banned ip -# [actor] = Who banned/muted -# [expires] = How long until the ban/mute ends - -messages: - duplicateIP: '&cWarning: [player] has the same IP as the following banned players:\n&6[players]' - duplicateIPAlts: '&cWarning: [player] has the same IP as the following players:\n&6[players]' - configReloaded: '&aConfiguration reloaded successfully!' - deniedNotify: - player: '&cWarning: [player] attempted to join the server but was denied due to &4[reason]' - ip: '&cWarning: [ip] attempted to join the server but was denied due to &4[reason]' - deniedMaxIp: '&cToo many players with your ip address online' - deniedMultiaccounts: '&cToo many players with your ip address logged in recently' - deniedCountry: '&cYou may not connect from your region' - - time: - now: 'now' - year: 'year' - years: 'years' - month: 'month' - months: 'months' - week: 'week' - weeks: 'weeks' - day: 'day' - days: 'days' - hour: 'hour' - hours: 'hours' - minute: 'minute' - minutes: 'minutes' - second: 'second' - seconds: 'seconds' - never: 'never' - error: - invalid: '&cYour time length is invalid' - limit: '&cYou cannot perform this action for that length of time' - - none: 'none' - # General command text - sender: - error: - notFound: '&c[player] not found, are you sure they exist?' - offline: '&c[player] is offline' - noSelf: '&cYou cannot perform that action on yourself!' - exception: '&cAn error occured whilst attempting to perform this command. Please check the console for further details.' - invalidIp: '&cInvalid IP address, expecting w.x.y.z format' - offlinePermission: '&cYou are not allowed to perform this action on an offline player' - ambiguousPlayer: '&cMultiple players match "[player]". Please use their full name.' - exempt: '&c[player] is exempt from that action' - noPermission: '&cYou do not have permission to perform that action' - invalidReason: '&c[reason] is no valid reason.' - # Commands - alts: - header: 'Possible alts found:' - - names: - header: 'Known names for [player]:' - row: '&e[name] &7(first: [firstSeen], last: [lastSeen])' - dateTimeFormat: 'dd-MM-yyyy' - none: '&7No name history found' - - export: - error: - inProgress: '&cAn export is already in progress, please wait' - player: - started: '&aPlayer ban export started' - finished: '&aPlayer ban export finished, file [file] created' - ip: - started: '&aIP ban export started' - finished: '&aIP ban export finished, file [file] created' - - import: - error: - inProgress: '&cAn import is already in progress, please wait' - player: - started: '&aPlayer ban import started' - finished: '&aPlayer ban import finished' - ip: - started: '&aIP ban import started' - finished: '&aIP ban import finished' - advancedban: - started: '&aAdvancedBan import started' - finished: '&aAdvancedBan import finished' - h2: - started: '&aH2 import started' - finished: '&aH2 import finished, please restart the server' - litebans: - started: '&aLiteBans import started' - finished: '&aLiteBans import finished' - - info: - error: - invalidIndex: '&cInvalid player option used' - indexRequired: '&cMultiple players named [name] found, please select a player by providing an index between 1 and [size], e.g. /bminfo [name] 1' - index: '&7#[index] - &6[name] - &4[uuid]' - stats: - player: '&6[player] has been banned [bans] times, muted [mutes] times, kicked [kicks] times and warned [warns] - times ([warnPoints] Points), has [notes] notes and been reported [reports] times' - ip: '&6This ip has been banned [bans] times, muted [mutes] times and range banned [rangebans] times' - connection: '&6Their last connection was with [ip] on [lastSeen]' - geoip: 'Country: [country] City: [city]' - ban: - permanent: '&6Currently banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently banned for &4[reason]&6 by [actor] at [created] which expires in [expires]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - ipban: - permanent: '&6Currently banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently banned for &4[reason]&6 by [actor] at [created] which expires in [expires]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - iprangeban: - permanent: '&6[from] - [to] banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6[from] - [to] banned for &4[reason]&6 by [actor] at [created] which expires in [expires]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - ipmute: - permanent: '&6Currently muted for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently muted for &4[reason]&6 by [actor] at [created] which expires in [expires]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - mute: - permanent: '&6Currently muted for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently muted for &4[reason]&6 by [actor] at [created] which expires in [expires]' - temporaryOnline: '&6Currently muted for &4[reason]&6 by [actor] at [created] which expires in [expires] (online time)' - temporaryOnlinePaused: '&6Currently muted for &4[reason]&6 by [actor] at [created] with [remaining] remaining (online time, paused)' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - website: - player: 'https://yourdomain.com/player/[uuid]' - ip: 'http://yourdomain.com/index.php?action=viewip&ip=[ip]&server=0' - history: - row: '&7#[id] &a[&f[type]&a] &6[actor]&f [meta] [reason] - &e[created]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - noResults: '&cNo results found' - ips: - row: '&e[ip] - &6[join] - [leave]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - - kick: - player: - noReason: '&6You have been kicked' - reason: '&6You have been kicked for &4[reason]' - notify: - noReason: '&6[player] has been kicked by [actor]' - reason: '&6[player] has been kicked by [actor] for &4[reason]' - - kickall: - player: - noReason: '&6You have been kicked' - reason: '&6You have been kicked for &4[reason]' - notify: - noReason: 'All players have been kicked by [actor]' - reason: 'All players have been kicked by [actor] for &4[reason]' - - ban: - player: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6[player] has been permanently banned by [actor] for &4[reason]' - error: - exists: '&c[player] is already banned' - cooldown: '&cThis player was banned too recently, try again later' - - banall: - notify: '&6[player] will be permanently banned by [actor] for &4[reason]' - - tempban: - player: - disallowed: '&6You have been temporarily banned from this server for &4[reason] \n&6It expires in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6[player] has been temporarily banned for [expires] by [actor] for &4[reason]' - - tempbanall: - notify: '&6[player] will be temporarily banned for [expires] by [actor] for &4[reason]' - - unban: - notify: '&6[player] has been unbanned by [actor]' - error: - noExists: '&c[player] is not banned' - notOwn: '&c[player] was not banned by you, unable to unban' - - unbanall: - notify: '&6[player] will be unbanned by [actor]' - - mute: - player: - blocked: '&cYou may not use the [command] command whilst muted!' - disallowed: '&6You have been permanently muted for &4[reason] &6by [actor]' - broadcast: '&4[Muted] [player]&7 [message]' - notify: '&6[player] has been permanently muted by [actor] for &4[reason]' - error: - exists: '&c[player] is already muted' - cooldown: '&cThis player was muted too recently, try again later' - - muteip: - ip: - disallowed: '&6You have been permanently muted for &4[reason] &6by [actor]' - broadcast: '&4[Muted] [player]&7 [message]' - notify: '&6[ip] ([players]) have been permanently muted by [actor] for &4[reason]' - error: - exists: '&c[ip] is already muted' - - muteall: - notify: '&6[player] will be permanently muted by [actor] for &4[reason]' - - tempmute: - player: - disallowed: '&6You have been temporarily muted for &4[reason] &6by [actor] which expires in [expires]' - disallowedOnline: '&6You have been temporarily muted for &4[reason] &6by [actor] which expires in [expires] (online time)' - notify: '&6[player] has been temporarily muted for [expires] by [actor] for &4[reason]' - notifyOnline: '&6[player] has been temporarily muted for [expires] (online time) by [actor] for &4[reason]' - error: - exists: '&c[player] is already muted' - - tempmuteip: - ip: - disallowed: '&6You have been temporarily muted for &4[reason] &6by [actor] which expires in [expires]' - notify: '&6[ip] ([players]) have been temporarily muted for [expires] by [actor] for &4[reason]' - error: - exists: '&c[ip] is already muted' - - tempmuteall: - notify: '&6[player] will be temporarily muted for [expires] by [actor] for &4[reason]' - - unmute: - notify: '&6[player] has been unmuted by [actor]' - player: '&6You have been unmuted by [actor]' - error: - noExists: '&c[player] is not muted' - notOwn: '&c[player] was not muted by you, unable to unmute' - - unmuteip: - notify: '&6[ip] has been unmuted by [actor]' - error: - noExists: '&c[ip] is not muted' - notOwn: '&c[ip] was not muted by you, unable to unmute' - - unmuteall: - notify: '&6[player] will be unmuted by [actor]' - - banname: - name: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6Name [name] has been permanently banned by [actor] for &4[reason]' - error: - exists: '&cName [name] is already banned' - - tempbanname: - name: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6Name [name] has been temporarily banned for [expires] by [actor] for &4[reason]' - - unbanname: - notify: '&6Name [name] has been unbanned by [actor]' - error: - noExists: '&cName [name] is not banned' - - banip: - ip: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6[ip] ([players]) has been permanently banned by [actor] for &4[reason]' - error: - exists: '&c[ip] is already banned' - cooldown: '&cThis ip was banned too recently, try again later' - - baniprange: - error: - invalid: '&cInvalid range, please use cidr notation 192.168.0.1/16 or wildcard 192.168.*.*' - minMax: '&cRange must be lowest to highest' - exists: '&cA ban containing those ranges already exists' - ip: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6[from] - [to] have been banned by [actor]' - - tempbaniprange: - notify: '&6[from] - [to] has been temporarily banned for [expires] by [actor]' - ip: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires in [expires]' - kick: '&6You have been temporarily banned for [expires] by [actor] for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - - unbaniprange: - notify: '&6[from] - [to] has been unbanned by [actor]' - - banipall: - notify: '&6[ip] will be permanently banned by [actor] for &4[reason]' - - tempbanip: - ip: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6[ip] ([players]) has been temporarily banned for [expires] by [actor] for &4[reason]' - - tempbanipall: - notify: '&6[ip] will be temporarily banned for [expires] by [actor] for &4[reason]' - - unbanip: - notify: '&6[ip] has been unbanned by [actor]' - error: - noExists: '&c[ip] is not banned' - notOwn: '&c[ip] was not banned by you, unable to unban' - - unbanipall: - notify: '&6[ip] will be unbanned by [actor]' - - warn: - player: - warned: '&6You have been warned by [actor] for &4[reason]' - disallowed: - header: '&cYou may not speak until you have accepted your most recent warning. Please type the following:' - reason: '&6[reason]' - removed: '&aThank you for your understanding, you may now speak again' - notify: '&6[player] has been warned by [actor] for &4[reason]' - error: - cooldown: '&cThis player was warned too recently, try again later' - - tempwarn: - player: - warned: '&6You have been warned for [expires] by [actor] for &4[reason]' - notify: '&6[player] has been warned for [expires] by [actor] for &4[reason]' - - dwarn: - player: - notify: '&6Your most recent warning has been deleted by &4[actor]' - notify: '&cThe most recent warning for [player] has been deleted' - error: - noWarnings: '&c[player] has no warnings to delete' - - bmclear: - notify: '&c[player] has had their [type] cleared' - error: - invalid: '&cInvalid type, please choose between banrecords, muterecords, kicks, notes or warnings' - - bmutils: - missingplayers: - notify: '&c[amount] missing players added' - noneFound: '&a0 missing players found' - found: '&c[amount] missing player data found. Fixing...' - error: - failedLookup: '&cFailed to lookup player [uuid], check server logs' - complete: '&a[amount] players resolved, please restart your server for failed punishments to take affect' - duplicates: - lookup: - notFound: '&aNo duplicate player names found' - error: - invalidName: '&cInvalid name, must be 16 characters or less and contain only letters, numbers and an underscore' - nameExists: '&cA player with that name already exists' - success: '&aPlayer name set to [player] successfully' - - bmrollback: - notify: '&c[player] has had their [type] actions undone' - error: - invalid: '&cInvalid type [type], please choose between [types]' - - sync: - player: - started: '&aStarting force [type] synchronisation' - finished: '&aForced [type] synchronisation complete' - - update: - notify: '&6[BanManager] &aAn update is available' - - notes: - header: '&6[player] has the following notes:' - joinAmount: '&6[player] has &e[amount] &6notes, click to view them' - note: '&6[[player]] &e[message] - &e[created]' - playerNote: '&a[[player]] &6[[actor]] &e[message] - &e[created]' - dateTimeFormat: 'dd-MM-yyyy' - notify: '[player] has a new note attached by [actor]: [message]' - error: - noNotes: '&c[player] has no notes' - noOnlineNotes: '&cNo online players have notes' - - report: - notify: '&6[player] has been reported by [actor] for &4[reason]' - error: - cooldown: '&cThis player was reported too recently, try again later' - assign: - player: '&aReport [id] assigned to [player]' - notify: '&aYou have been assigned report [id] by [actor]' - unassign: - player: '&aReport [id] unassigned' - close: - notify: - closed: '&aReport [id] closed by [actor]' - command: '&aReport [id] closed by [actor] with [command]' - comment: '&aReport [id] closed by [actor] with [comment]' - dispatch: 'Executing command [command]' - list: - noResults: '&cNo reports found' - error: - invalidState: '&cReport state [state] not found' - row: - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - header: '&e-- Reports ([count]) -- Page ([page]/[maxPage])' - all: '&7#[id] &e[[state]] &6- [created] - [player]' - tp: - error: - notFound: '&cReport not found' - worldNotFound: '&cWorld [world] could not be found' - invalidId: '&c[id] is not a valid report id' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: - report: '&7#[id] &6[actor] reported [player] for &4[reason]&6 at [created]' - location: '[world] - [x], [y], [z]' - info: - error: - notFound: '&cReport not found' - invalidId: '&c[id] is not a valid report id' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: - report: '&7#[id] &6[actor] reported [player] for &4[reason]&6 at [created]' - location: '[world] - [x], [y], [z]' - - addnoteall: - notify: '&c[player] will have a new attached by [actor]: [message]' - - banlist: - header: '&6There are [bans] [type] bans:' - - bmactivity: - row: - all: '&a[&f[type]&a] &6[player]&f - &6[actor]&f - &e[created]' - player: '&a[&f[type]&a] &6[player]&f - &e[created]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - noResults: '&cNo results found' - - bmdelete: - notify: '&a[rows] rows deleted' - error: - invalid: '&cInvalid type, please choose between banrecords, muterecords, kicks, notes or warnings' - invalidId: '&c[id] is not a valid number' - - denyalts: - player: - disallowed: '&cThe IP address you are joining from is linked to a banned player' - - reasons: - row: '[hashtag] = [reason]' diff --git a/common/src/main/resources/messages/messages_en.yml b/common/src/main/resources/messages/messages_en.yml new file mode 100644 index 000000000..1930ce4a0 --- /dev/null +++ b/common/src/main/resources/messages/messages_en.yml @@ -0,0 +1,474 @@ +# Message templates use MiniMessage formatting: https://docs.advntr.dev/minimessage/format.html +# Placeholders use angle brackets, e.g. , , , , + +tokens: + appeal_url: 'https://yourdomain.com/appeal' + server_name: 'My Server' + discord_url: 'https://discord.gg/example' + rules_url: 'https://yourdomain.com/rules' + +messages: + duplicateIP: 'Warning: has the same IP as the following banned players:\n' + duplicateIPAlts: 'Warning: has the same IP as the following players:\n' + configReloaded: 'Configuration reloaded successfully!' + deniedNotify: + player: 'Warning: attempted to join the server but was denied due to ' + ip: 'Warning: attempted to join the server but was denied due to ' + deniedMaxIp: 'Too many players with your ip address online' + deniedMultiaccounts: 'Too many players with your ip address logged in recently' + deniedCountry: 'You may not connect from your region' + + time: + now: 'now' + year: 'year' + years: 'years' + month: 'month' + months: 'months' + week: 'week' + weeks: 'weeks' + day: 'day' + days: 'days' + hour: 'hour' + hours: 'hours' + minute: 'minute' + minutes: 'minutes' + second: 'second' + seconds: 'seconds' + never: 'never' + error: + invalid: 'Your time length is invalid' + limit: 'You cannot perform this action for that length of time' + + none: 'none' + # General command text + sender: + error: + notFound: ' not found, are you sure they exist?' + offline: ' is offline' + noSelf: 'You cannot perform that action on yourself!' + exception: 'An error occurred whilst attempting to perform this command. Please check the console for further details.' + invalidIp: 'Invalid IP address, expecting w.x.y.z format' + offlinePermission: 'You are not allowed to perform this action on an offline player' + ambiguousPlayer: 'Multiple players match "". Please use their full name.' + exempt: ' is exempt from that action' + noPermission: 'You do not have permission to perform that action' + noConsole: 'This command cannot be used from console' + invalidReason: ' is not a valid reason.' + # Commands + alts: + header: 'Possible alts found:' + entry: '">' + separator: ', ' + + names: + header: 'Known names for :' + row: ' (first: , last: )' + interactive: ' (first: , last: )">">' + separator: ', ' + dateTimeFormat: 'dd-MM-yyyy' + none: 'No name history found' + + export: + error: + inProgress: 'An export is already in progress, please wait' + player: + started: 'Player ban export started' + finished: 'Player ban export finished, file created' + ip: + started: 'IP ban export started' + finished: 'IP ban export finished, file created' + + import: + error: + inProgress: 'An import is already in progress, please wait' + player: + started: 'Player ban import started' + finished: 'Player ban import finished' + ip: + started: 'IP ban import started' + finished: 'IP ban import finished' + advancedban: + started: 'AdvancedBan import started' + finished: 'AdvancedBan import finished' + h2: + started: 'H2 import started' + finished: 'H2 import finished, please restart the server' + litebans: + started: 'LiteBans import started' + finished: 'LiteBans import finished' + + info: + error: + invalidIndex: 'Invalid player option used' + indexRequired: 'Multiple players named found, please select a player by providing an index between 1 and , e.g. /bminfo 1' + index: '# - - ' + stats: + player: ' has been banned times, muted times, kicked times and warned + times ( Points), has notes and been reported times' + ip: 'This ip has been banned times, muted times and range banned times' + connection: 'Their last connection was with on ' + geoip: 'Country: City: ' + ban: + permanent: 'Currently banned for by at ' + temporary: 'Currently banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + ipban: + permanent: 'Currently banned for by at ' + temporary: 'Currently banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + iprangeban: + permanent: ' - banned for by at ' + temporary: ' - banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + ipmute: + permanent: 'Currently muted for by at ' + temporary: 'Currently muted for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + mute: + permanent: 'Currently muted for by at ' + temporary: 'Currently muted for by at which expires in ' + temporaryOnline: 'Currently muted for by at which expires in (online time)' + temporaryOnlinePaused: 'Currently muted for by at with remaining (online time, paused)' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + website: + player: 'https://yourdomain.com/player/' + ip: 'http://yourdomain.com/index.php?action=viewip&ip=&server=0' + history: + row: '# [] - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + noResults: 'No results found' + ips: + row: ' - - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + + kick: + player: + noReason: 'You have been kicked' + reason: 'You have been kicked for ' + notify: + noReason: ' has been kicked by ">View player info">[Info]' + reason: ' has been kicked by for ">View player info">[Info]' + + kickall: + player: + noReason: 'You have been kicked' + reason: 'You have been kicked for ' + notify: + noReason: 'All players have been kicked by ' + reason: 'All players have been kicked by for ' + + ban: + player: + disallowed: 'You are banned from this server\n \nReason: \nBanned by: \nDate: \n \nAppeal at ' + kick: 'You have been banned\n \nReason: \nBanned by: \nDate: \n \nAppeal at ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' has been permanently banned by for ">View player info">[Info] ">Unban player">[Unban]' + error: + exists: ' is already banned' + cooldown: 'This player was banned too recently, try again later' + + banall: + notify: ' will be permanently banned by for ' + + tempban: + player: + disallowed: 'You are temporarily banned from this server\n \nReason: \nBanned by: \nExpires: \nDate: \n \nAppeal at ' + kick: 'You have been temporarily banned\n \nReason: \nBanned by: \nExpires: \nDate: \n \nAppeal at ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' has been temporarily banned for by for ">View player info">[Info] ">Unban player">[Unban]' + + tempbanall: + notify: ' will be temporarily banned for by for ' + + unban: + notify: ' has been unbanned by ' + error: + noExists: ' is not banned' + notOwn: ' was not banned by you, unable to unban' + + unbanall: + notify: ' will be unbanned by ' + + mute: + player: + blocked: 'You may not use the command whilst muted!' + disallowed: 'You have been permanently muted for by ' + broadcast: '[Muted] ' + notify: ' has been permanently muted by for ">View player info">[Info] ">Unmute player">[Unmute]' + error: + exists: ' is already muted' + cooldown: 'This player was muted too recently, try again later' + + muteip: + ip: + disallowed: 'You have been permanently muted for by ' + broadcast: '[Muted] ' + notify: ' () have been permanently muted by for ' + error: + exists: ' is already muted' + + muteall: + notify: ' will be permanently muted by for ' + + tempmute: + player: + disallowed: 'You have been temporarily muted for by which expires in ' + disallowedOnline: 'You have been temporarily muted for by which expires in (online time)' + notify: ' has been temporarily muted for by for ">View player info">[Info] ">Unmute player">[Unmute]' + notifyOnline: ' has been temporarily muted for (online time) by for ' + error: + exists: ' is already muted' + + tempmuteip: + ip: + disallowed: 'You have been temporarily muted for by which expires in ' + notify: ' () have been temporarily muted for by for ' + error: + exists: ' is already muted' + + tempmuteall: + notify: ' will be temporarily muted for by for ' + + unmute: + notify: ' has been unmuted by ' + player: 'You have been unmuted by ' + error: + noExists: ' is not muted' + notOwn: ' was not muted by you, unable to unmute' + + unmuteip: + notify: ' has been unmuted by ' + error: + noExists: ' is not muted' + notOwn: ' was not muted by you, unable to unmute' + + unmuteall: + notify: ' will be unmuted by ' + + banname: + name: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: 'Name has been permanently banned by for ' + error: + exists: 'Name is already banned' + + tempbanname: + name: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: 'Name has been temporarily banned for by for ' + + unbanname: + notify: 'Name has been unbanned by ' + error: + noExists: 'Name is not banned' + + banip: + ip: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' () has been permanently banned by for ' + error: + exists: ' is already banned' + cooldown: 'This ip was banned too recently, try again later' + + baniprange: + error: + invalid: 'Invalid range, please use cidr notation 192.168.0.1/16 or wildcard 192.168.*.*' + minMax: 'Range must be lowest to highest' + exists: 'A ban containing those ranges already exists' + ip: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' - have been banned by ' + + tempbaniprange: + notify: ' - has been temporarily banned for by ' + ip: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for by for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + + unbaniprange: + notify: ' - has been unbanned by ' + + banipall: + notify: ' will be permanently banned by for ' + + tempbanip: + ip: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' () has been temporarily banned for by for ' + + tempbanipall: + notify: ' will be temporarily banned for by for ' + + unbanip: + notify: ' has been unbanned by ' + error: + noExists: ' is not banned' + notOwn: ' was not banned by you, unable to unban' + + unbanipall: + notify: ' will be unbanned by ' + + warn: + player: + warned: 'You have been warned by for ' + disallowed: + header: 'You may not speak until you have accepted your most recent warning. Please type the following:' + reason: '' + removed: 'Thank you for your understanding, you may now speak again' + notify: ' has been warned by for ">View player info">[Info]' + error: + cooldown: 'This player was warned too recently, try again later' + + tempwarn: + player: + warned: 'You have been warned for by for ' + notify: ' has been warned for by for ">View player info">[Info]' + + dwarn: + player: + notify: 'Your most recent warning has been deleted by ' + notify: 'The most recent warning for has been deleted' + error: + noWarnings: ' has no warnings to delete' + + bmclear: + notify: ' has had their cleared' + error: + invalid: 'Invalid type, please choose between banrecords, muterecords, kicks, notes or warnings' + + bmutils: + missingplayers: + notify: ' missing players added' + noneFound: '0 missing players found' + found: ' missing player data found. Fixing...' + error: + failedLookup: 'Failed to lookup player , check server logs' + complete: ' players resolved, please restart your server for failed punishments to take affect' + duplicates: + lookup: + notFound: 'No duplicate player names found' + error: + invalidName: 'Invalid name, must be 16 characters or less and contain only letters, numbers and an underscore' + nameExists: 'A player with that name already exists' + success: 'Player name set to successfully' + + bmrollback: + notify: ' has had their actions undone' + error: + invalid: 'Invalid type , please choose between ' + + sync: + player: + started: 'Starting force synchronisation' + finished: 'Forced synchronisation complete' + + update: + notify: '[BanManager] An update is available' + + notes: + header: ' has the following notes:' + joinAmount: '"> has notes, click to view them' + note: '[] - ' + playerNote: '[] [] - ' + dateTimeFormat: 'dd-MM-yyyy' + notify: ' has a new note attached by : ' + error: + noNotes: ' has no notes' + noOnlineNotes: 'No online players have notes' + + report: + notify: ' has been reported by for ' + error: + cooldown: 'This player was reported too recently, try again later' + assign: + player: 'Report assigned to ' + notify: 'You have been assigned report by ' + unassign: + player: 'Report unassigned' + close: + notify: + closed: 'Report closed by ' + command: 'Report closed by with ' + comment: 'Report closed by with ' + dispatch: 'Executing command ' + list: + noResults: 'No reports found' + error: + invalidState: 'Report state not found' + row: + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + header: '-- Reports () -- Page (/)' + all: '">Click to view details"># [] - - ' + tp: + error: + notFound: 'Report not found' + worldNotFound: 'World could not be found' + invalidId: ' is not a valid report id' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: + report: '# reported for at ' + location: ' - , , ' + info: + error: + notFound: 'Report not found' + invalidId: ' is not a valid report id' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: + report: '# reported for at ' + location: ' - , , ' + actions: + assign: '">Assign to yourself">[Assign]' + close: '">Close this report">[Close]' + tp: '">Teleport to location">[TP]' + feedback: + assigned: 'Your report # has been assigned to ' + closed: 'Your report # has been closed by ' + + addnoteall: + notify: ' will have a new note attached by : ' + + banlist: + header: 'There are bans:' + row: + player: '">Click for info"> - ' + ip: ' - ' + iprange: ' - - ' + + bmactivity: + row: + all: '[] - - ' + player: '[] - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + noResults: 'No results found' + + bmdelete: + notify: ' rows deleted' + error: + invalid: 'Invalid type, please choose between banrecords, muterecords, kicks, notes or warnings' + invalidId: ' is not a valid number' + + denyalts: + player: + disallowed: 'The IP address you are joining from is linked to a banned player' + + reasons: + row: ' = ' + + dashboard: + header: ' Staff Dashboard ' + activeBans: 'Active Bans: ' + activeMutes: 'Active Mutes: ' + openReports: 'Open Reports: View reports">[View]' + recentActivity: 'Recent Activity (24h): ' + footer: ' ' diff --git a/common/src/main/resources/notifications.yml b/common/src/main/resources/notifications.yml new file mode 100644 index 000000000..150597971 --- /dev/null +++ b/common/src/main/resources/notifications.yml @@ -0,0 +1,80 @@ +# Notifications Configuration +# Controls how punishment notifications are delivered to staff and players +# +# Each notification event can specify delivery channels: +# chat: true/false - Send via chat message (default: true) +# actionbar: true/false - Send via action bar (disappears after a few seconds) +# title: true/false - Send via title/subtitle overlay +# sound: '' - Sound to play (empty to disable). Use Minecraft sound names e.g. entity.experience_orb.pickup +# +# Title settings (only used when title: true): +# titleFadeIn: ticks for fade in (20 ticks = 1 second) +# titleStay: ticks to stay on screen +# titleFadeOut: ticks for fade out +# +# Sound settings: +# soundVolume: 0.0 - 1.0 +# soundPitch: 0.0 - 2.0 +# +# Platform notes: +# - BungeeCord: title, showTitle and playSound are not supported (ignored silently) +# - All other platforms (Bukkit/Paper, Velocity, Fabric, Sponge) support all channels + +staff: + ban: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + tempban: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + mute: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + tempmute: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + warn: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + report: + chat: true + actionbar: false + title: false + sound: 'block.note_block.pling' + soundVolume: 1.0 + soundPitch: 1.0 + duplicateIp: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + +player: + muted: + actionbar: true + warned: + sound: 'entity.villager.no' + soundVolume: 1.0 + soundPitch: 1.0 diff --git a/common/src/main/resources/plugin.yml b/common/src/main/resources/plugin.yml index 6250f1d94..02fac42ce 100644 --- a/common/src/main/resources/plugin.yml +++ b/common/src/main/resources/plugin.yml @@ -255,6 +255,10 @@ commands: usage: "/unbanname [reason]" alias: [bmunbanname] permission: bm.command.unbanname + bm: + description: "BanManager core commands (dashboard)" + usage: "/bm " + permission: bm.command.bm bmutils: description: "BanManager utility commands" usage: "/bmutils help" @@ -268,6 +272,7 @@ permissions: bm.command.*: description: Gives access to all BanManager commands children: + bm.command.bm: true bm.command.alts: true bm.command.ban: true bm.command.ban.offline: true diff --git a/common/src/main/resources/webhooks.yml b/common/src/main/resources/webhooks.yml index 33e924148..aa82fd755 100644 --- a/common/src/main/resources/webhooks.yml +++ b/common/src/main/resources/webhooks.yml @@ -1,6 +1,10 @@ # Webhooks Configuration # More info at https://banmanagement.com/docs/banmanager/configuration/webhooks-yml # +# NOTE: Webhook placeholders use [token] format (e.g. [player], [reason], [actor]). +# This is intentionally separate from MiniMessage's format used in messages. +# Webhooks send JSON to external services and do not use MiniMessage formatting. +# # Each punishment type can have multiple webhooks. Use the array format: # ban: # - name: discord diff --git a/common/src/test/java/me/confuser/banmanager/common/BasePluginTest.java b/common/src/test/java/me/confuser/banmanager/common/BasePluginTest.java index 12f50f31c..720924bc2 100644 --- a/common/src/test/java/me/confuser/banmanager/common/BasePluginTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/BasePluginTest.java @@ -40,7 +40,7 @@ public static PluginInfo setupConfigs(TemporaryFolder folder) { "webhooks.yml", "exemptions.yml", "geoip.yml", - "messages.yml", + "notifications.yml", "reasons.yml", "schedules.yml" }; @@ -58,6 +58,19 @@ public static PluginInfo setupConfigs(TemporaryFolder folder) { } } + File messagesDir = new File(folder.getRoot(), "messages"); + messagesDir.mkdirs(); + try (InputStream in = BasePluginTest.class.getClassLoader().getResource("messages/messages_en.yml").openStream(); + OutputStream out = new FileOutputStream(new File(messagesDir, "messages_en.yml"))) { + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + } catch (IOException e) { + e.printStackTrace(); + } + // Load plugin.yml PluginInfo pluginInfo = new PluginInfo(); try (InputStream in = BasePluginTest.class.getClassLoader().getResource("plugin.yml").openStream(); diff --git a/common/src/test/java/me/confuser/banmanager/common/TestPlayer.java b/common/src/test/java/me/confuser/banmanager/common/TestPlayer.java index e978bbe47..7a00bd3d9 100644 --- a/common/src/test/java/me/confuser/banmanager/common/TestPlayer.java +++ b/common/src/test/java/me/confuser/banmanager/common/TestPlayer.java @@ -2,7 +2,6 @@ import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.kyori.text.TextComponent; -import me.confuser.banmanager.common.util.Message; import java.net.InetAddress; import java.util.UUID; @@ -12,6 +11,7 @@ public class TestPlayer implements CommonPlayer { private final UUID uuid; private final String name; private final boolean onlineMode; + private String locale = "en"; public TestPlayer(UUID uuid, String name, boolean onlineMode) { this.uuid = uuid; @@ -19,16 +19,21 @@ public TestPlayer(UUID uuid, String name, boolean onlineMode) { this.onlineMode = onlineMode; } - @Override - public void kick(String message) { + public TestPlayer(UUID uuid, String name, boolean onlineMode, String locale) { + this(uuid, name, onlineMode); + this.locale = locale; + } + + public void setLocale(String locale) { + this.locale = locale; } @Override - public void sendMessage(String message) { + public void kick(String message) { } @Override - public void sendMessage(Message message) { + public void sendMessage(String message) { } @Override @@ -93,4 +98,9 @@ public boolean teleport(CommonWorld world, double x, double y, double z, float p public boolean canSee(CommonPlayer player) { return true; } + + @Override + public String getLocale() { + return locale; + } } diff --git a/common/src/test/java/me/confuser/banmanager/common/TestSender.java b/common/src/test/java/me/confuser/banmanager/common/TestSender.java index 75599ac4f..7c63c6ed4 100644 --- a/common/src/test/java/me/confuser/banmanager/common/TestSender.java +++ b/common/src/test/java/me/confuser/banmanager/common/TestSender.java @@ -3,8 +3,6 @@ import me.confuser.banmanager.common.commands.CommonCommand; import me.confuser.banmanager.common.commands.CommonSender; import me.confuser.banmanager.common.data.PlayerData; -import me.confuser.banmanager.common.util.Message; - import java.util.UUID; public class TestSender implements CommonSender { @@ -34,11 +32,6 @@ public void sendMessage(String message) { } - @Override - public void sendMessage(Message message) { - - } - @Override public boolean isConsole() { return true; diff --git a/common/src/test/java/me/confuser/banmanager/common/TestServer.java b/common/src/test/java/me/confuser/banmanager/common/TestServer.java index f90b27876..b8276661c 100644 --- a/common/src/test/java/me/confuser/banmanager/common/TestServer.java +++ b/common/src/test/java/me/confuser/banmanager/common/TestServer.java @@ -3,7 +3,7 @@ import me.confuser.banmanager.common.api.events.CommonEvent; import me.confuser.banmanager.common.commands.CommonSender; import me.confuser.banmanager.common.data.PlayerData; -import me.confuser.banmanager.common.kyori.text.TextComponent; +import me.confuser.banmanager.common.util.Message; import me.confuser.banmanager.common.util.UUIDUtils; import java.sql.SQLException; @@ -105,7 +105,7 @@ public void broadcast(String message, String permission) { } @Override - public void broadcastJSON(TextComponent message, String permission) { + public void broadcast(Message message, String permission) { } @Override diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/KickAllCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/KickAllCommandTest.java index 009c408ad..3922ebfe6 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/KickAllCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/KickAllCommandTest.java @@ -3,9 +3,12 @@ import me.confuser.banmanager.common.BasePluginDbTest; import me.confuser.banmanager.common.CommonPlayer; import me.confuser.banmanager.common.data.PlayerData; +import me.confuser.banmanager.common.util.Message; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentCaptor; +import static org.junit.Assert.*; import static org.mockito.Mockito.*; public class KickAllCommandTest extends BasePluginDbTest { @@ -46,7 +49,10 @@ public void shouldFailIfExempt() { assert (cmd.onCommand(sender, new CommandParser(plugin, args, 0))); verify(commonPlayer, never()).kick("&6You have been kicked"); - verify(server).broadcast("All players have been kicked by Console for &4test", "bm.notify.kick"); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Message.class); + verify(server).broadcast(msgCaptor.capture(), eq("bm.notify.kick")); + assertEquals("&6All players have been kicked by Console for &4test", msgCaptor.getValue().toString()); } @Test @@ -62,7 +68,10 @@ public void shouldKickPlayerWithoutAReason() { assert (cmd.onCommand(sender, new CommandParser(plugin, args, 0))); verify(commonPlayer).kick("&6You have been kicked"); - verify(server).broadcast("All players have been kicked by Console", "bm.notify.kick"); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Message.class); + verify(server).broadcast(msgCaptor.capture(), eq("bm.notify.kick")); + assertEquals("&6All players have been kicked by Console", msgCaptor.getValue().toString()); } @Test @@ -78,7 +87,10 @@ public void shouldKickPlayerWithAReason() { assert (cmd.onCommand(sender, new CommandParser(plugin, args, 0))); verify(commonPlayer).kick("&6You have been kicked for &4" + args[0]); - verify(server).broadcast("All players have been kicked by Console for &4" + args[0], "bm.notify.kick"); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Message.class); + verify(server).broadcast(msgCaptor.capture(), eq("bm.notify.kick")); + assertEquals("&6All players have been kicked by Console for &4" + args[0], msgCaptor.getValue().toString()); } @Test @@ -94,7 +106,7 @@ public void shouldKickPlayerWithoutAReasonSilently() { assert (cmd.onCommand(sender, new CommandParser(plugin, args, 0))); verify(commonPlayer).kick("&6You have been kicked"); - verify(server, never()).broadcast("All players have been kicked by Console", "bm.notify.kick"); + verify(server, never()).broadcast(any(Message.class), eq("bm.notify.kick")); } @Test @@ -110,6 +122,6 @@ public void shouldKickPlayerWithAReasonSilently() { assert (cmd.onCommand(sender, new CommandParser(plugin, args, 0))); verify(commonPlayer).kick("&6You have been kicked for &4test reason"); - verify(server, never()).broadcast("All players have been kicked by Console for &4test reason", "bm.notify.kick"); + verify(server, never()).broadcast(any(Message.class), eq("bm.notify.kick")); } } diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/KickCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/KickCommandTest.java index 31c415ec6..d1222145b 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/KickCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/KickCommandTest.java @@ -3,8 +3,10 @@ import me.confuser.banmanager.common.BasePluginDbTest; import me.confuser.banmanager.common.CommonPlayer; import me.confuser.banmanager.common.data.PlayerData; +import me.confuser.banmanager.common.util.Message; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentCaptor; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @@ -87,7 +89,10 @@ public void shouldKickPlayerWithoutAReason() { assert (cmd.onCommand(sender, new CommandParser(plugin, args))); verify(commonPlayer).kick("&6You have been kicked"); - verify(server).broadcast("&6" + args[0] + " has been kicked by Console", "bm.notify.kick"); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Message.class); + verify(server).broadcast(msgCaptor.capture(), eq("bm.notify.kick")); + assertEquals("&6" + args[0] + " has been kicked by Console &3[Info]", msgCaptor.getValue().toString()); } @Test @@ -103,7 +108,10 @@ public void shouldKickPlayerWithAReason() { assert (cmd.onCommand(sender, new CommandParser(plugin, args))); verify(commonPlayer).kick("&6You have been kicked for &4" + args[1]); - verify(server).broadcast("&6" + args[0] + " has been kicked by Console for &4" + args[1], "bm.notify.kick"); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Message.class); + verify(server).broadcast(msgCaptor.capture(), eq("bm.notify.kick")); + assertEquals("&6" + args[0] + " has been kicked by Console for &4" + args[1] + " &3[Info]", msgCaptor.getValue().toString()); } @Test @@ -119,7 +127,7 @@ public void shouldKickPlayerWithoutAReasonSilently() { assert (cmd.onCommand(sender, new CommandParser(plugin, args))); verify(commonPlayer).kick("&6You have been kicked"); - verify(server, never()).broadcast("&6" + args[0] + " has been kicked by Console", "bm.notify.kick"); + verify(server, never()).broadcast(any(Message.class), eq("bm.notify.kick")); } @Test @@ -135,6 +143,6 @@ public void shouldKickPlayerWithAReasonSilently() { assert (cmd.onCommand(sender, new CommandParser(plugin, args))); verify(commonPlayer).kick("&6You have been kicked for &4test reason"); - verify(server, never()).broadcast("&6" + args[0] + " has been kicked by Console for &4test reason", "bm.notify.kick"); + verify(server, never()).broadcast(any(Message.class), eq("bm.notify.kick")); } } diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/LoglessKickAllCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/LoglessKickAllCommandTest.java index 0fc23f900..12bc88f54 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/LoglessKickAllCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/LoglessKickAllCommandTest.java @@ -3,9 +3,12 @@ import me.confuser.banmanager.common.BasePluginDbTest; import me.confuser.banmanager.common.CommonPlayer; import me.confuser.banmanager.common.data.PlayerData; +import me.confuser.banmanager.common.util.Message; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentCaptor; +import static org.junit.Assert.*; import static org.mockito.Mockito.*; public class LoglessKickAllCommandTest extends BasePluginDbTest { @@ -46,7 +49,10 @@ public void shouldFailIfExempt() { assert (cmd.onCommand(sender, new CommandParser(plugin, args, 0))); verify(commonPlayer, never()).kick("&6You have been kicked"); - verify(server).broadcast("All players have been kicked by Console for &4test", "bm.notify.kick"); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Message.class); + verify(server).broadcast(msgCaptor.capture(), eq("bm.notify.kick")); + assertEquals("&6All players have been kicked by Console for &4test", msgCaptor.getValue().toString()); } @Test @@ -62,7 +68,10 @@ public void shouldKickPlayerWithoutAReason() { assert (cmd.onCommand(sender, new CommandParser(plugin, args, 0))); verify(commonPlayer).kick("&6You have been kicked"); - verify(server).broadcast("All players have been kicked by Console", "bm.notify.kick"); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Message.class); + verify(server).broadcast(msgCaptor.capture(), eq("bm.notify.kick")); + assertEquals("&6All players have been kicked by Console", msgCaptor.getValue().toString()); } @Test @@ -78,7 +87,10 @@ public void shouldKickPlayerWithAReason() { assert (cmd.onCommand(sender, new CommandParser(plugin, args, 0))); verify(commonPlayer).kick("&6You have been kicked for &4" + args[0]); - verify(server).broadcast("All players have been kicked by Console for &4" + args[0], "bm.notify.kick"); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Message.class); + verify(server).broadcast(msgCaptor.capture(), eq("bm.notify.kick")); + assertEquals("&6All players have been kicked by Console for &4" + args[0], msgCaptor.getValue().toString()); } @Test @@ -94,7 +106,7 @@ public void shouldKickPlayerWithoutAReasonSilently() { assert (cmd.onCommand(sender, new CommandParser(plugin, args, 0))); verify(commonPlayer).kick("&6You have been kicked"); - verify(server, never()).broadcast("All players have been kicked by Console", "bm.notify.kick"); + verify(server, never()).broadcast(any(Message.class), eq("bm.notify.kick")); } @Test @@ -110,6 +122,6 @@ public void shouldKickPlayerWithAReasonSilently() { assert (cmd.onCommand(sender, new CommandParser(plugin, args, 0))); verify(commonPlayer).kick("&6You have been kicked for &4test reason"); - verify(server, never()).broadcast("All players have been kicked by Console for &4test reason", "bm.notify.kick"); + verify(server, never()).broadcast(any(Message.class), eq("bm.notify.kick")); } } diff --git a/common/src/test/java/me/confuser/banmanager/common/configs/ConfigReloadTest.java b/common/src/test/java/me/confuser/banmanager/common/configs/ConfigReloadTest.java index a517027d7..040092529 100644 --- a/common/src/test/java/me/confuser/banmanager/common/configs/ConfigReloadTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/configs/ConfigReloadTest.java @@ -97,20 +97,17 @@ public void setupConfigsReplacesConfigOnSuccessfulReload() throws IOException { @Test public void messagesArePreservedWhenConfigFails() throws IOException { - // Get a message that should exist String originalMessage = Message.getString("configReloaded"); assertNotNull("configReloaded message should exist", originalMessage); - // Corrupt the messages.yml file - File messagesFile = new File(temporaryFolder.getRoot(), "messages.yml"); - try (FileWriter writer = new FileWriter(messagesFile)) { + // Corrupt the messages/messages_en.yml so reload yields no usable messages + File messagesEnFile = new File(temporaryFolder.getRoot(), "messages/messages_en.yml"); + try (FileWriter writer = new FileWriter(messagesEnFile)) { writer.write("invalid: yaml: [unclosed"); } - // Reload configs plugin.setupConfigs(); - // Messages should still be available String afterReloadMessage = Message.getString("configReloaded"); assertEquals("Messages should be preserved after failed reload", originalMessage, afterReloadMessage); } @@ -121,8 +118,8 @@ public void messagesAreUpdatedOnSuccessfulReload() throws IOException { String originalMessage = Message.getString("configReloaded"); assertNotNull("configReloaded message should exist", originalMessage); - // Modify the messages.yml file with a new message value - File messagesFile = new File(temporaryFolder.getRoot(), "messages.yml"); + // Modify the messages/messages_en.yml file with a new message value + File messagesFile = new File(temporaryFolder.getRoot(), "messages/messages_en.yml"); try (FileWriter writer = new FileWriter(messagesFile)) { writer.write("messages:\n"); writer.write(" configReloaded: \"New reload message\"\n"); diff --git a/common/src/test/java/me/confuser/banmanager/common/configs/MessagesConfigTest.java b/common/src/test/java/me/confuser/banmanager/common/configs/MessagesConfigTest.java deleted file mode 100644 index 283cbf5e8..000000000 --- a/common/src/test/java/me/confuser/banmanager/common/configs/MessagesConfigTest.java +++ /dev/null @@ -1,69 +0,0 @@ -package me.confuser.banmanager.common.configs; - -import me.confuser.banmanager.common.BasePluginTest; -import me.confuser.banmanager.common.TestLogger; -import me.confuser.banmanager.common.configuration.file.YamlConfiguration; -import me.confuser.banmanager.common.util.Message; -import org.junit.Test; - -import java.io.StringReader; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; - -public class MessagesConfigTest extends BasePluginTest { - - @Test - public void isValid() { - // @TODO test tokens for all messages - assertEquals("&6Currently banned for &4abc&6 by def at 8th July which expires in 1d", Message - .get("info.ban.temporary").set("reason", "abc").set("actor", "def").set("created", - "8th July").set("expires", "1d").toString()); - } - - @Test - public void doubleNewlineProducesNonEmptyLine() { - String yaml = "messages:\n test:\n greeting: 'Hello\\n\\nWorld'"; - YamlConfiguration config = YamlConfiguration.loadConfiguration(new StringReader(yaml)); - Message.load(config, new TestLogger()); - - String result = Message.get("test.greeting").toString(); - - assertEquals("Hello\n \nWorld", result); - } - - @Test - public void tripleNewlineProducesNonEmptyLines() { - String yaml = "messages:\n test:\n greeting: 'Hello\\n\\n\\nWorld'"; - YamlConfiguration config = YamlConfiguration.loadConfiguration(new StringReader(yaml)); - Message.load(config, new TestLogger()); - - String result = Message.get("test.greeting").toString(); - - assertEquals("Hello\n \n \nWorld", result); - } - - @Test - public void singleNewlineIsUnchanged() { - String yaml = "messages:\n test:\n greeting: 'Hello\\nWorld'"; - YamlConfiguration config = YamlConfiguration.loadConfiguration(new StringReader(yaml)); - Message.load(config, new TestLogger()); - - String result = Message.get("test.greeting").toString(); - - assertEquals("Hello\nWorld", result); - } - - @Test - public void noConsecutiveEmptyLinesInLoadedMessages() { - String yaml = "messages:\n test:\n msg: 'Line1\\n\\nLine2\\n\\n\\nLine3'"; - YamlConfiguration config = YamlConfiguration.loadConfiguration(new StringReader(yaml)); - Message.load(config, new TestLogger()); - - String result = Message.get("test.msg").toString(); - - for (String line : result.split("\n", -1)) { - assertFalse("Empty lines should contain a space for chat rendering", line.isEmpty()); - } - } -} diff --git a/common/src/test/java/me/confuser/banmanager/common/configs/NotificationsConfigTest.java b/common/src/test/java/me/confuser/banmanager/common/configs/NotificationsConfigTest.java new file mode 100644 index 000000000..171eac588 --- /dev/null +++ b/common/src/test/java/me/confuser/banmanager/common/configs/NotificationsConfigTest.java @@ -0,0 +1,43 @@ +package me.confuser.banmanager.common.configs; + +import me.confuser.banmanager.common.BasePluginTest; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class NotificationsConfigTest extends BasePluginTest { + + @Test + public void loadsStaffChannels() { + NotificationsConfig config = plugin.getNotificationsConfig(); + assertNotNull(config); + assertFalse(config.getStaffChannels().isEmpty()); + } + + @Test + public void banChannelHasChat() { + NotificationsConfig.NotificationChannel channel = plugin.getNotificationsConfig().getStaffChannel("ban"); + assertTrue(channel.isChat()); + } + + @Test + public void banChannelHasSound() { + NotificationsConfig.NotificationChannel channel = plugin.getNotificationsConfig().getStaffChannel("ban"); + assertTrue(channel.hasSound()); + assertEquals("entity.experience_orb.pickup", channel.getSound()); + } + + @Test + public void unknownEventReturnsChatOnly() { + NotificationsConfig.NotificationChannel channel = plugin.getNotificationsConfig().getStaffChannel("nonexistent"); + assertTrue(channel.isChat()); + assertFalse(channel.isActionbar()); + assertFalse(channel.isTitle()); + assertFalse(channel.hasSound()); + } + + @Test + public void mutedActionBarDefaults() { + assertTrue(plugin.getNotificationsConfig().isMutedActionBar()); + } +} diff --git a/common/src/test/java/me/confuser/banmanager/common/listeners/CommonJoinListenerTest.java b/common/src/test/java/me/confuser/banmanager/common/listeners/CommonJoinListenerTest.java index ab22bbe51..cd6f9d8c6 100644 --- a/common/src/test/java/me/confuser/banmanager/common/listeners/CommonJoinListenerTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/listeners/CommonJoinListenerTest.java @@ -295,9 +295,6 @@ public void kick(String message) {} @Override public void sendMessage(String message) {} - @Override - public void sendMessage(Message message) {} - @Override public void sendJSONMessage(me.confuser.banmanager.common.kyori.text.TextComponent jsonString) {} @@ -349,6 +346,9 @@ public boolean teleport(CommonWorld world, double x, double y, double z, float p @Override public boolean canSee(CommonPlayer player) { return true; } + + @Override + public String getLocale() { return "en"; } }; } } diff --git a/common/src/test/java/me/confuser/banmanager/common/listeners/NoteListenerTest.java b/common/src/test/java/me/confuser/banmanager/common/listeners/NoteListenerTest.java index 2007faa01..7f03dee52 100755 --- a/common/src/test/java/me/confuser/banmanager/common/listeners/NoteListenerTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/listeners/NoteListenerTest.java @@ -6,7 +6,9 @@ import me.confuser.banmanager.common.data.PlayerNoteData; import me.confuser.banmanager.common.util.Message; import org.junit.Test; +import org.mockito.ArgumentCaptor; +import static org.junit.Assert.*; import static org.mockito.Mockito.*; public class NoteListenerTest extends BasePluginDbTest { @@ -18,9 +20,9 @@ public void shouldBroadcast() { CommonSender sender = plugin.getServer().getConsoleSender(); PlayerNoteData data = new PlayerNoteData(player, sender.getData(), "test"); CommonPlayer testPlayer = spy(new TestPlayer(sender.getData().getUUID(), sender.getName(), false)); - Message message = Message.get("notes.notify"); + Message expected = Message.get("notes.notify"); - message.set("player", data.getPlayer().getName()) + expected.set("player", data.getPlayer().getName()) .set("playerId", data.getPlayer().getUUID().toString()) .set("actor", data.getActor().getName()) .set("message", data.getMessage()); @@ -32,7 +34,12 @@ public void shouldBroadcast() { CommonNoteListener listener = new CommonNoteListener(plugin); listener.notifyOnNote(data); - verify(server).broadcast(message.toString(), "bm.notify.notes"); - verify(testPlayer).sendMessage(message); + ArgumentCaptor broadcastCaptor = ArgumentCaptor.forClass(Message.class); + verify(server).broadcast(broadcastCaptor.capture(), eq("bm.notify.notes")); + assertEquals(expected.toString(), broadcastCaptor.getValue().toString()); + + ArgumentCaptor playerCaptor = ArgumentCaptor.forClass(Message.class); + verify(testPlayer).sendMessage(playerCaptor.capture()); + assertEquals(expected.toString(), playerCaptor.getValue().toString()); } } diff --git a/common/src/test/java/me/confuser/banmanager/common/storage/PlayerStorageTest.java b/common/src/test/java/me/confuser/banmanager/common/storage/PlayerStorageTest.java index 6b72639c4..350fc450f 100644 --- a/common/src/test/java/me/confuser/banmanager/common/storage/PlayerStorageTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/storage/PlayerStorageTest.java @@ -40,6 +40,51 @@ public void shouldUpsertPlayerData() throws SQLException { assertNotNull(playerStorage.getAutoCompleteTree().getValueForExactKey("Name 2")); } + @Test + public void shouldPersistLocale() throws SQLException { + PlayerStorage playerStorage = plugin.getPlayerStorage(); + + UUID uuid = UUID.randomUUID(); + PlayerData data = new PlayerData(uuid, "LocalePlayer"); + data.setLocale("de"); + + playerStorage.upsert(data); + + PlayerData retrieved = playerStorage.retrieve("LocalePlayer", false); + assertNotNull(retrieved); + assertEquals("de", retrieved.getLocale()); + } + + @Test + public void shouldUpdateLocale() throws SQLException { + PlayerStorage playerStorage = plugin.getPlayerStorage(); + + UUID uuid = UUID.randomUUID(); + PlayerData data = new PlayerData(uuid, "LocaleUpdate"); + data.setLocale("en"); + playerStorage.upsert(data); + + data.setLocale("fr"); + playerStorage.upsert(data); + + PlayerData retrieved = playerStorage.retrieve("LocaleUpdate", false); + assertNotNull(retrieved); + assertEquals("fr", retrieved.getLocale()); + } + + @Test + public void shouldHandleNullLocale() throws SQLException { + PlayerStorage playerStorage = plugin.getPlayerStorage(); + + UUID uuid = UUID.randomUUID(); + PlayerData data = new PlayerData(uuid, "NullLocale"); + playerStorage.upsert(data); + + PlayerData retrieved = playerStorage.retrieve("NullLocale", false); + assertNotNull(retrieved); + assertNull(retrieved.getLocale()); + } + @Test public void shouldRetrievePlayerData() throws SQLException { PlayerStorage playerStorage = plugin.getPlayerStorage(); diff --git a/common/src/test/java/me/confuser/banmanager/common/storage/migration/MigrationIntegrationTest.java b/common/src/test/java/me/confuser/banmanager/common/storage/migration/MigrationIntegrationTest.java index 62aa4729e..466deb1b5 100644 --- a/common/src/test/java/me/confuser/banmanager/common/storage/migration/MigrationIntegrationTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/storage/migration/MigrationIntegrationTest.java @@ -50,7 +50,7 @@ public void freshInstall_marksLatestVersion() throws Exception { for (SchemaVersion sv : versions) { if ("local".equals(sv.getScope())) { hasLocal = true; - assertEquals("Fresh install should mark at latest version", 1, sv.getVersion()); + assertEquals("Fresh install should mark at latest version", 2, sv.getVersion()); assertTrue("Description should indicate fresh install", sv.getDescription().contains("fresh install")); } } diff --git a/common/src/test/java/me/confuser/banmanager/common/util/LocaleNormalisationTest.java b/common/src/test/java/me/confuser/banmanager/common/util/LocaleNormalisationTest.java new file mode 100644 index 000000000..e88a7a93f --- /dev/null +++ b/common/src/test/java/me/confuser/banmanager/common/util/LocaleNormalisationTest.java @@ -0,0 +1,48 @@ +package me.confuser.banmanager.common.util; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class LocaleNormalisationTest { + + @Test + public void enGBBecomesEnGb() { + assertEquals("en_gb", MessageRegistry.normaliseLocale("en_GB")); + } + + @Test + public void zhTWBecomesZhTw() { + assertEquals("zh_tw", MessageRegistry.normaliseLocale("zh-TW")); + } + + @Test + public void uppercaseBecomesLowercase() { + assertEquals("en", MessageRegistry.normaliseLocale("EN")); + } + + @Test + public void ptBRBecomesPtBr() { + assertEquals("pt_br", MessageRegistry.normaliseLocale("pt_BR")); + } + + @Test + public void hyphenIsReplacedWithUnderscore() { + assertEquals("en_gb", MessageRegistry.normaliseLocale("en-gb")); + } + + @Test + public void alreadyNormalisedIsUnchanged() { + assertEquals("en", MessageRegistry.normaliseLocale("en")); + } + + @Test + public void nullReturnsEn() { + assertEquals("en", MessageRegistry.normaliseLocale(null)); + } + + @Test + public void emptyStringReturnsEn() { + assertEquals("en", MessageRegistry.normaliseLocale("")); + } +} diff --git a/common/src/test/java/me/confuser/banmanager/common/util/MessageDeferredTest.java b/common/src/test/java/me/confuser/banmanager/common/util/MessageDeferredTest.java new file mode 100644 index 000000000..39152fa04 --- /dev/null +++ b/common/src/test/java/me/confuser/banmanager/common/util/MessageDeferredTest.java @@ -0,0 +1,130 @@ +package me.confuser.banmanager.common.util; + +import me.confuser.banmanager.common.TestLogger; +import me.confuser.banmanager.common.TestPlayer; +import me.confuser.banmanager.common.kyori.text.Component; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import static org.junit.Assert.*; + +public class MessageDeferredTest { + + @Before + public void setUp() { + MessageRegistry registry = new MessageRegistry("en"); + + Map en = new HashMap<>(); + en.put("ban.kick", "You are banned by for "); + en.put("greeting", "Hello "); + registry.loadLocale("en", en); + + Map de = new HashMap<>(); + de.put("ban.kick", "Du wurdest von gebannt: "); + de.put("greeting", "Hallo "); + registry.loadLocale("de", de); + + Message.init(registry, new TestLogger()); + } + + @Test + public void resolveWithDefaultLocale() { + Component component = Message.get("ban.kick") + .set("actor", "Admin") + .set("reason", "griefing") + .resolveComponent("en"); + + String plain = MessageRenderer.getInstance().toPlainText(component); + assertEquals("You are banned by Admin for griefing", plain); + } + + @Test + public void resolveWithSpecificLocale() { + Component component = Message.get("ban.kick") + .set("actor", "Admin") + .set("reason", "griefing") + .resolveComponent("de"); + + String plain = MessageRenderer.getInstance().toPlainText(component); + assertEquals("Du wurdest von Admin gebannt: griefing", plain); + } + + @Test + public void toStringUsesDefaultLocale() { + Component component = Message.get("greeting") + .set("player", "Steve") + .resolveComponent(); + + String plain = MessageRenderer.getInstance().toPlainText(component); + assertEquals("Hello Steve", plain); + } + + @Test + public void resolveWithPlayerLocale() { + TestPlayer player = new TestPlayer(UUID.randomUUID(), "Steve", true, "de"); + Component component = Message.get("greeting") + .set("player", "Steve") + .resolveComponent(player.getLocale()); + + String plain = MessageRenderer.getInstance().toPlainText(component); + assertEquals("Hallo Steve", plain); + } + + @Test + public void resolveForFallsBackWithoutPlugin() { + TestPlayer player = new TestPlayer(UUID.randomUUID(), "Steve", true, "de"); + Component component = Message.get("greeting") + .set("player", "Steve") + .resolveComponentFor(player); + + String plain = MessageRenderer.getInstance().toPlainText(component); + assertEquals("Hello Steve", plain); + } + + @Test + public void tokenReplacementOrderPreserved() { + MessageRegistry registry = new MessageRegistry("en"); + Map en = new HashMap<>(); + en.put("test.order", " "); + registry.loadLocale("en", en); + Message.init(registry, new TestLogger()); + + Component component = Message.get("test.order") + .set("first", "X") + .set("second", "Y") + .resolveComponent(); + + String plain = MessageRenderer.getInstance().toPlainText(component); + assertEquals("X Y X", plain); + } + + @Test + public void missingKeyReturnsEmptyString() { + String result = Message.get("nonexistent.key").toString(); + assertEquals("", result); + } + + @Test + public void dynamicRegistrationWritesToDefaultLocale() { + new Message("custom.key", "Custom message"); + + String result = Message.getString("custom.key"); + assertNotNull("Dynamic registration should produce a non-null result", result); + assertEquals("Custom message", result); + } + + @Test + public void replaceMethodWorks() { + Component component = Message.get("greeting") + .set("player", "Steve") + .replace("Hello", "Hey") + .resolveComponent(); + + String plain = MessageRenderer.getInstance().toPlainText(component); + assertEquals("Hey Steve", plain); + } +} diff --git a/common/src/test/java/me/confuser/banmanager/common/util/MessageLoadingTest.java b/common/src/test/java/me/confuser/banmanager/common/util/MessageLoadingTest.java new file mode 100644 index 000000000..e2a2a96a0 --- /dev/null +++ b/common/src/test/java/me/confuser/banmanager/common/util/MessageLoadingTest.java @@ -0,0 +1,73 @@ +package me.confuser.banmanager.common.util; + +import me.confuser.banmanager.common.BasePluginTest; +import me.confuser.banmanager.common.TestLogger; +import me.confuser.banmanager.common.configuration.file.YamlConfiguration; +import me.confuser.banmanager.common.kyori.text.Component; +import org.junit.Test; + +import java.io.StringReader; + +import static org.junit.Assert.*; + + +public class MessageLoadingTest extends BasePluginTest { + + @Test + public void isValid() { + Component component = Message.get("info.ban.temporary") + .set("reason", "abc") + .set("actor", "def") + .set("created", "8th July") + .set("expires", "1d") + .resolveComponent(); + + String plain = MessageRenderer.getInstance().toPlainText(component); + assertEquals("Currently banned for abc by def at 8th July which expires in 1d", plain); + } + + private void loadTestMessages(String yaml) { + YamlConfiguration config = YamlConfiguration.loadConfiguration(new StringReader(yaml)); + MessageRegistry registry = new MessageRegistry("en"); + + for (String key : config.getConfigurationSection("messages").getKeys(true)) { + String value = config.getString("messages." + key); + if (value != null) { + registry.putMessage(key, value.replace("\\n", "\n").replaceAll("(?<=\\n)(?=\\n)", " ")); + } + } + + Message.init(registry, new TestLogger()); + } + + @Test + public void doubleNewlineProducesNonEmptyLine() { + loadTestMessages("messages:\n test:\n greeting: 'Hello\\n\\nWorld'"); + String result = Message.get("test.greeting").toString(); + assertEquals("Hello\n \nWorld", result); + } + + @Test + public void tripleNewlineProducesNonEmptyLines() { + loadTestMessages("messages:\n test:\n greeting: 'Hello\\n\\n\\nWorld'"); + String result = Message.get("test.greeting").toString(); + assertEquals("Hello\n \n \nWorld", result); + } + + @Test + public void singleNewlineIsUnchanged() { + loadTestMessages("messages:\n test:\n greeting: 'Hello\\nWorld'"); + String result = Message.get("test.greeting").toString(); + assertEquals("Hello\nWorld", result); + } + + @Test + public void noConsecutiveEmptyLinesInLoadedMessages() { + loadTestMessages("messages:\n test:\n msg: 'Line1\\n\\nLine2\\n\\n\\nLine3'"); + String result = Message.get("test.msg").toString(); + + for (String line : result.split("\n", -1)) { + assertFalse("Empty lines should contain a space for chat rendering", line.isEmpty()); + } + } +} diff --git a/common/src/test/java/me/confuser/banmanager/common/util/MessageRegistryTest.java b/common/src/test/java/me/confuser/banmanager/common/util/MessageRegistryTest.java new file mode 100644 index 000000000..80a123c00 --- /dev/null +++ b/common/src/test/java/me/confuser/banmanager/common/util/MessageRegistryTest.java @@ -0,0 +1,135 @@ +package me.confuser.banmanager.common.util; + +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.*; + +public class MessageRegistryTest { + + private MessageRegistry registry; + + @Before + public void setUp() { + registry = new MessageRegistry("en"); + + Map en = new HashMap<>(); + en.put("greeting", "Hello"); + en.put("farewell", "Goodbye"); + en.put("only.in.english", "English only"); + registry.loadLocale("en", en); + + Map zh = new HashMap<>(); + zh.put("greeting", "你好"); + zh.put("farewell", "再见"); + registry.loadLocale("zh", zh); + + Map zhTw = new HashMap<>(); + zhTw.put("greeting", "你好 (繁體)"); + registry.loadLocale("zh_tw", zhTw); + } + + @Test + public void cascadingFallbackExactLocale() { + assertEquals("你好 (繁體)", registry.getMessage("greeting", "zh_tw")); + } + + @Test + public void cascadingFallbackToBaseLanguage() { + assertEquals("再见", registry.getMessage("farewell", "zh_tw")); + } + + @Test + public void cascadingFallbackToDefault() { + assertEquals("English only", registry.getMessage("only.in.english", "zh_tw")); + } + + @Test + public void missingKeyFallbackToDefault() { + assertEquals("English only", registry.getMessage("only.in.english", "de")); + } + + @Test + public void unknownLocaleReturnsDefault() { + assertEquals("Hello", registry.getMessage("greeting", "fr")); + } + + @Test + public void defaultLocaleReturnsDirectly() { + assertEquals("Hello", registry.getMessage("greeting")); + } + + @Test + public void missingKeyReturnsNull() { + assertNull(registry.getMessage("nonexistent", "en")); + } + + @Test + public void availableLocales() { + Set locales = registry.getAvailableLocales(); + assertTrue(locales.contains("en")); + assertTrue(locales.contains("zh")); + assertTrue(locales.contains("zh_tw")); + assertEquals(3, locales.size()); + } + + @Test + public void missingKeyCount() { + assertEquals(1, registry.getMissingKeyCount("zh")); + assertEquals(2, registry.getMissingKeyCount("zh_tw")); + assertEquals(0, registry.getMissingKeyCount("en")); + } + + @Test + public void atomicSwapReplacesContent() { + MessageRegistry newRegistry = new MessageRegistry("de"); + Map de = new HashMap<>(); + de.put("greeting", "Hallo"); + newRegistry.loadLocale("de", de); + + registry.atomicSwap(newRegistry); + + assertEquals("de", registry.getDefaultLocale()); + assertEquals("Hallo", registry.getMessage("greeting")); + assertNull(registry.getMessage("farewell")); + } + + @Test + public void putMessageUpdatesExistingLocale() { + registry.putMessage("greeting", "Hi", "en"); + assertEquals("Hi", registry.getMessage("greeting", "en")); + } + + @Test + public void putMessageCreatesNewLocale() { + registry.putMessage("greeting", "Bonjour", "fr"); + assertEquals("Bonjour", registry.getMessage("greeting", "fr")); + assertTrue(registry.getAvailableLocales().contains("fr")); + } + + @Test + public void hasAnyMessagesReturnsTrueWhenLoaded() { + assertTrue(registry.hasAnyMessages()); + } + + @Test + public void hasAnyMessagesReturnsFalseWhenEmpty() { + MessageRegistry empty = new MessageRegistry("en"); + assertFalse(empty.hasAnyMessages()); + } + + @Test + public void defaultLocaleMismatchStillResolvesViaFallback() { + MessageRegistry reg = new MessageRegistry("en_us"); + Map en = new HashMap<>(); + en.put("test", "Hello"); + reg.loadLocale("en", en); + + assertEquals("Hello", reg.getMessage("test", "en_us")); + assertTrue(reg.hasAnyMessages()); + } +} diff --git a/common/src/test/java/me/confuser/banmanager/common/util/MessageRendererTest.java b/common/src/test/java/me/confuser/banmanager/common/util/MessageRendererTest.java new file mode 100644 index 000000000..c2d20aa2b --- /dev/null +++ b/common/src/test/java/me/confuser/banmanager/common/util/MessageRendererTest.java @@ -0,0 +1,118 @@ +package me.confuser.banmanager.common.util; + +import me.confuser.banmanager.common.kyori.text.Component; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.*; + +public class MessageRendererTest { + + private MessageRenderer renderer; + + @Before + public void setUp() { + renderer = MessageRenderer.getInstance(); + } + + @After + public void tearDown() { + renderer.loadStaticTokens(new HashMap<>()); + } + + @Test + public void renderPlainText() { + Component result = renderer.render("Hello world"); + String plain = renderer.toPlainText(result); + assertEquals("Hello world", plain); + } + + @Test + public void renderWithPlaceholders() { + Map placeholders = new HashMap<>(); + placeholders.put("player", "Steve"); + Component result = renderer.render(" joined", placeholders); + String plain = renderer.toPlainText(result); + assertEquals("Steve joined", plain); + } + + @Test + public void renderMiniMessageFormatting() { + Component result = renderer.render("Error: Something went wrong"); + String plain = renderer.toPlainText(result); + assertEquals("Error: Something went wrong", plain); + } + + @Test + public void toLegacyPreservesColors() { + Component result = renderer.render("Red text"); + String legacy = renderer.toLegacy(result); + assertTrue(legacy.contains("Red text")); + } + + @Test + public void toJsonProducesValidJson() { + Component result = renderer.render("Success"); + String json = renderer.toJson(result); + assertTrue(json.startsWith("{") || json.startsWith("[")); + assertTrue(json.contains("Success")); + } + + @Test + public void isLegacyFormatDetectsAmpersandCodes() { + assertTrue(renderer.isLegacyFormat("&cHello &eworld")); + assertFalse(renderer.isLegacyFormat("Hello world")); + assertFalse(renderer.isLegacyFormat("Plain text")); + } + + @Test + public void convertLegacyToMiniMessage() { + String result = renderer.convertLegacyToMiniMessage("&cRed &lbold &agreen"); + assertFalse(result.contains("&c")); + assertFalse(result.contains("&l")); + assertFalse(result.contains("&a")); + } + + @Test + public void staticTokensAreResolved() { + Map tokens = new HashMap<>(); + tokens.put("server_name", "TestServer"); + renderer.loadStaticTokens(tokens); + + Component result = renderer.render("Welcome to !"); + String plain = renderer.toPlainText(result); + assertEquals("Welcome to TestServer!", plain); + } + + @Test + public void camelCaseTokensAreNormalised() { + Map tokens = new HashMap<>(); + tokens.put("serverName", "TestServer"); + renderer.loadStaticTokens(tokens); + + Component result = renderer.render("Welcome to !"); + String plain = renderer.toPlainText(result); + assertEquals("Welcome to TestServer!", plain); + } + + @Test + public void legacyConvertedExplicitlyThenRenders() { + String mini = renderer.convertLegacyToMiniMessage("&cThis is legacy"); + Component result = renderer.render(mini); + String plain = renderer.toPlainText(result); + assertEquals("This is legacy", plain); + } + + @Test + public void escapeTagsPreventsInjection() { + String malicious = "injected"; + String escaped = renderer.escapeTags(malicious); + Component result = renderer.render("" + escaped); + String plain = renderer.toPlainText(result); + assertTrue("Escaped tags should render as literal text", plain.contains("injected")); + } +} diff --git a/common/src/test/java/me/confuser/banmanager/common/util/MessagesYamlValidatorTest.java b/common/src/test/java/me/confuser/banmanager/common/util/MessagesYamlValidatorTest.java new file mode 100644 index 000000000..2182c1288 --- /dev/null +++ b/common/src/test/java/me/confuser/banmanager/common/util/MessagesYamlValidatorTest.java @@ -0,0 +1,320 @@ +package me.confuser.banmanager.common.util; + +import me.confuser.banmanager.common.configuration.ConfigurationSection; +import me.confuser.banmanager.common.configuration.file.YamlConfiguration; +import me.confuser.banmanager.common.kyori.text.Component; +import me.confuser.banmanager.common.kyori.text.minimessage.tag.resolver.Placeholder; +import me.confuser.banmanager.common.kyori.text.minimessage.tag.resolver.TagResolver; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Validates that every message in the bundled messages_en.yml parses cleanly through MiniMessage. + * Catches malformed tags, unknown tag usage, mismatched closing tags, and other translation bugs. + */ +public class MessagesYamlValidatorTest { + + private static final String MESSAGES_RESOURCE = "messages/messages_en.yml"; + + private static final Set KNOWN_DYNAMIC_TOKENS = new HashSet<>(Arrays.asList( + "player", "name", "actor", "ip", "ip_address", "reason", "created", "expires", "remaining", + "id", "uuid", "command", "comment", "message", "world", "x", "y", "z", "from", "to", + "from_ip", "to_ip", "first_seen", "last_seen", "country", "city", "join", "leave", + "type", "types", "rows", "amount", "size", "index", "page", "max_page", "count", + "bans", "mutes", "kicks", "warns", "warn_points", "notes", "reports", "rangebans", + "players", "file", "meta", "state", "hashtag", "appeal_url" + )); + + private static final Set KNOWN_STATIC_TOKENS = new HashSet<>(Arrays.asList( + "appeal_url", "server_name", "discord_url", "rules_url" + )); + + private MessageRenderer renderer; + private List errors; + + @Before + public void setUp() { + MessageRenderer.reset(); + renderer = MessageRenderer.getInstance(); + Map staticTokens = new HashMap<>(); + for (String token : KNOWN_STATIC_TOKENS) { + staticTokens.put(token, "test_" + token); + } + renderer.loadStaticTokens(staticTokens); + errors = new ArrayList<>(); + } + + @After + public void tearDown() { + renderer.loadStaticTokens(new HashMap<>()); + MessageRenderer.reset(); + } + + @Test + public void everyMessageParsesWithoutError() throws Exception { + YamlConfiguration conf = loadBundledMessages(); + ConfigurationSection messages = conf.getConfigurationSection("messages"); + assertNotNull("messages section missing", messages); + + TagResolver.Builder resolverBuilder = TagResolver.builder(); + for (String token : KNOWN_DYNAMIC_TOKENS) { + resolverBuilder.resolver(Placeholder.unparsed(token, "test_" + token)); + } + TagResolver dynamicResolver = resolverBuilder.build(); + + int parsed = 0; + for (String key : messages.getKeys(true)) { + String value = messages.getString(key); + if (value == null) continue; + String processed = value.replace("\\n", "\n").replaceAll("(?<=\\n)(?=\\n)", " "); + + if (renderer.isLegacyFormat(processed)) { + errors.add("messages." + key + ": legacy &-code formatting detected"); + continue; + } + + try { + Component component = renderer.render(processed, dynamicResolver); + String plain = renderer.toPlainText(component); + if (plain == null) { + errors.add("messages." + key + ": render produced null plain text"); + } + parsed++; + } catch (Exception e) { + errors.add("messages." + key + ": failed to render — " + e.getMessage() + + " | template: " + processed); + } + } + + if (!errors.isEmpty()) { + fail("Found " + errors.size() + " message issue(s):\n" + String.join("\n", errors)); + } + assertTrue("Expected to parse at least 1 message", parsed > 0); + } + + @Test + public void noUnknownTagsInMessages() throws Exception { + YamlConfiguration conf = loadBundledMessages(); + ConfigurationSection messages = conf.getConfigurationSection("messages"); + + Set standardMiniMessageTags = new HashSet<>(Arrays.asList( + // Color tags + "black", "dark_blue", "dark_green", "dark_aqua", "dark_red", "dark_purple", + "gold", "gray", "dark_gray", "blue", "green", "aqua", "red", "light_purple", + "yellow", "white", "color", "colour", "c", + // Decoration tags (and shorthand) + "bold", "b", "italic", "i", "em", "underlined", "u", "strikethrough", "st", + "obfuscated", "obf", + // Formatting tags + "reset", "newline", "br", "rainbow", "gradient", "transition", + // Interaction tags + "click", "hover", "insertion", "selector", "sel", + // Misc + "key", "translatable", "tr", "lang", "score", "nbt", "font", + // Pre-tag for verbatim + "pre" + )); + + Set allowedTags = new HashSet<>(standardMiniMessageTags); + allowedTags.addAll(KNOWN_DYNAMIC_TOKENS); + allowedTags.addAll(KNOWN_STATIC_TOKENS); + + Pattern tagPattern = Pattern.compile("<([!/]?)([a-zA-Z_][a-zA-Z0-9_-]*)(?::[^>]*)?>"); + + for (String key : messages.getKeys(true)) { + String value = messages.getString(key); + if (value == null) continue; + + Matcher m = tagPattern.matcher(value); + while (m.find()) { + String tagName = m.group(2).toLowerCase(); + if (allowedTags.contains(tagName)) continue; + if (tagName.startsWith("#")) continue; + + errors.add("messages." + key + ": unknown tag <" + tagName + "> in: " + value); + } + } + + if (!errors.isEmpty()) { + fail("Found " + errors.size() + " unknown tag(s):\n" + String.join("\n", errors)); + } + } + + @Test + public void noMismatchedClosingTags() throws Exception { + YamlConfiguration conf = loadBundledMessages(); + ConfigurationSection messages = conf.getConfigurationSection("messages"); + + Pattern tagPattern = Pattern.compile("<(/?)([a-zA-Z_][a-zA-Z0-9_-]*)(?::([^>]*))?>"); + + for (String key : messages.getKeys(true)) { + String value = messages.getString(key); + if (value == null) continue; + + List tagStack = new ArrayList<>(); + Matcher m = tagPattern.matcher(value); + + while (m.find()) { + String slash = m.group(1); + String tagName = m.group(2).toLowerCase(); + + if (slash.isEmpty()) { + tagStack.add(tagName); + } else { + if (tagStack.isEmpty()) { + errors.add("messages." + key + ": closing tag with no matching opening tag in: " + value); + } else { + tagStack.remove(tagStack.size() - 1); + } + } + } + } + + if (!errors.isEmpty()) { + fail("Found " + errors.size() + " mismatched tag(s):\n" + String.join("\n", errors)); + } + } + + @Test + public void colorChoiceIsConsistentForActionButtons() throws Exception { + YamlConfiguration conf = loadBundledMessages(); + ConfigurationSection messages = conf.getConfigurationSection("messages"); + + String assign = messages.getString("report.actions.assign"); + String close = messages.getString("report.actions.close"); + String tp = messages.getString("report.actions.tp"); + + assertNotNull("report.actions.assign missing", assign); + assertNotNull("report.actions.close missing", close); + assertNotNull("report.actions.tp missing", tp); + + String buttonColor = ""; + assertTrue("report.actions.assign should use " + buttonColor + " for visual consistency: " + assign, + assign.contains(buttonColor)); + assertTrue("report.actions.close should use " + buttonColor + " for visual consistency: " + close, + close.contains(buttonColor)); + assertTrue("report.actions.tp should use " + buttonColor + " for visual consistency: " + tp, + tp.contains(buttonColor)); + } + + @Test + public void noTypoMissingNoun_addnoteall() throws Exception { + YamlConfiguration conf = loadBundledMessages(); + String value = conf.getString("messages.addnoteall.notify"); + assertNotNull(value); + assertTrue("addnoteall.notify is missing the word 'note': " + value, + value.toLowerCase().contains("note")); + } + + @Test + public void noGrammarErrors_invalidReason() throws Exception { + YamlConfiguration conf = loadBundledMessages(); + String value = conf.getString("messages.sender.error.invalidReason"); + assertNotNull(value); + assertTrue("invalidReason should say 'is not a valid reason' (was previously 'is no valid reason'): " + value, + value.contains("is not a valid")); + } + + @Test + public void banPlayerKickAndDisallowedShareCriticalTokens() throws Exception { + YamlConfiguration conf = loadBundledMessages(); + String disallowed = conf.getString("messages.ban.player.disallowed"); + String kick = conf.getString("messages.ban.player.kick"); + + assertNotNull("ban.player.disallowed missing", disallowed); + assertNotNull("ban.player.kick missing", kick); + + for (String token : new String[]{"", "", "", ""}) { + assertTrue("ban.player.disallowed should contain " + token + ": " + disallowed, + disallowed.contains(token)); + assertTrue("ban.player.kick should contain " + token + " for parity with disallowed: " + kick, + kick.contains(token)); + } + } + + @Test + public void tempbanPlayerKickAndDisallowedShareCriticalTokens() throws Exception { + YamlConfiguration conf = loadBundledMessages(); + String disallowed = conf.getString("messages.tempban.player.disallowed"); + String kick = conf.getString("messages.tempban.player.kick"); + + assertNotNull("tempban.player.disallowed missing", disallowed); + assertNotNull("tempban.player.kick missing", kick); + + for (String token : new String[]{"", "", "", "", ""}) { + assertTrue("tempban.player.disallowed should contain " + token + ": " + disallowed, + disallowed.contains(token)); + assertTrue("tempban.player.kick should contain " + token + " for parity with disallowed: " + kick, + kick.contains(token)); + } + } + + @Test + public void dashboardHeaderRendersStaffDashboardText() throws Exception { + YamlConfiguration conf = loadBundledMessages(); + String header = conf.getString("messages.dashboard.header"); + assertNotNull(header); + + Component component = renderer.render(header); + String plain = renderer.toPlainText(component); + assertTrue("dashboard.header plain text should contain 'Staff Dashboard': " + plain, + plain.contains("Staff Dashboard")); + } + + @Test + public void noLeftoverBracketTokens() throws Exception { + YamlConfiguration conf = loadBundledMessages(); + ConfigurationSection messages = conf.getConfigurationSection("messages"); + + Pattern bracketTokenPattern = Pattern.compile("\\[[a-zA-Z][a-zA-Z0-9_]*\\]"); + Set allowedBracketLiterals = new HashSet<>(Arrays.asList( + "[Info]", "[Unban]", "[Unmute]", "[Assign]", "[Close]", "[TP]", "[View]", + "[Muted]", "[BanManager]" + )); + + for (String key : messages.getKeys(true)) { + String value = messages.getString(key); + if (value == null) continue; + + Matcher m = bracketTokenPattern.matcher(value); + while (m.find()) { + String literal = m.group(); + if (allowedBracketLiterals.contains(literal)) continue; + errors.add("messages." + key + ": suspected leftover bracket-style token " + + literal + " in: " + value); + } + } + + if (!errors.isEmpty()) { + fail("Found " + errors.size() + " leftover bracket-style token(s):\n" + String.join("\n", errors)); + } + } + + private YamlConfiguration loadBundledMessages() throws Exception { + InputStream in = getClass().getClassLoader().getResourceAsStream(MESSAGES_RESOURCE); + assertNotNull("Resource " + MESSAGES_RESOURCE + " not found on classpath", in); + try (InputStream stream = in; + Reader reader = new InputStreamReader(stream)) { + return YamlConfiguration.loadConfiguration(reader); + } + } +} diff --git a/common/src/test/java/me/confuser/banmanager/common/util/PaginatedViewTest.java b/common/src/test/java/me/confuser/banmanager/common/util/PaginatedViewTest.java new file mode 100644 index 000000000..b79bac6d9 --- /dev/null +++ b/common/src/test/java/me/confuser/banmanager/common/util/PaginatedViewTest.java @@ -0,0 +1,60 @@ +package me.confuser.banmanager.common.util; + +import me.confuser.banmanager.common.kyori.text.Component; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.*; + +public class PaginatedViewTest { + + @Test + public void totalPagesCalculation() { + List items = createItems(25); + + PaginatedView view = new PaginatedView(items, "/test"); + assertEquals(4, view.getTotalPages()); + } + + @Test + public void totalPagesWithExactFit() { + List items = createItems(16); + + PaginatedView view = new PaginatedView(items, "/test"); + assertEquals(2, view.getTotalPages()); + } + + @Test + public void totalPagesWithSinglePage() { + List items = createItems(5); + + PaginatedView view = new PaginatedView(items, "/test"); + assertEquals(1, view.getTotalPages()); + } + + @Test + public void emptyListGivesOnePage() { + List items = new ArrayList<>(); + + PaginatedView view = new PaginatedView(items, "/test"); + assertEquals(1, view.getTotalPages()); + } + + @Test + public void customPageSize() { + List items = createItems(10); + + PaginatedView view = new PaginatedView(items, "/test", 5); + assertEquals(2, view.getTotalPages()); + } + + private List createItems(int count) { + List items = new ArrayList<>(); + for (int i = 0; i < count; i++) { + items.add(Component.text("Item " + i)); + } + return items; + } +} diff --git a/common/src/test/resources/plugin.yml b/common/src/test/resources/plugin.yml index 6250f1d94..fff172788 100644 --- a/common/src/test/resources/plugin.yml +++ b/common/src/test/resources/plugin.yml @@ -264,10 +264,15 @@ commands: usage: "/bmnames " aliases: [names] permission: bm.command.bmnames + bm: + description: "BanManager core commands (dashboard)" + usage: "/bm " + permission: bm.command.bm permissions: bm.command.*: description: Gives access to all BanManager commands children: + bm.command.bm: true bm.command.alts: true bm.command.ban: true bm.command.ban.offline: true diff --git a/e2e/build.gradle.kts b/e2e/build.gradle.kts index 0721587c0..faae3f786 100644 --- a/e2e/build.gradle.kts +++ b/e2e/build.gradle.kts @@ -157,18 +157,6 @@ tasks.register("testSpongeAll") { } } -// Sponge7 (Legacy API 7 / MC 1.12.2) E2E tests -createPlatformTestTask( - "testSponge7", - "sponge7", - ":BanManagerSponge7:shadowJar", - "Run Sponge7 (legacy API 7 / MC 1.12.2) E2E tests in Docker", - mapOf( - "MC_VERSION" to "1.12.2", - "JAVA_IMAGE" to "java8" - ) -) - // Velocity Proxy E2E tests createPlatformTestTask( "testVelocity", @@ -380,34 +368,6 @@ tasks.register("logsSponge") { commandLine("docker", "compose", "logs", "-f", "sponge") } -// Sponge7 debug tasks -tasks.register("startSponge7") { - group = "verification" - description = "Start the Sponge7 (legacy) test server without running tests (for debugging)" - - dependsOn(":BanManagerSponge7:shadowJar") - - workingDir = file("platforms/sponge7") - commandLine("docker", "compose", "up", "-d", "mariadb", "sponge7") -} - -tasks.register("stopSponge7") { - group = "verification" - description = "Stop the Sponge7 test server" - - workingDir = file("platforms/sponge7") - commandLine("docker", "compose", "down", "-v") - isIgnoreExitValue = true -} - -tasks.register("logsSponge7") { - group = "verification" - description = "Show Sponge7 server logs" - - workingDir = file("platforms/sponge7") - commandLine("docker", "compose", "logs", "-f", "sponge7") -} - // Velocity debug tasks tasks.register("startVelocity") { group = "verification" @@ -467,7 +427,7 @@ tasks.register("logsBungee") { tasks.named("clean") { doLast { // Clean up all platform Docker resources - listOf("bukkit", "fabric", "sponge", "sponge7", "velocity", "bungee").forEach { platform -> + listOf("bukkit", "fabric", "sponge", "velocity", "bungee").forEach { platform -> providers.exec { workingDir = file("platforms/$platform") commandLine("docker", "compose", "down", "-v", "--rmi", "local") diff --git a/e2e/platforms/bukkit/configs/config.yml b/e2e/platforms/bukkit/configs/config.yml index c9a784112..b8ac0e3a3 100644 --- a/e2e/platforms/bukkit/configs/config.yml +++ b/e2e/platforms/bukkit/configs/config.yml @@ -1,3 +1,7 @@ +locale: + default: en + perPlayer: true + debug: false databases: local: diff --git a/e2e/platforms/bukkit/configs/messages.yml b/e2e/platforms/bukkit/configs/messages.yml deleted file mode 100644 index 09382e935..000000000 --- a/e2e/platforms/bukkit/configs/messages.yml +++ /dev/null @@ -1,441 +0,0 @@ -# Variables -# [reason] = Ban/Mute reason -# [player] = The name of the player -# [ip] = The banned ip -# [actor] = Who banned/muted -# [expires] = How long until the ban/mute ends - -messages: - duplicateIP: '&cWarning: [player] has the same IP as the following banned players:\n&6[players]' - duplicateIPAlts: '&cWarning: [player] has the same IP as the following players:\n&6[players]' - configReloaded: '�ff00Configuration &#ff5733reloaded &asuccessfully!' - deniedNotify: - player: '&cWarning: [player] attempted to join the server but was denied due to &4[reason]' - ip: '&cWarning: [ip] attempted to join the server but was denied due to &4[reason]' - deniedMaxIp: '&cToo many players with your ip address online' - deniedMultiaccounts: '&cToo many players with your ip address logged in recently' - deniedCountry: '&cYou may not connect from your region' - - time: - now: 'now' - year: 'year' - years: 'years' - month: 'month' - months: 'months' - week: 'week' - weeks: 'weeks' - day: 'day' - days: 'days' - hour: 'hour' - hours: 'hours' - minute: 'minute' - minutes: 'minutes' - second: 'second' - seconds: 'seconds' - never: 'never' - error: - invalid: '&cYour time length is invalid' - limit: '&cYou cannot perform this action for that length of time' - - none: 'none' - # General command text - sender: - error: - notFound: '&c[player] not found, are you sure they exist?' - offline: '&c[player] is offline' - noSelf: '&cYou cannot perform that action on yourself!' - exception: '&cAn error occured whilst attempting to perform this command. Please check the console for further details.' - invalidIp: '&cInvalid IP address, expecting w.x.y.z format' - offlinePermission: '&cYou are not allowed to perform this action on an offline player' - exempt: '&c[player] is exempt from that action' - noPermission: '&cYou do not have permission to perform that action' - invalidReason: '&c[reason] is no valid reason.' - # Commands - alts: - header: 'Possible alts found:' - - export: - error: - inProgress: '&cAn export is already in progress, please wait' - player: - started: '&aPlayer ban export started' - finished: '&aPlayer ban export finished, file [file] created' - ip: - started: '&aIP ban export started' - finished: '&aIP ban export finished, file [file] created' - - import: - error: - inProgress: '&cAn import is already in progress, please wait' - player: - started: '&aPlayer ban import started' - finished: '&aPlayer ban import finished' - ip: - started: '&aIP ban import started' - finished: '&aIP ban import finished' - advancedban: - started: '&aAdvancedBan import started' - finished: '&aAdvancedBan import finished' - h2: - started: '&aH2 import started' - finished: '&aH2 import finished, please restart the server' - litebans: - started: '&aLiteBans import started' - finished: '&aLiteBans import finished' - - info: - error: - invalidIndex: '&cInvalid player option used' - indexRequired: '&cMultiple players named [name] found, please select a player by providing an index between 1 and [size], e.g. /bminfo [name] 1' - index: '&7#[index] - &6[name] - &4[uuid]' - stats: - player: '&6[player] has been banned [bans] times, muted [mutes] times, kicked [kicks] times and warned [warns] - times ([warnPoints] Points), has [notes] notes and been reported [reports] times' - ip: '&6This ip has been banned [bans] times, muted [mutes] times and range banned [rangebans] times' - connection: '&6Their last connection was with [ip] on [lastSeen]' - geoip: 'Country: [country] City: [city]' - ban: - permanent: '&6Currently banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently banned for &4[reason]&6 by [actor] at [created] which expires in [expires]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - ipban: - permanent: '&6Currently banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently banned for &4[reason]&6 by [actor] at [created] which expires in [expires]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - iprangeban: - permanent: '&6[from] - [to] banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6[from] - [to] banned for &4[reason]&6 by [actor] at [created] which expires in [expires]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - ipmute: - permanent: '&6Currently muted for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently muted for &4[reason]&6 by [actor] at [created] which expires in [expires]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - mute: - permanent: '&6Currently muted for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently muted for &4[reason]&6 by [actor] at [created] which expires in [expires]' - temporaryOnline: '&6Currently muted for &4[reason]&6 by [actor] at [created] which expires in [expires] (online time)' - temporaryOnlinePaused: '&6Currently muted for &4[reason]&6 by [actor] at [created] with [remaining] remaining (online time, paused)' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - website: - player: 'https://yourdomain.com/player/[uuid]' - ip: 'http://yourdomain.com/index.php?action=viewip&ip=[ip]&server=0' - history: - row: '&7#[id] &a[&f[type]&a] &6[actor]&f [meta] [reason] - &e[created]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - noResults: '&cNo results found' - ips: - row: '&e[ip] - &6[join] - [leave]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - - kick: - player: - noReason: '&6You have been kicked' - reason: '&6You have been kicked for &4[reason]' - notify: - noReason: '&6[player] has been kicked by [actor]' - reason: '&6[player] has been kicked by [actor] for &4[reason]' - - kickall: - player: - noReason: '&6You have been kicked' - reason: '&6You have been kicked for &4[reason]' - notify: - noReason: 'All players have been kicked by [actor]' - reason: 'All players have been kicked by [actor] for &4[reason]' - - ban: - player: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6[player] has been permanently banned by [actor] for &4[reason]' - error: - exists: '&c[player] is already banned' - cooldown: '&cThis player was banned too recently, try again later' - - banall: - notify: '&6[player] will be permanently banned by [actor] for &4[reason]' - - tempban: - player: - disallowed: '&6You have been temporarily banned from this server for &4[reason] \n&6It expires in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6[player] has been temporarily banned for [expires] by [actor] for &4[reason]' - - tempbanall: - notify: '&6[player] will be temporarily banned for [expires] by [actor] for &4[reason]' - - unban: - notify: '&6[player] has been unbanned by [actor]' - error: - noExists: '&c[player] is not banned' - notOwn: '&c[player] was not banned by you, unable to unban' - - unbanall: - notify: '&6[player] will be unbanned by [actor]' - - mute: - player: - blocked: '&cYou may not use the [command] command whilst muted!' - disallowed: '&6You have been permanently muted for &4[reason] &6by [actor]' - broadcast: '&4[Muted] [player]&7 [message]' - notify: '&6[player] has been permanently muted by [actor] for &4[reason]' - error: - exists: '&c[player] is already muted' - cooldown: '&cThis player was muted too recently, try again later' - - muteip: - ip: - disallowed: '&6You have been permanently muted for &4[reason] &6by [actor]' - broadcast: '&4[Muted] [player]&7 [message]' - notify: '&6[ip] ([players]) have been permanently muted by [actor] for &4[reason]' - error: - exists: '&c[ip] is already muted' - - muteall: - notify: '&6[player] will be permanently muted by [actor] for &4[reason]' - - tempmute: - player: - disallowed: '&6You have been temporarily muted for &4[reason] &6by [actor] which expires in [expires]' - disallowedOnline: '&6You have been temporarily muted for &4[reason] &6by [actor] which expires in [expires] (online time)' - notify: '&6[player] has been temporarily muted for [expires] by [actor] for &4[reason]' - notifyOnline: '&6[player] has been temporarily muted for [expires] (online time) by [actor] for &4[reason]' - error: - exists: '&c[player] is already muted' - - tempmuteip: - ip: - disallowed: '&6You have been temporarily muted for &4[reason] &6by [actor] which expires in [expires]' - notify: '&6[ip] ([players]) have been temporarily muted for [expires] by [actor] for &4[reason]' - error: - exists: '&c[ip] is already muted' - - tempmuteall: - notify: '&6[player] will be temporarily muted for [expires] by [actor] for &4[reason]' - - unmute: - notify: '&6[player] has been unmuted by [actor]' - player: '&6You have been unmuted by [actor]' - error: - noExists: '&c[player] is not muted' - notOwn: '&c[player] was not muted by you, unable to unmute' - - unmuteip: - notify: '&6[ip] has been unmuted by [actor]' - error: - noExists: '&c[ip] is not muted' - notOwn: '&c[ip] was not muted by you, unable to unmute' - - unmuteall: - notify: '&6[player] will be unmuted by [actor]' - - banname: - name: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6Name [name] has been permanently banned by [actor] for &4[reason]' - error: - exists: '&cName [name] is already banned' - - tempbanname: - name: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6Name [name] has been temporarily banned for [expires] by [actor] for &4[reason]' - - unbanname: - notify: '&6Name [name] has been unbanned by [actor]' - error: - noExists: '&cName [name] is not banned' - - banip: - ip: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6[ip] ([players]) has been permanently banned by [actor] for &4[reason]' - error: - exists: '&c[ip] is already banned' - cooldown: '&cThis ip was banned too recently, try again later' - - baniprange: - error: - invalid: '&cInvalid range, please use cidr notation 192.168.0.1/16 or wildcard 192.168.*.*' - minMax: '&cRange must be lowest to highest' - exists: '&cA ban containing those ranges already exists' - ip: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6[from] - [to] have been banned by [actor]' - - tempbaniprange: - notify: '&6[from] - [to] has been temporarily banned for [expires] by [actor]' - ip: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires in [expires]' - kick: '&6You have been temporarily banned for [expires] by [actor] for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - - unbaniprange: - notify: '&6[from] - [to] has been unbanned by [actor]' - - banipall: - notify: '&6[ip] will be permanently banned by [actor] for &4[reason]' - - tempbanip: - ip: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6[ip] ([players]) has been temporarily banned for [expires] by [actor] for &4[reason]' - - tempbanipall: - notify: '&6[ip] will be temporarily banned for [expires] by [actor] for &4[reason]' - - unbanip: - notify: '&6[ip] has been unbanned by [actor]' - error: - noExists: '&c[ip] is not banned' - notOwn: '&c[ip] was not banned by you, unable to unban' - - unbanipall: - notify: '&6[ip] will be unbanned by [actor]' - - warn: - player: - warned: '&6You have been warned by [actor] for &4[reason]' - disallowed: - header: '&cYou may not speak until you have accepted your most recent warning. Please type the following:' - reason: '&6[reason]' - removed: '&aThank you for your understanding, you may now speak again' - notify: '&6[player] has been warned by [actor] for &4[reason]' - error: - cooldown: '&cThis player was warned too recently, try again later' - - tempwarn: - player: - warned: '&6You have been warned for [expires] by [actor] for &4[reason]' - notify: '&6[player] has been warned for [expires] by [actor] for &4[reason]' - - dwarn: - player: - notify: '&6Your most recent warning has been deleted by &4[actor]' - notify: '&cThe most recent warning for [player] has been deleted' - error: - noWarnings: '&c[player] has no warnings to delete' - - bmclear: - notify: '&c[player] has had their [type] cleared' - error: - invalid: '&cInvalid type, please choose between banrecords, muterecords, kicks, notes or warnings' - - bmutils: - missingplayers: - notify: '&c[amount] missing players added' - noneFound: '&a0 missing players found' - found: '&c[amount] missing player data found. Fixing...' - error: - failedLookup: '&cFailed to lookup player [uuid], check server logs' - complete: '&a[amount] players resolved, please restart your server for failed punishments to take affect' - duplicates: - lookup: - notFound: '&aNo duplicate player names found' - error: - invalidName: '&cInvalid name, must be 16 characters or less and contain only letters, numbers and an underscore' - nameExists: '&cA player with that name already exists' - success: '&aPlayer name set to [player] successfully' - - bmrollback: - notify: '&c[player] has had their [type] actions undone' - error: - invalid: '&cInvalid type [type], please choose between [types]' - - sync: - player: - started: '&aStarting force [type] synchronisation' - finished: '&aForced [type] synchronisation complete' - - update: - notify: '&6[BanManager] &aAn update is available' - - notes: - header: '&6[player] has the following notes:' - joinAmount: '&6[player] has &e[amount] &6notes, click to view them' - note: '&6[[player]] &e[message] - &e[created]' - playerNote: '&a[[player]] &6[[actor]] &e[message] - &e[created]' - dateTimeFormat: 'dd-MM-yyyy' - notify: '[player] has a new note attached by [actor]: [message]' - error: - noNotes: '&c[player] has no notes' - noOnlineNotes: '&cNo online players have notes' - - report: - notify: '&6[player] has been reported by [actor] for &4[reason]' - error: - cooldown: '&cThis player was reported too recently, try again later' - assign: - player: '&aReport [id] assigned to [player]' - notify: '&aYou have been assigned report [id] by [actor]' - unassign: - player: '&aReport [id] unassigned' - close: - notify: - closed: '&aReport [id] closed by [actor]' - command: '&aReport [id] closed by [actor] with [command]' - comment: '&aReport [id] closed by [actor] with [comment]' - dispatch: 'Executing command [command]' - list: - noResults: '&cNo reports found' - error: - invalidState: '&cReport state [state] not found' - row: - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - header: '&e-- Reports ([count]) -- Page ([page]/[maxPage])' - all: '&7#[id] &e[[state]] &6- [created] - [player]' - tp: - error: - notFound: '&cReport not found' - worldNotFound: '&cWorld [world] could not be found' - invalidId: '&c[id] is not a valid report id' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: - report: '&7#[id] &6[actor] reported [player] for &4[reason]&6 at [created]' - location: '[world] - [x], [y], [z]' - info: - error: - notFound: '&cReport not found' - invalidId: '&c[id] is not a valid report id' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: - report: '&7#[id] &6[actor] reported [player] for &4[reason]&6 at [created]' - location: '[world] - [x], [y], [z]' - - addnoteall: - notify: '&c[player] will have a new attached by [actor]: [message]' - - banlist: - header: '&6There are [bans] [type] bans:' - - bmactivity: - row: - all: '&a[&f[type]&a] &6[player]&f - &6[actor]&f - &e[created]' - player: '&a[&f[type]&a] &6[player]&f - &e[created]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - noResults: '&cNo results found' - - bmdelete: - notify: '&a[rows] rows deleted' - error: - invalid: '&cInvalid type, please choose between banrecords, muterecords, kicks, notes or warnings' - invalidId: '&c[id] is not a valid number' - - denyalts: - player: - disallowed: '&cThe IP address you are joining from is linked to a banned player' - - reasons: - row: '[hashtag] = [reason]' diff --git a/e2e/platforms/bukkit/configs/messages/messages_de.yml b/e2e/platforms/bukkit/configs/messages/messages_de.yml new file mode 100644 index 000000000..d813fecbc --- /dev/null +++ b/e2e/platforms/bukkit/configs/messages/messages_de.yml @@ -0,0 +1,16 @@ +messages: + configReloaded: '&aKonfiguration erfolgreich neu geladen!' + + ban: + player: + disallowed: '&6Du wurdest von diesem Server gebannt wegen &4[reason]' + kick: '&6Du wurdest dauerhaft gebannt wegen &4[reason]' + notify: '&6[player] wurde dauerhaft gebannt von [actor] wegen &4[reason]' + + unban: + notify: '&6[player] wurde von [actor] entbannt' + + mute: + player: + disallowed: '&6Du bist stummgeschaltet wegen &4[reason]' + notify: '&6[player] wurde dauerhaft stummgeschaltet von [actor] wegen &4[reason]' diff --git a/e2e/platforms/bukkit/configs/messages/messages_en.yml b/e2e/platforms/bukkit/configs/messages/messages_en.yml new file mode 100644 index 000000000..9da20bc47 --- /dev/null +++ b/e2e/platforms/bukkit/configs/messages/messages_en.yml @@ -0,0 +1,474 @@ +# Message templates use MiniMessage formatting: https://docs.advntr.dev/minimessage/format.html +# Placeholders use angle brackets, e.g. , , , , + +tokens: + appeal_url: 'https://yourdomain.com/appeal' + server_name: 'My Server' + discord_url: 'https://discord.gg/example' + rules_url: 'https://yourdomain.com/rules' + +messages: + duplicateIP: 'Warning: has the same IP as the following banned players:\n' + duplicateIPAlts: 'Warning: has the same IP as the following players:\n' + configReloaded: 'Configuration reloaded successfully!' + deniedNotify: + player: 'Warning: attempted to join the server but was denied due to ' + ip: 'Warning: attempted to join the server but was denied due to ' + deniedMaxIp: 'Too many players with your ip address online' + deniedMultiaccounts: 'Too many players with your ip address logged in recently' + deniedCountry: 'You may not connect from your region' + + time: + now: 'now' + year: 'year' + years: 'years' + month: 'month' + months: 'months' + week: 'week' + weeks: 'weeks' + day: 'day' + days: 'days' + hour: 'hour' + hours: 'hours' + minute: 'minute' + minutes: 'minutes' + second: 'second' + seconds: 'seconds' + never: 'never' + error: + invalid: 'Your time length is invalid' + limit: 'You cannot perform this action for that length of time' + + none: 'none' + # General command text + sender: + error: + notFound: ' not found, are you sure they exist?' + offline: ' is offline' + noSelf: 'You cannot perform that action on yourself!' + exception: 'An error occured whilst attempting to perform this command. Please check the console for further details.' + invalidIp: 'Invalid IP address, expecting w.x.y.z format' + offlinePermission: 'You are not allowed to perform this action on an offline player' + ambiguousPlayer: 'Multiple players match "". Please use their full name.' + exempt: ' is exempt from that action' + noPermission: 'You do not have permission to perform that action' + noConsole: 'This command cannot be used from console' + invalidReason: ' is not a valid reason.' + # Commands + alts: + header: 'Possible alts found:' + entry: '">' + separator: ', ' + + names: + header: 'Known names for :' + row: ' (first: , last: )' + interactive: ' (first: , last: )">">' + separator: ', ' + dateTimeFormat: 'dd-MM-yyyy' + none: 'No name history found' + + export: + error: + inProgress: 'An export is already in progress, please wait' + player: + started: 'Player ban export started' + finished: 'Player ban export finished, file created' + ip: + started: 'IP ban export started' + finished: 'IP ban export finished, file created' + + import: + error: + inProgress: 'An import is already in progress, please wait' + player: + started: 'Player ban import started' + finished: 'Player ban import finished' + ip: + started: 'IP ban import started' + finished: 'IP ban import finished' + advancedban: + started: 'AdvancedBan import started' + finished: 'AdvancedBan import finished' + h2: + started: 'H2 import started' + finished: 'H2 import finished, please restart the server' + litebans: + started: 'LiteBans import started' + finished: 'LiteBans import finished' + + info: + error: + invalidIndex: 'Invalid player option used' + indexRequired: 'Multiple players named found, please select a player by providing an index between 1 and , e.g. /bminfo 1' + index: '# - - ' + stats: + player: ' has been banned times, muted times, kicked times and warned + times ( Points), has notes and been reported times' + ip: 'This ip has been banned times, muted times and range banned times' + connection: 'Their last connection was with on ' + geoip: 'Country: City: ' + ban: + permanent: 'Currently banned for by at ' + temporary: 'Currently banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + ipban: + permanent: 'Currently banned for by at ' + temporary: 'Currently banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + iprangeban: + permanent: ' - banned for by at ' + temporary: ' - banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + ipmute: + permanent: 'Currently muted for by at ' + temporary: 'Currently muted for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + mute: + permanent: 'Currently muted for by at ' + temporary: 'Currently muted for by at which expires in ' + temporaryOnline: 'Currently muted for by at which expires in (online time)' + temporaryOnlinePaused: 'Currently muted for by at with remaining (online time, paused)' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + website: + player: 'https://yourdomain.com/player/' + ip: 'http://yourdomain.com/index.php?action=viewip&ip=&server=0' + history: + row: '# [] - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + noResults: 'No results found' + ips: + row: ' - - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + + kick: + player: + noReason: 'You have been kicked' + reason: 'You have been kicked for ' + notify: + noReason: ' has been kicked by ">View player info">[Info]' + reason: ' has been kicked by for ">View player info">[Info]' + + kickall: + player: + noReason: 'You have been kicked' + reason: 'You have been kicked for ' + notify: + noReason: 'All players have been kicked by ' + reason: 'All players have been kicked by for ' + + ban: + player: + disallowed: 'You are banned from this server\n \nReason: \nBanned by: \nDate: \n \nAppeal at ' + kick: 'You have been banned\n \nReason: \nBanned by: \nDate: \n \nAppeal at ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' has been permanently banned by for ">View player info">[Info] ">Unban player">[Unban]' + error: + exists: ' is already banned' + cooldown: 'This player was banned too recently, try again later' + + banall: + notify: ' will be permanently banned by for ' + + tempban: + player: + disallowed: 'You are temporarily banned from this server\n \nReason: \nBanned by: \nExpires: \nDate: \n \nAppeal at ' + kick: 'You have been temporarily banned\n \nReason: \nBanned by: \nExpires: \nDate: \n \nAppeal at ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' has been temporarily banned for by for ">View player info">[Info] ">Unban player">[Unban]' + + tempbanall: + notify: ' will be temporarily banned for by for ' + + unban: + notify: ' has been unbanned by ' + error: + noExists: ' is not banned' + notOwn: ' was not banned by you, unable to unban' + + unbanall: + notify: ' will be unbanned by ' + + mute: + player: + blocked: 'You may not use the command whilst muted!' + disallowed: 'You have been permanently muted for by ' + broadcast: '[Muted] ' + notify: ' has been permanently muted by for ">View player info">[Info] ">Unmute player">[Unmute]' + error: + exists: ' is already muted' + cooldown: 'This player was muted too recently, try again later' + + muteip: + ip: + disallowed: 'You have been permanently muted for by ' + broadcast: '[Muted] ' + notify: ' () have been permanently muted by for ' + error: + exists: ' is already muted' + + muteall: + notify: ' will be permanently muted by for ' + + tempmute: + player: + disallowed: 'You have been temporarily muted for by which expires in ' + disallowedOnline: 'You have been temporarily muted for by which expires in (online time)' + notify: ' has been temporarily muted for by for ">View player info">[Info] ">Unmute player">[Unmute]' + notifyOnline: ' has been temporarily muted for (online time) by for ' + error: + exists: ' is already muted' + + tempmuteip: + ip: + disallowed: 'You have been temporarily muted for by which expires in ' + notify: ' () have been temporarily muted for by for ' + error: + exists: ' is already muted' + + tempmuteall: + notify: ' will be temporarily muted for by for ' + + unmute: + notify: ' has been unmuted by ' + player: 'You have been unmuted by ' + error: + noExists: ' is not muted' + notOwn: ' was not muted by you, unable to unmute' + + unmuteip: + notify: ' has been unmuted by ' + error: + noExists: ' is not muted' + notOwn: ' was not muted by you, unable to unmute' + + unmuteall: + notify: ' will be unmuted by ' + + banname: + name: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: 'Name has been permanently banned by for ' + error: + exists: 'Name is already banned' + + tempbanname: + name: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: 'Name has been temporarily banned for by for ' + + unbanname: + notify: 'Name has been unbanned by ' + error: + noExists: 'Name is not banned' + + banip: + ip: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' () has been permanently banned by for ' + error: + exists: ' is already banned' + cooldown: 'This ip was banned too recently, try again later' + + baniprange: + error: + invalid: 'Invalid range, please use cidr notation 192.168.0.1/16 or wildcard 192.168.*.*' + minMax: 'Range must be lowest to highest' + exists: 'A ban containing those ranges already exists' + ip: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' - have been banned by ' + + tempbaniprange: + notify: ' - has been temporarily banned for by ' + ip: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for by for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + + unbaniprange: + notify: ' - has been unbanned by ' + + banipall: + notify: ' will be permanently banned by for ' + + tempbanip: + ip: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' () has been temporarily banned for by for ' + + tempbanipall: + notify: ' will be temporarily banned for by for ' + + unbanip: + notify: ' has been unbanned by ' + error: + noExists: ' is not banned' + notOwn: ' was not banned by you, unable to unban' + + unbanipall: + notify: ' will be unbanned by ' + + warn: + player: + warned: 'You have been warned by for ' + disallowed: + header: 'You may not speak until you have accepted your most recent warning. Please type the following:' + reason: '' + removed: 'Thank you for your understanding, you may now speak again' + notify: ' has been warned by for ">View player info">[Info]' + error: + cooldown: 'This player was warned too recently, try again later' + + tempwarn: + player: + warned: 'You have been warned for by for ' + notify: ' has been warned for by for ">View player info">[Info]' + + dwarn: + player: + notify: 'Your most recent warning has been deleted by ' + notify: 'The most recent warning for has been deleted' + error: + noWarnings: ' has no warnings to delete' + + bmclear: + notify: ' has had their cleared' + error: + invalid: 'Invalid type, please choose between banrecords, muterecords, kicks, notes or warnings' + + bmutils: + missingplayers: + notify: ' missing players added' + noneFound: '0 missing players found' + found: ' missing player data found. Fixing...' + error: + failedLookup: 'Failed to lookup player , check server logs' + complete: ' players resolved, please restart your server for failed punishments to take affect' + duplicates: + lookup: + notFound: 'No duplicate player names found' + error: + invalidName: 'Invalid name, must be 16 characters or less and contain only letters, numbers and an underscore' + nameExists: 'A player with that name already exists' + success: 'Player name set to successfully' + + bmrollback: + notify: ' has had their actions undone' + error: + invalid: 'Invalid type , please choose between ' + + sync: + player: + started: 'Starting force synchronisation' + finished: 'Forced synchronisation complete' + + update: + notify: '[BanManager] An update is available' + + notes: + header: ' has the following notes:' + joinAmount: '"> has notes, click to view them' + note: '[] - ' + playerNote: '[] [] - ' + dateTimeFormat: 'dd-MM-yyyy' + notify: ' has a new note attached by : ' + error: + noNotes: ' has no notes' + noOnlineNotes: 'No online players have notes' + + report: + notify: ' has been reported by for ' + error: + cooldown: 'This player was reported too recently, try again later' + assign: + player: 'Report assigned to ' + notify: 'You have been assigned report by ' + unassign: + player: 'Report unassigned' + close: + notify: + closed: 'Report closed by ' + command: 'Report closed by with ' + comment: 'Report closed by with ' + dispatch: 'Executing command ' + list: + noResults: 'No reports found' + error: + invalidState: 'Report state not found' + row: + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + header: '-- Reports () -- Page (/)' + all: '">Click to view details"># [] - - ' + tp: + error: + notFound: 'Report not found' + worldNotFound: 'World could not be found' + invalidId: ' is not a valid report id' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: + report: '# reported for at ' + location: ' - , , ' + info: + error: + notFound: 'Report not found' + invalidId: ' is not a valid report id' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: + report: '# reported for at ' + location: ' - , , ' + actions: + assign: '">Assign to yourself">[Assign]' + close: '">Close this report">[Close]' + tp: '">Teleport to location">[TP]' + feedback: + assigned: 'Your report # has been assigned to ' + closed: 'Your report # has been closed by ' + + addnoteall: + notify: ' will have a new note attached by : ' + + banlist: + header: 'There are bans:' + row: + player: '">Click for info"> - ' + ip: ' - ' + iprange: ' - - ' + + bmactivity: + row: + all: '[] - - ' + player: '[] - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + noResults: 'No results found' + + bmdelete: + notify: ' rows deleted' + error: + invalid: 'Invalid type, please choose between banrecords, muterecords, kicks, notes or warnings' + invalidId: ' is not a valid number' + + denyalts: + player: + disallowed: 'The IP address you are joining from is linked to a banned player' + + reasons: + row: ' = ' + + dashboard: + header: ' Staff Dashboard ' + activeBans: 'Active Bans: ' + activeMutes: 'Active Mutes: ' + openReports: 'Open Reports: View reports">[View]' + recentActivity: 'Recent Activity (24h): ' + footer: ' ' diff --git a/e2e/platforms/bukkit/configs/notifications.yml b/e2e/platforms/bukkit/configs/notifications.yml new file mode 100644 index 000000000..75b1fb646 --- /dev/null +++ b/e2e/platforms/bukkit/configs/notifications.yml @@ -0,0 +1,81 @@ +# Notifications Configuration +# Controls how punishment notifications are delivered to staff and players +# +# Each notification event can specify delivery channels: +# chat: true/false - Send via chat message (default: true) +# actionbar: true/false - Send via action bar (disappears after a few seconds) +# title: true/false - Send via title/subtitle overlay +# sound: '' - Sound to play (empty to disable). Use Minecraft sound names e.g. entity.experience_orb.pickup +# +# Title settings (only used when title: true): +# titleFadeIn: ticks for fade in (20 ticks = 1 second) +# titleStay: ticks to stay on screen +# titleFadeOut: ticks for fade out +# +# Sound settings: +# soundVolume: 0.0 - 1.0 +# soundPitch: 0.0 - 2.0 +# +# Platform notes: +# - BungeeCord: title, showTitle and playSound are not supported (ignored silently) +# - Sponge API7: playSound is not supported (ignored silently) +# - All other platforms (Bukkit/Paper, Velocity, Fabric, Sponge API8+) support all channels + +staff: + ban: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + tempban: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + mute: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + tempmute: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + warn: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + report: + chat: true + actionbar: false + title: false + sound: 'block.note_block.pling' + soundVolume: 1.0 + soundPitch: 1.0 + duplicateIp: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + +player: + muted: + actionbar: true + warned: + sound: 'entity.villager.no' + soundVolume: 1.0 + soundPitch: 1.0 diff --git a/e2e/platforms/bungee/configs/banmanager/config.yml b/e2e/platforms/bungee/configs/banmanager/config.yml index 8581b02e3..4c59ef67e 100644 --- a/e2e/platforms/bungee/configs/banmanager/config.yml +++ b/e2e/platforms/bungee/configs/banmanager/config.yml @@ -1,5 +1,9 @@ # # Aliases will be found and blocked automatically, e.g. msg will block tell +locale: + default: en + perPlayer: true + debug: false databases: local: diff --git a/e2e/platforms/bungee/configs/banmanager/messages.yml b/e2e/platforms/bungee/configs/banmanager/messages.yml deleted file mode 100644 index 689b5c8c8..000000000 --- a/e2e/platforms/bungee/configs/banmanager/messages.yml +++ /dev/null @@ -1,424 +0,0 @@ -# Variables -# [reason] = Ban/Mute reason -# [player] = The name of the player -# [ip] = The banned ip -# [actor] = Who banned/muted -# [expires] = How long until the ban/mute ends - -messages: - duplicateIP: '&cWarning: [player] has the same IP as the following banned players:\n&6[players]' - duplicateIPAlts: '&cWarning: [player] has the same IP as the following players:\n&6[players]' - configReloaded: '�ff00Configuration &#ff5733reloaded &asuccessfully!' - deniedNotify: - player: '&cWarning: [player] attempted to join the server but was denied due to - &4[reason]' - ip: '&cWarning: [ip] attempted to join the server but was denied due to &4[reason]' - deniedMaxIp: '&cToo many players with your ip address online' - deniedMultiaccounts: '&cToo many players with your ip address logged in recently' - deniedCountry: '&cYou may not connect from your region' - time: - now: now - year: year - years: years - month: month - months: months - week: week - weeks: weeks - day: day - days: days - hour: hour - hours: hours - minute: minute - minutes: minutes - second: second - seconds: seconds - never: never - error: - invalid: '&cYour time length is invalid' - limit: '&cYou cannot perform this action for that length of time' - none: none - sender: - error: - notFound: '&c[player] not found, are you sure they exist?' - offline: '&c[player] is offline' - noSelf: '&cYou cannot perform that action on yourself!' - exception: '&cAn error occured whilst attempting to perform this command. Please - check the console for further details.' - invalidIp: '&cInvalid IP address, expecting w.x.y.z format' - offlinePermission: '&cYou are not allowed to perform this action on an offline - player' - exempt: '&c[player] is exempt from that action' - noPermission: '&cYou do not have permission to perform that action' - invalidReason: '&c[reason] is no valid reason.' - alts: - header: 'Possible alts found:' - names: - header: 'Known names for [player]:' - row: '&e[name] &7(first: [firstSeen], last: [lastSeen])' - dateTimeFormat: dd-MM-yyyy - none: '&7No name history found' - export: - error: - inProgress: '&cAn export is already in progress, please wait' - player: - started: '&aPlayer ban export started' - finished: '&aPlayer ban export finished, file [file] created' - ip: - started: '&aIP ban export started' - finished: '&aIP ban export finished, file [file] created' - import: - error: - inProgress: '&cAn import is already in progress, please wait' - player: - started: '&aPlayer ban import started' - finished: '&aPlayer ban import finished' - ip: - started: '&aIP ban import started' - finished: '&aIP ban import finished' - advancedban: - started: '&aAdvancedBan import started' - finished: '&aAdvancedBan import finished' - h2: - started: '&aH2 import started' - finished: '&aH2 import finished, please restart the server' - litebans: - started: '&aLiteBans import started' - finished: '&aLiteBans import finished' - info: - error: - invalidIndex: '&cInvalid player option used' - indexRequired: '&cMultiple players named [name] found, please select a player - by providing an index between 1 and [size], e.g. /bminfo [name] 1' - index: '&7#[index] - &6[name] - &4[uuid]' - stats: - player: '&6[player] has been banned [bans] times, muted [mutes] times, kicked - [kicks] times and warned [warns] times ([warnPoints] Points), has [notes] - notes and been reported [reports] times' - ip: '&6This ip has been banned [bans] times, muted [mutes] times and range banned - [rangebans] times' - connection: '&6Their last connection was with [ip] on [lastSeen]' - geoip: 'Country: [country] City: [city]' - ban: - permanent: '&6Currently banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently banned for &4[reason]&6 by [actor] at [created] which - expires in [expires]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - ipban: - permanent: '&6Currently banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently banned for &4[reason]&6 by [actor] at [created] which - expires in [expires]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - iprangeban: - permanent: '&6[from] - [to] banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6[from] - [to] banned for &4[reason]&6 by [actor] at [created] - which expires in [expires]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - ipmute: - permanent: '&6Currently muted for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently muted for &4[reason]&6 by [actor] at [created] which - expires in [expires]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - mute: - permanent: '&6Currently muted for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently muted for &4[reason]&6 by [actor] at [created] which - expires in [expires]' - temporaryOnline: '&6Currently muted for &4[reason]&6 by [actor] at [created] - which expires in [expires] (online time)' - temporaryOnlinePaused: '&6Currently muted for &4[reason]&6 by [actor] at [created] - with [remaining] remaining (online time, paused)' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - website: - player: https://yourdomain.com/player/[uuid] - ip: http://yourdomain.com/index.php?action=viewip&ip=[ip]&server=0 - history: - row: '&7#[id] &a[&f[type]&a] &6[actor]&f [meta] [reason] - &e[created]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - noResults: '&cNo results found' - ips: - row: '&e[ip] - &6[join] - [leave]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - kick: - player: - noReason: '&6You have been kicked' - reason: '&6You have been kicked for &4[reason]' - notify: - noReason: '&6[player] has been kicked by [actor]' - reason: '&6[player] has been kicked by [actor] for &4[reason]' - kickall: - player: - noReason: '&6You have been kicked' - reason: '&6You have been kicked for &4[reason]' - notify: - noReason: All players have been kicked by [actor] - reason: All players have been kicked by [actor] for &4[reason] - ban: - player: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[player] has been permanently banned by [actor] for &4[reason]' - error: - exists: '&c[player] is already banned' - cooldown: '&cThis player was banned too recently, try again later' - banall: - notify: '&6[player] will be permanently banned by [actor] for &4[reason]' - tempban: - player: - disallowed: '&6You have been temporarily banned from this server for &4[reason] - \n&6It expires in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[player] has been temporarily banned for [expires] by [actor] for &4[reason]' - tempbanall: - notify: '&6[player] will be temporarily banned for [expires] by [actor] for &4[reason]' - unban: - notify: '&6[player] has been unbanned by [actor]' - error: - noExists: '&c[player] is not banned' - notOwn: '&c[player] was not banned by you, unable to unban' - unbanall: - notify: '&6[player] will be unbanned by [actor]' - mute: - player: - blocked: '&cYou may not use the [command] command whilst muted!' - disallowed: '&6You have been permanently muted for &4[reason] &6by [actor]' - broadcast: '&4[Muted] [player]&7 [message]' - notify: '&6[player] has been permanently muted by [actor] for &4[reason]' - error: - exists: '&c[player] is already muted' - cooldown: '&cThis player was muted too recently, try again later' - muteip: - ip: - disallowed: '&6You have been permanently muted for &4[reason] &6by [actor]' - broadcast: '&4[Muted] [player]&7 [message]' - notify: '&6[ip] ([players]) have been permanently muted by [actor] for &4[reason]' - error: - exists: '&c[ip] is already muted' - muteall: - notify: '&6[player] will be permanently muted by [actor] for &4[reason]' - tempmute: - player: - disallowed: '&6You have been temporarily muted for &4[reason] &6by [actor] which - expires in [expires]' - disallowedOnline: '&6You have been temporarily muted for &4[reason] &6by [actor] - which expires in [expires] (online time)' - notify: '&6[player] has been temporarily muted for [expires] by [actor] for &4[reason]' - notifyOnline: '&6[player] has been temporarily muted for [expires] (online time) - by [actor] for &4[reason]' - error: - exists: '&c[player] is already muted' - tempmuteip: - ip: - disallowed: '&6You have been temporarily muted for &4[reason] &6by [actor] which - expires in [expires]' - notify: '&6[ip] ([players]) have been temporarily muted for [expires] by [actor] - for &4[reason]' - error: - exists: '&c[ip] is already muted' - tempmuteall: - notify: '&6[player] will be temporarily muted for [expires] by [actor] for &4[reason]' - unmute: - notify: '&6[player] has been unmuted by [actor]' - player: '&6You have been unmuted by [actor]' - error: - noExists: '&c[player] is not muted' - notOwn: '&c[player] was not muted by you, unable to unmute' - unmuteip: - notify: '&6[ip] has been unmuted by [actor]' - error: - noExists: '&c[ip] is not muted' - notOwn: '&c[ip] was not muted by you, unable to unmute' - unmuteall: - notify: '&6[player] will be unmuted by [actor]' - banname: - name: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6Name [name] has been permanently banned by [actor] for &4[reason]' - error: - exists: '&cName [name] is already banned' - tempbanname: - name: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires - in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6Name [name] has been temporarily banned for [expires] by [actor] for - &4[reason]' - unbanname: - notify: '&6Name [name] has been unbanned by [actor]' - error: - noExists: '&cName [name] is not banned' - banip: - ip: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[ip] ([players]) has been permanently banned by [actor] for &4[reason]' - error: - exists: '&c[ip] is already banned' - cooldown: '&cThis ip was banned too recently, try again later' - baniprange: - error: - invalid: '&cInvalid range, please use cidr notation 192.168.0.1/16 or wildcard - 192.168.*.*' - minMax: '&cRange must be lowest to highest' - exists: '&cA ban containing those ranges already exists' - ip: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[from] - [to] have been banned by [actor]' - tempbaniprange: - notify: '&6[from] - [to] has been temporarily banned for [expires] by [actor]' - ip: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires - in [expires]' - kick: '&6You have been temporarily banned for [expires] by [actor] for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - unbaniprange: - notify: '&6[from] - [to] has been unbanned by [actor]' - banipall: - notify: '&6[ip] will be permanently banned by [actor] for &4[reason]' - tempbanip: - ip: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires - in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[ip] ([players]) has been temporarily banned for [expires] by [actor] - for &4[reason]' - tempbanipall: - notify: '&6[ip] will be temporarily banned for [expires] by [actor] for &4[reason]' - unbanip: - notify: '&6[ip] has been unbanned by [actor]' - error: - noExists: '&c[ip] is not banned' - notOwn: '&c[ip] was not banned by you, unable to unban' - unbanipall: - notify: '&6[ip] will be unbanned by [actor]' - warn: - player: - warned: '&6You have been warned by [actor] for &4[reason]' - disallowed: - header: '&cYou may not speak until you have accepted your most recent warning. - Please type the following:' - reason: '&6[reason]' - removed: '&aThank you for your understanding, you may now speak again' - notify: '&6[player] has been warned by [actor] for &4[reason]' - error: - cooldown: '&cThis player was warned too recently, try again later' - tempwarn: - player: - warned: '&6You have been warned for [expires] by [actor] for &4[reason]' - notify: '&6[player] has been warned for [expires] by [actor] for &4[reason]' - dwarn: - player: - notify: '&6Your most recent warning has been deleted by &4[actor]' - notify: '&cThe most recent warning for [player] has been deleted' - error: - noWarnings: '&c[player] has no warnings to delete' - bmclear: - notify: '&c[player] has had their [type] cleared' - error: - invalid: '&cInvalid type, please choose between banrecords, muterecords, kicks, - notes or warnings' - bmutils: - missingplayers: - notify: '&c[amount] missing players added' - noneFound: '&a0 missing players found' - found: '&c[amount] missing player data found. Fixing...' - error: - failedLookup: '&cFailed to lookup player [uuid], check server logs' - complete: '&a[amount] players resolved, please restart your server for failed - punishments to take affect' - duplicates: - lookup: - notFound: '&aNo duplicate player names found' - error: - invalidName: '&cInvalid name, must be 16 characters or less and contain only - letters, numbers and an underscore' - nameExists: '&cA player with that name already exists' - success: '&aPlayer name set to [player] successfully' - bmrollback: - notify: '&c[player] has had their [type] actions undone' - error: - invalid: '&cInvalid type [type], please choose between [types]' - sync: - player: - started: '&aStarting force [type] synchronisation' - finished: '&aForced [type] synchronisation complete' - update: - notify: '&6[BanManager] &aAn update is available' - notes: - header: '&6[player] has the following notes:' - joinAmount: '&6[player] has &e[amount] &6notes, click to view them' - note: '&6[[player]] &e[message] - &e[created]' - playerNote: '&a[[player]] &6[[actor]] &e[message] - &e[created]' - dateTimeFormat: dd-MM-yyyy - notify: '[player] has a new note attached by [actor]: [message]' - error: - noNotes: '&c[player] has no notes' - noOnlineNotes: '&cNo online players have notes' - report: - notify: '&6[player] has been reported by [actor] for &4[reason]' - error: - cooldown: '&cThis player was reported too recently, try again later' - assign: - player: '&aReport [id] assigned to [player]' - notify: '&aYou have been assigned report [id] by [actor]' - unassign: - player: '&aReport [id] unassigned' - close: - notify: - closed: '&aReport [id] closed by [actor]' - command: '&aReport [id] closed by [actor] with [command]' - comment: '&aReport [id] closed by [actor] with [comment]' - dispatch: Executing command [command] - list: - noResults: '&cNo reports found' - error: - invalidState: '&cReport state [state] not found' - row: - dateTimeFormat: yyyy-MM-dd HH:mm:ss - header: '&e-- Reports ([count]) -- Page ([page]/[maxPage])' - all: '&7#[id] &e[[state]] &6- [created] - [player]' - tp: - error: - notFound: '&cReport not found' - worldNotFound: '&cWorld [world] could not be found' - invalidId: '&c[id] is not a valid report id' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: - report: '&7#[id] &6[actor] reported [player] for &4[reason]&6 at [created]' - location: '[world] - [x], [y], [z]' - info: - error: - notFound: '&cReport not found' - invalidId: '&c[id] is not a valid report id' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: - report: '&7#[id] &6[actor] reported [player] for &4[reason]&6 at [created]' - location: '[world] - [x], [y], [z]' - addnoteall: - notify: '&c[player] will have a new attached by [actor]: [message]' - banlist: - header: '&6There are [bans] [type] bans:' - bmactivity: - row: - all: '&a[&f[type]&a] &6[player]&f - &6[actor]&f - &e[created]' - player: '&a[&f[type]&a] &6[player]&f - &e[created]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - noResults: '&cNo results found' - bmdelete: - notify: '&a[rows] rows deleted' - error: - invalid: '&cInvalid type, please choose between banrecords, muterecords, kicks, - notes or warnings' - invalidId: '&c[id] is not a valid number' - denyalts: - player: - disallowed: '&cThe IP address you are joining from is linked to a banned player' - reasons: - row: '[hashtag] = [reason]' diff --git a/e2e/platforms/bungee/configs/banmanager/messages/messages_de.yml b/e2e/platforms/bungee/configs/banmanager/messages/messages_de.yml new file mode 100644 index 000000000..d813fecbc --- /dev/null +++ b/e2e/platforms/bungee/configs/banmanager/messages/messages_de.yml @@ -0,0 +1,16 @@ +messages: + configReloaded: '&aKonfiguration erfolgreich neu geladen!' + + ban: + player: + disallowed: '&6Du wurdest von diesem Server gebannt wegen &4[reason]' + kick: '&6Du wurdest dauerhaft gebannt wegen &4[reason]' + notify: '&6[player] wurde dauerhaft gebannt von [actor] wegen &4[reason]' + + unban: + notify: '&6[player] wurde von [actor] entbannt' + + mute: + player: + disallowed: '&6Du bist stummgeschaltet wegen &4[reason]' + notify: '&6[player] wurde dauerhaft stummgeschaltet von [actor] wegen &4[reason]' diff --git a/e2e/platforms/bungee/configs/banmanager/messages/messages_en.yml b/e2e/platforms/bungee/configs/banmanager/messages/messages_en.yml new file mode 100644 index 000000000..9da20bc47 --- /dev/null +++ b/e2e/platforms/bungee/configs/banmanager/messages/messages_en.yml @@ -0,0 +1,474 @@ +# Message templates use MiniMessage formatting: https://docs.advntr.dev/minimessage/format.html +# Placeholders use angle brackets, e.g. , , , , + +tokens: + appeal_url: 'https://yourdomain.com/appeal' + server_name: 'My Server' + discord_url: 'https://discord.gg/example' + rules_url: 'https://yourdomain.com/rules' + +messages: + duplicateIP: 'Warning: has the same IP as the following banned players:\n' + duplicateIPAlts: 'Warning: has the same IP as the following players:\n' + configReloaded: 'Configuration reloaded successfully!' + deniedNotify: + player: 'Warning: attempted to join the server but was denied due to ' + ip: 'Warning: attempted to join the server but was denied due to ' + deniedMaxIp: 'Too many players with your ip address online' + deniedMultiaccounts: 'Too many players with your ip address logged in recently' + deniedCountry: 'You may not connect from your region' + + time: + now: 'now' + year: 'year' + years: 'years' + month: 'month' + months: 'months' + week: 'week' + weeks: 'weeks' + day: 'day' + days: 'days' + hour: 'hour' + hours: 'hours' + minute: 'minute' + minutes: 'minutes' + second: 'second' + seconds: 'seconds' + never: 'never' + error: + invalid: 'Your time length is invalid' + limit: 'You cannot perform this action for that length of time' + + none: 'none' + # General command text + sender: + error: + notFound: ' not found, are you sure they exist?' + offline: ' is offline' + noSelf: 'You cannot perform that action on yourself!' + exception: 'An error occured whilst attempting to perform this command. Please check the console for further details.' + invalidIp: 'Invalid IP address, expecting w.x.y.z format' + offlinePermission: 'You are not allowed to perform this action on an offline player' + ambiguousPlayer: 'Multiple players match "". Please use their full name.' + exempt: ' is exempt from that action' + noPermission: 'You do not have permission to perform that action' + noConsole: 'This command cannot be used from console' + invalidReason: ' is not a valid reason.' + # Commands + alts: + header: 'Possible alts found:' + entry: '">' + separator: ', ' + + names: + header: 'Known names for :' + row: ' (first: , last: )' + interactive: ' (first: , last: )">">' + separator: ', ' + dateTimeFormat: 'dd-MM-yyyy' + none: 'No name history found' + + export: + error: + inProgress: 'An export is already in progress, please wait' + player: + started: 'Player ban export started' + finished: 'Player ban export finished, file created' + ip: + started: 'IP ban export started' + finished: 'IP ban export finished, file created' + + import: + error: + inProgress: 'An import is already in progress, please wait' + player: + started: 'Player ban import started' + finished: 'Player ban import finished' + ip: + started: 'IP ban import started' + finished: 'IP ban import finished' + advancedban: + started: 'AdvancedBan import started' + finished: 'AdvancedBan import finished' + h2: + started: 'H2 import started' + finished: 'H2 import finished, please restart the server' + litebans: + started: 'LiteBans import started' + finished: 'LiteBans import finished' + + info: + error: + invalidIndex: 'Invalid player option used' + indexRequired: 'Multiple players named found, please select a player by providing an index between 1 and , e.g. /bminfo 1' + index: '# - - ' + stats: + player: ' has been banned times, muted times, kicked times and warned + times ( Points), has notes and been reported times' + ip: 'This ip has been banned times, muted times and range banned times' + connection: 'Their last connection was with on ' + geoip: 'Country: City: ' + ban: + permanent: 'Currently banned for by at ' + temporary: 'Currently banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + ipban: + permanent: 'Currently banned for by at ' + temporary: 'Currently banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + iprangeban: + permanent: ' - banned for by at ' + temporary: ' - banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + ipmute: + permanent: 'Currently muted for by at ' + temporary: 'Currently muted for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + mute: + permanent: 'Currently muted for by at ' + temporary: 'Currently muted for by at which expires in ' + temporaryOnline: 'Currently muted for by at which expires in (online time)' + temporaryOnlinePaused: 'Currently muted for by at with remaining (online time, paused)' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + website: + player: 'https://yourdomain.com/player/' + ip: 'http://yourdomain.com/index.php?action=viewip&ip=&server=0' + history: + row: '# [] - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + noResults: 'No results found' + ips: + row: ' - - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + + kick: + player: + noReason: 'You have been kicked' + reason: 'You have been kicked for ' + notify: + noReason: ' has been kicked by ">View player info">[Info]' + reason: ' has been kicked by for ">View player info">[Info]' + + kickall: + player: + noReason: 'You have been kicked' + reason: 'You have been kicked for ' + notify: + noReason: 'All players have been kicked by ' + reason: 'All players have been kicked by for ' + + ban: + player: + disallowed: 'You are banned from this server\n \nReason: \nBanned by: \nDate: \n \nAppeal at ' + kick: 'You have been banned\n \nReason: \nBanned by: \nDate: \n \nAppeal at ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' has been permanently banned by for ">View player info">[Info] ">Unban player">[Unban]' + error: + exists: ' is already banned' + cooldown: 'This player was banned too recently, try again later' + + banall: + notify: ' will be permanently banned by for ' + + tempban: + player: + disallowed: 'You are temporarily banned from this server\n \nReason: \nBanned by: \nExpires: \nDate: \n \nAppeal at ' + kick: 'You have been temporarily banned\n \nReason: \nBanned by: \nExpires: \nDate: \n \nAppeal at ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' has been temporarily banned for by for ">View player info">[Info] ">Unban player">[Unban]' + + tempbanall: + notify: ' will be temporarily banned for by for ' + + unban: + notify: ' has been unbanned by ' + error: + noExists: ' is not banned' + notOwn: ' was not banned by you, unable to unban' + + unbanall: + notify: ' will be unbanned by ' + + mute: + player: + blocked: 'You may not use the command whilst muted!' + disallowed: 'You have been permanently muted for by ' + broadcast: '[Muted] ' + notify: ' has been permanently muted by for ">View player info">[Info] ">Unmute player">[Unmute]' + error: + exists: ' is already muted' + cooldown: 'This player was muted too recently, try again later' + + muteip: + ip: + disallowed: 'You have been permanently muted for by ' + broadcast: '[Muted] ' + notify: ' () have been permanently muted by for ' + error: + exists: ' is already muted' + + muteall: + notify: ' will be permanently muted by for ' + + tempmute: + player: + disallowed: 'You have been temporarily muted for by which expires in ' + disallowedOnline: 'You have been temporarily muted for by which expires in (online time)' + notify: ' has been temporarily muted for by for ">View player info">[Info] ">Unmute player">[Unmute]' + notifyOnline: ' has been temporarily muted for (online time) by for ' + error: + exists: ' is already muted' + + tempmuteip: + ip: + disallowed: 'You have been temporarily muted for by which expires in ' + notify: ' () have been temporarily muted for by for ' + error: + exists: ' is already muted' + + tempmuteall: + notify: ' will be temporarily muted for by for ' + + unmute: + notify: ' has been unmuted by ' + player: 'You have been unmuted by ' + error: + noExists: ' is not muted' + notOwn: ' was not muted by you, unable to unmute' + + unmuteip: + notify: ' has been unmuted by ' + error: + noExists: ' is not muted' + notOwn: ' was not muted by you, unable to unmute' + + unmuteall: + notify: ' will be unmuted by ' + + banname: + name: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: 'Name has been permanently banned by for ' + error: + exists: 'Name is already banned' + + tempbanname: + name: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: 'Name has been temporarily banned for by for ' + + unbanname: + notify: 'Name has been unbanned by ' + error: + noExists: 'Name is not banned' + + banip: + ip: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' () has been permanently banned by for ' + error: + exists: ' is already banned' + cooldown: 'This ip was banned too recently, try again later' + + baniprange: + error: + invalid: 'Invalid range, please use cidr notation 192.168.0.1/16 or wildcard 192.168.*.*' + minMax: 'Range must be lowest to highest' + exists: 'A ban containing those ranges already exists' + ip: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' - have been banned by ' + + tempbaniprange: + notify: ' - has been temporarily banned for by ' + ip: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for by for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + + unbaniprange: + notify: ' - has been unbanned by ' + + banipall: + notify: ' will be permanently banned by for ' + + tempbanip: + ip: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' () has been temporarily banned for by for ' + + tempbanipall: + notify: ' will be temporarily banned for by for ' + + unbanip: + notify: ' has been unbanned by ' + error: + noExists: ' is not banned' + notOwn: ' was not banned by you, unable to unban' + + unbanipall: + notify: ' will be unbanned by ' + + warn: + player: + warned: 'You have been warned by for ' + disallowed: + header: 'You may not speak until you have accepted your most recent warning. Please type the following:' + reason: '' + removed: 'Thank you for your understanding, you may now speak again' + notify: ' has been warned by for ">View player info">[Info]' + error: + cooldown: 'This player was warned too recently, try again later' + + tempwarn: + player: + warned: 'You have been warned for by for ' + notify: ' has been warned for by for ">View player info">[Info]' + + dwarn: + player: + notify: 'Your most recent warning has been deleted by ' + notify: 'The most recent warning for has been deleted' + error: + noWarnings: ' has no warnings to delete' + + bmclear: + notify: ' has had their cleared' + error: + invalid: 'Invalid type, please choose between banrecords, muterecords, kicks, notes or warnings' + + bmutils: + missingplayers: + notify: ' missing players added' + noneFound: '0 missing players found' + found: ' missing player data found. Fixing...' + error: + failedLookup: 'Failed to lookup player , check server logs' + complete: ' players resolved, please restart your server for failed punishments to take affect' + duplicates: + lookup: + notFound: 'No duplicate player names found' + error: + invalidName: 'Invalid name, must be 16 characters or less and contain only letters, numbers and an underscore' + nameExists: 'A player with that name already exists' + success: 'Player name set to successfully' + + bmrollback: + notify: ' has had their actions undone' + error: + invalid: 'Invalid type , please choose between ' + + sync: + player: + started: 'Starting force synchronisation' + finished: 'Forced synchronisation complete' + + update: + notify: '[BanManager] An update is available' + + notes: + header: ' has the following notes:' + joinAmount: '"> has notes, click to view them' + note: '[] - ' + playerNote: '[] [] - ' + dateTimeFormat: 'dd-MM-yyyy' + notify: ' has a new note attached by : ' + error: + noNotes: ' has no notes' + noOnlineNotes: 'No online players have notes' + + report: + notify: ' has been reported by for ' + error: + cooldown: 'This player was reported too recently, try again later' + assign: + player: 'Report assigned to ' + notify: 'You have been assigned report by ' + unassign: + player: 'Report unassigned' + close: + notify: + closed: 'Report closed by ' + command: 'Report closed by with ' + comment: 'Report closed by with ' + dispatch: 'Executing command ' + list: + noResults: 'No reports found' + error: + invalidState: 'Report state not found' + row: + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + header: '-- Reports () -- Page (/)' + all: '">Click to view details"># [] - - ' + tp: + error: + notFound: 'Report not found' + worldNotFound: 'World could not be found' + invalidId: ' is not a valid report id' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: + report: '# reported for at ' + location: ' - , , ' + info: + error: + notFound: 'Report not found' + invalidId: ' is not a valid report id' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: + report: '# reported for at ' + location: ' - , , ' + actions: + assign: '">Assign to yourself">[Assign]' + close: '">Close this report">[Close]' + tp: '">Teleport to location">[TP]' + feedback: + assigned: 'Your report # has been assigned to ' + closed: 'Your report # has been closed by ' + + addnoteall: + notify: ' will have a new note attached by : ' + + banlist: + header: 'There are bans:' + row: + player: '">Click for info"> - ' + ip: ' - ' + iprange: ' - - ' + + bmactivity: + row: + all: '[] - - ' + player: '[] - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + noResults: 'No results found' + + bmdelete: + notify: ' rows deleted' + error: + invalid: 'Invalid type, please choose between banrecords, muterecords, kicks, notes or warnings' + invalidId: ' is not a valid number' + + denyalts: + player: + disallowed: 'The IP address you are joining from is linked to a banned player' + + reasons: + row: ' = ' + + dashboard: + header: ' Staff Dashboard ' + activeBans: 'Active Bans: ' + activeMutes: 'Active Mutes: ' + openReports: 'Open Reports: View reports">[View]' + recentActivity: 'Recent Activity (24h): ' + footer: ' ' diff --git a/e2e/platforms/bungee/configs/banmanager/notifications.yml b/e2e/platforms/bungee/configs/banmanager/notifications.yml new file mode 100644 index 000000000..75b1fb646 --- /dev/null +++ b/e2e/platforms/bungee/configs/banmanager/notifications.yml @@ -0,0 +1,81 @@ +# Notifications Configuration +# Controls how punishment notifications are delivered to staff and players +# +# Each notification event can specify delivery channels: +# chat: true/false - Send via chat message (default: true) +# actionbar: true/false - Send via action bar (disappears after a few seconds) +# title: true/false - Send via title/subtitle overlay +# sound: '' - Sound to play (empty to disable). Use Minecraft sound names e.g. entity.experience_orb.pickup +# +# Title settings (only used when title: true): +# titleFadeIn: ticks for fade in (20 ticks = 1 second) +# titleStay: ticks to stay on screen +# titleFadeOut: ticks for fade out +# +# Sound settings: +# soundVolume: 0.0 - 1.0 +# soundPitch: 0.0 - 2.0 +# +# Platform notes: +# - BungeeCord: title, showTitle and playSound are not supported (ignored silently) +# - Sponge API7: playSound is not supported (ignored silently) +# - All other platforms (Bukkit/Paper, Velocity, Fabric, Sponge API8+) support all channels + +staff: + ban: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + tempban: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + mute: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + tempmute: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + warn: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + report: + chat: true + actionbar: false + title: false + sound: 'block.note_block.pling' + soundVolume: 1.0 + soundPitch: 1.0 + duplicateIp: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + +player: + muted: + actionbar: true + warned: + sound: 'entity.villager.no' + soundVolume: 1.0 + soundPitch: 1.0 diff --git a/e2e/platforms/fabric/configs/config.yml b/e2e/platforms/fabric/configs/config.yml index c9a784112..b8ac0e3a3 100644 --- a/e2e/platforms/fabric/configs/config.yml +++ b/e2e/platforms/fabric/configs/config.yml @@ -1,3 +1,7 @@ +locale: + default: en + perPlayer: true + debug: false databases: local: diff --git a/e2e/platforms/fabric/configs/messages.yml b/e2e/platforms/fabric/configs/messages.yml deleted file mode 100644 index 09382e935..000000000 --- a/e2e/platforms/fabric/configs/messages.yml +++ /dev/null @@ -1,441 +0,0 @@ -# Variables -# [reason] = Ban/Mute reason -# [player] = The name of the player -# [ip] = The banned ip -# [actor] = Who banned/muted -# [expires] = How long until the ban/mute ends - -messages: - duplicateIP: '&cWarning: [player] has the same IP as the following banned players:\n&6[players]' - duplicateIPAlts: '&cWarning: [player] has the same IP as the following players:\n&6[players]' - configReloaded: '�ff00Configuration &#ff5733reloaded &asuccessfully!' - deniedNotify: - player: '&cWarning: [player] attempted to join the server but was denied due to &4[reason]' - ip: '&cWarning: [ip] attempted to join the server but was denied due to &4[reason]' - deniedMaxIp: '&cToo many players with your ip address online' - deniedMultiaccounts: '&cToo many players with your ip address logged in recently' - deniedCountry: '&cYou may not connect from your region' - - time: - now: 'now' - year: 'year' - years: 'years' - month: 'month' - months: 'months' - week: 'week' - weeks: 'weeks' - day: 'day' - days: 'days' - hour: 'hour' - hours: 'hours' - minute: 'minute' - minutes: 'minutes' - second: 'second' - seconds: 'seconds' - never: 'never' - error: - invalid: '&cYour time length is invalid' - limit: '&cYou cannot perform this action for that length of time' - - none: 'none' - # General command text - sender: - error: - notFound: '&c[player] not found, are you sure they exist?' - offline: '&c[player] is offline' - noSelf: '&cYou cannot perform that action on yourself!' - exception: '&cAn error occured whilst attempting to perform this command. Please check the console for further details.' - invalidIp: '&cInvalid IP address, expecting w.x.y.z format' - offlinePermission: '&cYou are not allowed to perform this action on an offline player' - exempt: '&c[player] is exempt from that action' - noPermission: '&cYou do not have permission to perform that action' - invalidReason: '&c[reason] is no valid reason.' - # Commands - alts: - header: 'Possible alts found:' - - export: - error: - inProgress: '&cAn export is already in progress, please wait' - player: - started: '&aPlayer ban export started' - finished: '&aPlayer ban export finished, file [file] created' - ip: - started: '&aIP ban export started' - finished: '&aIP ban export finished, file [file] created' - - import: - error: - inProgress: '&cAn import is already in progress, please wait' - player: - started: '&aPlayer ban import started' - finished: '&aPlayer ban import finished' - ip: - started: '&aIP ban import started' - finished: '&aIP ban import finished' - advancedban: - started: '&aAdvancedBan import started' - finished: '&aAdvancedBan import finished' - h2: - started: '&aH2 import started' - finished: '&aH2 import finished, please restart the server' - litebans: - started: '&aLiteBans import started' - finished: '&aLiteBans import finished' - - info: - error: - invalidIndex: '&cInvalid player option used' - indexRequired: '&cMultiple players named [name] found, please select a player by providing an index between 1 and [size], e.g. /bminfo [name] 1' - index: '&7#[index] - &6[name] - &4[uuid]' - stats: - player: '&6[player] has been banned [bans] times, muted [mutes] times, kicked [kicks] times and warned [warns] - times ([warnPoints] Points), has [notes] notes and been reported [reports] times' - ip: '&6This ip has been banned [bans] times, muted [mutes] times and range banned [rangebans] times' - connection: '&6Their last connection was with [ip] on [lastSeen]' - geoip: 'Country: [country] City: [city]' - ban: - permanent: '&6Currently banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently banned for &4[reason]&6 by [actor] at [created] which expires in [expires]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - ipban: - permanent: '&6Currently banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently banned for &4[reason]&6 by [actor] at [created] which expires in [expires]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - iprangeban: - permanent: '&6[from] - [to] banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6[from] - [to] banned for &4[reason]&6 by [actor] at [created] which expires in [expires]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - ipmute: - permanent: '&6Currently muted for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently muted for &4[reason]&6 by [actor] at [created] which expires in [expires]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - mute: - permanent: '&6Currently muted for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently muted for &4[reason]&6 by [actor] at [created] which expires in [expires]' - temporaryOnline: '&6Currently muted for &4[reason]&6 by [actor] at [created] which expires in [expires] (online time)' - temporaryOnlinePaused: '&6Currently muted for &4[reason]&6 by [actor] at [created] with [remaining] remaining (online time, paused)' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - website: - player: 'https://yourdomain.com/player/[uuid]' - ip: 'http://yourdomain.com/index.php?action=viewip&ip=[ip]&server=0' - history: - row: '&7#[id] &a[&f[type]&a] &6[actor]&f [meta] [reason] - &e[created]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - noResults: '&cNo results found' - ips: - row: '&e[ip] - &6[join] - [leave]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - - kick: - player: - noReason: '&6You have been kicked' - reason: '&6You have been kicked for &4[reason]' - notify: - noReason: '&6[player] has been kicked by [actor]' - reason: '&6[player] has been kicked by [actor] for &4[reason]' - - kickall: - player: - noReason: '&6You have been kicked' - reason: '&6You have been kicked for &4[reason]' - notify: - noReason: 'All players have been kicked by [actor]' - reason: 'All players have been kicked by [actor] for &4[reason]' - - ban: - player: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6[player] has been permanently banned by [actor] for &4[reason]' - error: - exists: '&c[player] is already banned' - cooldown: '&cThis player was banned too recently, try again later' - - banall: - notify: '&6[player] will be permanently banned by [actor] for &4[reason]' - - tempban: - player: - disallowed: '&6You have been temporarily banned from this server for &4[reason] \n&6It expires in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6[player] has been temporarily banned for [expires] by [actor] for &4[reason]' - - tempbanall: - notify: '&6[player] will be temporarily banned for [expires] by [actor] for &4[reason]' - - unban: - notify: '&6[player] has been unbanned by [actor]' - error: - noExists: '&c[player] is not banned' - notOwn: '&c[player] was not banned by you, unable to unban' - - unbanall: - notify: '&6[player] will be unbanned by [actor]' - - mute: - player: - blocked: '&cYou may not use the [command] command whilst muted!' - disallowed: '&6You have been permanently muted for &4[reason] &6by [actor]' - broadcast: '&4[Muted] [player]&7 [message]' - notify: '&6[player] has been permanently muted by [actor] for &4[reason]' - error: - exists: '&c[player] is already muted' - cooldown: '&cThis player was muted too recently, try again later' - - muteip: - ip: - disallowed: '&6You have been permanently muted for &4[reason] &6by [actor]' - broadcast: '&4[Muted] [player]&7 [message]' - notify: '&6[ip] ([players]) have been permanently muted by [actor] for &4[reason]' - error: - exists: '&c[ip] is already muted' - - muteall: - notify: '&6[player] will be permanently muted by [actor] for &4[reason]' - - tempmute: - player: - disallowed: '&6You have been temporarily muted for &4[reason] &6by [actor] which expires in [expires]' - disallowedOnline: '&6You have been temporarily muted for &4[reason] &6by [actor] which expires in [expires] (online time)' - notify: '&6[player] has been temporarily muted for [expires] by [actor] for &4[reason]' - notifyOnline: '&6[player] has been temporarily muted for [expires] (online time) by [actor] for &4[reason]' - error: - exists: '&c[player] is already muted' - - tempmuteip: - ip: - disallowed: '&6You have been temporarily muted for &4[reason] &6by [actor] which expires in [expires]' - notify: '&6[ip] ([players]) have been temporarily muted for [expires] by [actor] for &4[reason]' - error: - exists: '&c[ip] is already muted' - - tempmuteall: - notify: '&6[player] will be temporarily muted for [expires] by [actor] for &4[reason]' - - unmute: - notify: '&6[player] has been unmuted by [actor]' - player: '&6You have been unmuted by [actor]' - error: - noExists: '&c[player] is not muted' - notOwn: '&c[player] was not muted by you, unable to unmute' - - unmuteip: - notify: '&6[ip] has been unmuted by [actor]' - error: - noExists: '&c[ip] is not muted' - notOwn: '&c[ip] was not muted by you, unable to unmute' - - unmuteall: - notify: '&6[player] will be unmuted by [actor]' - - banname: - name: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6Name [name] has been permanently banned by [actor] for &4[reason]' - error: - exists: '&cName [name] is already banned' - - tempbanname: - name: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6Name [name] has been temporarily banned for [expires] by [actor] for &4[reason]' - - unbanname: - notify: '&6Name [name] has been unbanned by [actor]' - error: - noExists: '&cName [name] is not banned' - - banip: - ip: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6[ip] ([players]) has been permanently banned by [actor] for &4[reason]' - error: - exists: '&c[ip] is already banned' - cooldown: '&cThis ip was banned too recently, try again later' - - baniprange: - error: - invalid: '&cInvalid range, please use cidr notation 192.168.0.1/16 or wildcard 192.168.*.*' - minMax: '&cRange must be lowest to highest' - exists: '&cA ban containing those ranges already exists' - ip: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6[from] - [to] have been banned by [actor]' - - tempbaniprange: - notify: '&6[from] - [to] has been temporarily banned for [expires] by [actor]' - ip: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires in [expires]' - kick: '&6You have been temporarily banned for [expires] by [actor] for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - - unbaniprange: - notify: '&6[from] - [to] has been unbanned by [actor]' - - banipall: - notify: '&6[ip] will be permanently banned by [actor] for &4[reason]' - - tempbanip: - ip: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: '&6[ip] ([players]) has been temporarily banned for [expires] by [actor] for &4[reason]' - - tempbanipall: - notify: '&6[ip] will be temporarily banned for [expires] by [actor] for &4[reason]' - - unbanip: - notify: '&6[ip] has been unbanned by [actor]' - error: - noExists: '&c[ip] is not banned' - notOwn: '&c[ip] was not banned by you, unable to unban' - - unbanipall: - notify: '&6[ip] will be unbanned by [actor]' - - warn: - player: - warned: '&6You have been warned by [actor] for &4[reason]' - disallowed: - header: '&cYou may not speak until you have accepted your most recent warning. Please type the following:' - reason: '&6[reason]' - removed: '&aThank you for your understanding, you may now speak again' - notify: '&6[player] has been warned by [actor] for &4[reason]' - error: - cooldown: '&cThis player was warned too recently, try again later' - - tempwarn: - player: - warned: '&6You have been warned for [expires] by [actor] for &4[reason]' - notify: '&6[player] has been warned for [expires] by [actor] for &4[reason]' - - dwarn: - player: - notify: '&6Your most recent warning has been deleted by &4[actor]' - notify: '&cThe most recent warning for [player] has been deleted' - error: - noWarnings: '&c[player] has no warnings to delete' - - bmclear: - notify: '&c[player] has had their [type] cleared' - error: - invalid: '&cInvalid type, please choose between banrecords, muterecords, kicks, notes or warnings' - - bmutils: - missingplayers: - notify: '&c[amount] missing players added' - noneFound: '&a0 missing players found' - found: '&c[amount] missing player data found. Fixing...' - error: - failedLookup: '&cFailed to lookup player [uuid], check server logs' - complete: '&a[amount] players resolved, please restart your server for failed punishments to take affect' - duplicates: - lookup: - notFound: '&aNo duplicate player names found' - error: - invalidName: '&cInvalid name, must be 16 characters or less and contain only letters, numbers and an underscore' - nameExists: '&cA player with that name already exists' - success: '&aPlayer name set to [player] successfully' - - bmrollback: - notify: '&c[player] has had their [type] actions undone' - error: - invalid: '&cInvalid type [type], please choose between [types]' - - sync: - player: - started: '&aStarting force [type] synchronisation' - finished: '&aForced [type] synchronisation complete' - - update: - notify: '&6[BanManager] &aAn update is available' - - notes: - header: '&6[player] has the following notes:' - joinAmount: '&6[player] has &e[amount] &6notes, click to view them' - note: '&6[[player]] &e[message] - &e[created]' - playerNote: '&a[[player]] &6[[actor]] &e[message] - &e[created]' - dateTimeFormat: 'dd-MM-yyyy' - notify: '[player] has a new note attached by [actor]: [message]' - error: - noNotes: '&c[player] has no notes' - noOnlineNotes: '&cNo online players have notes' - - report: - notify: '&6[player] has been reported by [actor] for &4[reason]' - error: - cooldown: '&cThis player was reported too recently, try again later' - assign: - player: '&aReport [id] assigned to [player]' - notify: '&aYou have been assigned report [id] by [actor]' - unassign: - player: '&aReport [id] unassigned' - close: - notify: - closed: '&aReport [id] closed by [actor]' - command: '&aReport [id] closed by [actor] with [command]' - comment: '&aReport [id] closed by [actor] with [comment]' - dispatch: 'Executing command [command]' - list: - noResults: '&cNo reports found' - error: - invalidState: '&cReport state [state] not found' - row: - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - header: '&e-- Reports ([count]) -- Page ([page]/[maxPage])' - all: '&7#[id] &e[[state]] &6- [created] - [player]' - tp: - error: - notFound: '&cReport not found' - worldNotFound: '&cWorld [world] could not be found' - invalidId: '&c[id] is not a valid report id' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: - report: '&7#[id] &6[actor] reported [player] for &4[reason]&6 at [created]' - location: '[world] - [x], [y], [z]' - info: - error: - notFound: '&cReport not found' - invalidId: '&c[id] is not a valid report id' - dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' - notify: - report: '&7#[id] &6[actor] reported [player] for &4[reason]&6 at [created]' - location: '[world] - [x], [y], [z]' - - addnoteall: - notify: '&c[player] will have a new attached by [actor]: [message]' - - banlist: - header: '&6There are [bans] [type] bans:' - - bmactivity: - row: - all: '&a[&f[type]&a] &6[player]&f - &6[actor]&f - &e[created]' - player: '&a[&f[type]&a] &6[player]&f - &e[created]' - dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' - noResults: '&cNo results found' - - bmdelete: - notify: '&a[rows] rows deleted' - error: - invalid: '&cInvalid type, please choose between banrecords, muterecords, kicks, notes or warnings' - invalidId: '&c[id] is not a valid number' - - denyalts: - player: - disallowed: '&cThe IP address you are joining from is linked to a banned player' - - reasons: - row: '[hashtag] = [reason]' diff --git a/e2e/platforms/fabric/configs/messages/messages_de.yml b/e2e/platforms/fabric/configs/messages/messages_de.yml new file mode 100644 index 000000000..d813fecbc --- /dev/null +++ b/e2e/platforms/fabric/configs/messages/messages_de.yml @@ -0,0 +1,16 @@ +messages: + configReloaded: '&aKonfiguration erfolgreich neu geladen!' + + ban: + player: + disallowed: '&6Du wurdest von diesem Server gebannt wegen &4[reason]' + kick: '&6Du wurdest dauerhaft gebannt wegen &4[reason]' + notify: '&6[player] wurde dauerhaft gebannt von [actor] wegen &4[reason]' + + unban: + notify: '&6[player] wurde von [actor] entbannt' + + mute: + player: + disallowed: '&6Du bist stummgeschaltet wegen &4[reason]' + notify: '&6[player] wurde dauerhaft stummgeschaltet von [actor] wegen &4[reason]' diff --git a/e2e/platforms/fabric/configs/messages/messages_en.yml b/e2e/platforms/fabric/configs/messages/messages_en.yml new file mode 100644 index 000000000..9da20bc47 --- /dev/null +++ b/e2e/platforms/fabric/configs/messages/messages_en.yml @@ -0,0 +1,474 @@ +# Message templates use MiniMessage formatting: https://docs.advntr.dev/minimessage/format.html +# Placeholders use angle brackets, e.g. , , , , + +tokens: + appeal_url: 'https://yourdomain.com/appeal' + server_name: 'My Server' + discord_url: 'https://discord.gg/example' + rules_url: 'https://yourdomain.com/rules' + +messages: + duplicateIP: 'Warning: has the same IP as the following banned players:\n' + duplicateIPAlts: 'Warning: has the same IP as the following players:\n' + configReloaded: 'Configuration reloaded successfully!' + deniedNotify: + player: 'Warning: attempted to join the server but was denied due to ' + ip: 'Warning: attempted to join the server but was denied due to ' + deniedMaxIp: 'Too many players with your ip address online' + deniedMultiaccounts: 'Too many players with your ip address logged in recently' + deniedCountry: 'You may not connect from your region' + + time: + now: 'now' + year: 'year' + years: 'years' + month: 'month' + months: 'months' + week: 'week' + weeks: 'weeks' + day: 'day' + days: 'days' + hour: 'hour' + hours: 'hours' + minute: 'minute' + minutes: 'minutes' + second: 'second' + seconds: 'seconds' + never: 'never' + error: + invalid: 'Your time length is invalid' + limit: 'You cannot perform this action for that length of time' + + none: 'none' + # General command text + sender: + error: + notFound: ' not found, are you sure they exist?' + offline: ' is offline' + noSelf: 'You cannot perform that action on yourself!' + exception: 'An error occured whilst attempting to perform this command. Please check the console for further details.' + invalidIp: 'Invalid IP address, expecting w.x.y.z format' + offlinePermission: 'You are not allowed to perform this action on an offline player' + ambiguousPlayer: 'Multiple players match "". Please use their full name.' + exempt: ' is exempt from that action' + noPermission: 'You do not have permission to perform that action' + noConsole: 'This command cannot be used from console' + invalidReason: ' is not a valid reason.' + # Commands + alts: + header: 'Possible alts found:' + entry: '">' + separator: ', ' + + names: + header: 'Known names for :' + row: ' (first: , last: )' + interactive: ' (first: , last: )">">' + separator: ', ' + dateTimeFormat: 'dd-MM-yyyy' + none: 'No name history found' + + export: + error: + inProgress: 'An export is already in progress, please wait' + player: + started: 'Player ban export started' + finished: 'Player ban export finished, file created' + ip: + started: 'IP ban export started' + finished: 'IP ban export finished, file created' + + import: + error: + inProgress: 'An import is already in progress, please wait' + player: + started: 'Player ban import started' + finished: 'Player ban import finished' + ip: + started: 'IP ban import started' + finished: 'IP ban import finished' + advancedban: + started: 'AdvancedBan import started' + finished: 'AdvancedBan import finished' + h2: + started: 'H2 import started' + finished: 'H2 import finished, please restart the server' + litebans: + started: 'LiteBans import started' + finished: 'LiteBans import finished' + + info: + error: + invalidIndex: 'Invalid player option used' + indexRequired: 'Multiple players named found, please select a player by providing an index between 1 and , e.g. /bminfo 1' + index: '# - - ' + stats: + player: ' has been banned times, muted times, kicked times and warned + times ( Points), has notes and been reported times' + ip: 'This ip has been banned times, muted times and range banned times' + connection: 'Their last connection was with on ' + geoip: 'Country: City: ' + ban: + permanent: 'Currently banned for by at ' + temporary: 'Currently banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + ipban: + permanent: 'Currently banned for by at ' + temporary: 'Currently banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + iprangeban: + permanent: ' - banned for by at ' + temporary: ' - banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + ipmute: + permanent: 'Currently muted for by at ' + temporary: 'Currently muted for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + mute: + permanent: 'Currently muted for by at ' + temporary: 'Currently muted for by at which expires in ' + temporaryOnline: 'Currently muted for by at which expires in (online time)' + temporaryOnlinePaused: 'Currently muted for by at with remaining (online time, paused)' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + website: + player: 'https://yourdomain.com/player/' + ip: 'http://yourdomain.com/index.php?action=viewip&ip=&server=0' + history: + row: '# [] - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + noResults: 'No results found' + ips: + row: ' - - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + + kick: + player: + noReason: 'You have been kicked' + reason: 'You have been kicked for ' + notify: + noReason: ' has been kicked by ">View player info">[Info]' + reason: ' has been kicked by for ">View player info">[Info]' + + kickall: + player: + noReason: 'You have been kicked' + reason: 'You have been kicked for ' + notify: + noReason: 'All players have been kicked by ' + reason: 'All players have been kicked by for ' + + ban: + player: + disallowed: 'You are banned from this server\n \nReason: \nBanned by: \nDate: \n \nAppeal at ' + kick: 'You have been banned\n \nReason: \nBanned by: \nDate: \n \nAppeal at ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' has been permanently banned by for ">View player info">[Info] ">Unban player">[Unban]' + error: + exists: ' is already banned' + cooldown: 'This player was banned too recently, try again later' + + banall: + notify: ' will be permanently banned by for ' + + tempban: + player: + disallowed: 'You are temporarily banned from this server\n \nReason: \nBanned by: \nExpires: \nDate: \n \nAppeal at ' + kick: 'You have been temporarily banned\n \nReason: \nBanned by: \nExpires: \nDate: \n \nAppeal at ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' has been temporarily banned for by for ">View player info">[Info] ">Unban player">[Unban]' + + tempbanall: + notify: ' will be temporarily banned for by for ' + + unban: + notify: ' has been unbanned by ' + error: + noExists: ' is not banned' + notOwn: ' was not banned by you, unable to unban' + + unbanall: + notify: ' will be unbanned by ' + + mute: + player: + blocked: 'You may not use the command whilst muted!' + disallowed: 'You have been permanently muted for by ' + broadcast: '[Muted] ' + notify: ' has been permanently muted by for ">View player info">[Info] ">Unmute player">[Unmute]' + error: + exists: ' is already muted' + cooldown: 'This player was muted too recently, try again later' + + muteip: + ip: + disallowed: 'You have been permanently muted for by ' + broadcast: '[Muted] ' + notify: ' () have been permanently muted by for ' + error: + exists: ' is already muted' + + muteall: + notify: ' will be permanently muted by for ' + + tempmute: + player: + disallowed: 'You have been temporarily muted for by which expires in ' + disallowedOnline: 'You have been temporarily muted for by which expires in (online time)' + notify: ' has been temporarily muted for by for ">View player info">[Info] ">Unmute player">[Unmute]' + notifyOnline: ' has been temporarily muted for (online time) by for ' + error: + exists: ' is already muted' + + tempmuteip: + ip: + disallowed: 'You have been temporarily muted for by which expires in ' + notify: ' () have been temporarily muted for by for ' + error: + exists: ' is already muted' + + tempmuteall: + notify: ' will be temporarily muted for by for ' + + unmute: + notify: ' has been unmuted by ' + player: 'You have been unmuted by ' + error: + noExists: ' is not muted' + notOwn: ' was not muted by you, unable to unmute' + + unmuteip: + notify: ' has been unmuted by ' + error: + noExists: ' is not muted' + notOwn: ' was not muted by you, unable to unmute' + + unmuteall: + notify: ' will be unmuted by ' + + banname: + name: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: 'Name has been permanently banned by for ' + error: + exists: 'Name is already banned' + + tempbanname: + name: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: 'Name has been temporarily banned for by for ' + + unbanname: + notify: 'Name has been unbanned by ' + error: + noExists: 'Name is not banned' + + banip: + ip: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' () has been permanently banned by for ' + error: + exists: ' is already banned' + cooldown: 'This ip was banned too recently, try again later' + + baniprange: + error: + invalid: 'Invalid range, please use cidr notation 192.168.0.1/16 or wildcard 192.168.*.*' + minMax: 'Range must be lowest to highest' + exists: 'A ban containing those ranges already exists' + ip: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' - have been banned by ' + + tempbaniprange: + notify: ' - has been temporarily banned for by ' + ip: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for by for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + + unbaniprange: + notify: ' - has been unbanned by ' + + banipall: + notify: ' will be permanently banned by for ' + + tempbanip: + ip: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' () has been temporarily banned for by for ' + + tempbanipall: + notify: ' will be temporarily banned for by for ' + + unbanip: + notify: ' has been unbanned by ' + error: + noExists: ' is not banned' + notOwn: ' was not banned by you, unable to unban' + + unbanipall: + notify: ' will be unbanned by ' + + warn: + player: + warned: 'You have been warned by for ' + disallowed: + header: 'You may not speak until you have accepted your most recent warning. Please type the following:' + reason: '' + removed: 'Thank you for your understanding, you may now speak again' + notify: ' has been warned by for ">View player info">[Info]' + error: + cooldown: 'This player was warned too recently, try again later' + + tempwarn: + player: + warned: 'You have been warned for by for ' + notify: ' has been warned for by for ">View player info">[Info]' + + dwarn: + player: + notify: 'Your most recent warning has been deleted by ' + notify: 'The most recent warning for has been deleted' + error: + noWarnings: ' has no warnings to delete' + + bmclear: + notify: ' has had their cleared' + error: + invalid: 'Invalid type, please choose between banrecords, muterecords, kicks, notes or warnings' + + bmutils: + missingplayers: + notify: ' missing players added' + noneFound: '0 missing players found' + found: ' missing player data found. Fixing...' + error: + failedLookup: 'Failed to lookup player , check server logs' + complete: ' players resolved, please restart your server for failed punishments to take affect' + duplicates: + lookup: + notFound: 'No duplicate player names found' + error: + invalidName: 'Invalid name, must be 16 characters or less and contain only letters, numbers and an underscore' + nameExists: 'A player with that name already exists' + success: 'Player name set to successfully' + + bmrollback: + notify: ' has had their actions undone' + error: + invalid: 'Invalid type , please choose between ' + + sync: + player: + started: 'Starting force synchronisation' + finished: 'Forced synchronisation complete' + + update: + notify: '[BanManager] An update is available' + + notes: + header: ' has the following notes:' + joinAmount: '"> has notes, click to view them' + note: '[] - ' + playerNote: '[] [] - ' + dateTimeFormat: 'dd-MM-yyyy' + notify: ' has a new note attached by : ' + error: + noNotes: ' has no notes' + noOnlineNotes: 'No online players have notes' + + report: + notify: ' has been reported by for ' + error: + cooldown: 'This player was reported too recently, try again later' + assign: + player: 'Report assigned to ' + notify: 'You have been assigned report by ' + unassign: + player: 'Report unassigned' + close: + notify: + closed: 'Report closed by ' + command: 'Report closed by with ' + comment: 'Report closed by with ' + dispatch: 'Executing command ' + list: + noResults: 'No reports found' + error: + invalidState: 'Report state not found' + row: + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + header: '-- Reports () -- Page (/)' + all: '">Click to view details"># [] - - ' + tp: + error: + notFound: 'Report not found' + worldNotFound: 'World could not be found' + invalidId: ' is not a valid report id' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: + report: '# reported for at ' + location: ' - , , ' + info: + error: + notFound: 'Report not found' + invalidId: ' is not a valid report id' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: + report: '# reported for at ' + location: ' - , , ' + actions: + assign: '">Assign to yourself">[Assign]' + close: '">Close this report">[Close]' + tp: '">Teleport to location">[TP]' + feedback: + assigned: 'Your report # has been assigned to ' + closed: 'Your report # has been closed by ' + + addnoteall: + notify: ' will have a new note attached by : ' + + banlist: + header: 'There are bans:' + row: + player: '">Click for info"> - ' + ip: ' - ' + iprange: ' - - ' + + bmactivity: + row: + all: '[] - - ' + player: '[] - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + noResults: 'No results found' + + bmdelete: + notify: ' rows deleted' + error: + invalid: 'Invalid type, please choose between banrecords, muterecords, kicks, notes or warnings' + invalidId: ' is not a valid number' + + denyalts: + player: + disallowed: 'The IP address you are joining from is linked to a banned player' + + reasons: + row: ' = ' + + dashboard: + header: ' Staff Dashboard ' + activeBans: 'Active Bans: ' + activeMutes: 'Active Mutes: ' + openReports: 'Open Reports: View reports">[View]' + recentActivity: 'Recent Activity (24h): ' + footer: ' ' diff --git a/e2e/platforms/fabric/configs/notifications.yml b/e2e/platforms/fabric/configs/notifications.yml new file mode 100644 index 000000000..75b1fb646 --- /dev/null +++ b/e2e/platforms/fabric/configs/notifications.yml @@ -0,0 +1,81 @@ +# Notifications Configuration +# Controls how punishment notifications are delivered to staff and players +# +# Each notification event can specify delivery channels: +# chat: true/false - Send via chat message (default: true) +# actionbar: true/false - Send via action bar (disappears after a few seconds) +# title: true/false - Send via title/subtitle overlay +# sound: '' - Sound to play (empty to disable). Use Minecraft sound names e.g. entity.experience_orb.pickup +# +# Title settings (only used when title: true): +# titleFadeIn: ticks for fade in (20 ticks = 1 second) +# titleStay: ticks to stay on screen +# titleFadeOut: ticks for fade out +# +# Sound settings: +# soundVolume: 0.0 - 1.0 +# soundPitch: 0.0 - 2.0 +# +# Platform notes: +# - BungeeCord: title, showTitle and playSound are not supported (ignored silently) +# - Sponge API7: playSound is not supported (ignored silently) +# - All other platforms (Bukkit/Paper, Velocity, Fabric, Sponge API8+) support all channels + +staff: + ban: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + tempban: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + mute: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + tempmute: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + warn: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + report: + chat: true + actionbar: false + title: false + sound: 'block.note_block.pling' + soundVolume: 1.0 + soundPitch: 1.0 + duplicateIp: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + +player: + muted: + actionbar: true + warned: + sound: 'entity.villager.no' + soundVolume: 1.0 + soundPitch: 1.0 diff --git a/e2e/platforms/sponge/configs/banmanager/config.yml b/e2e/platforms/sponge/configs/banmanager/config.yml index 41de43066..663f077e8 100644 --- a/e2e/platforms/sponge/configs/banmanager/config.yml +++ b/e2e/platforms/sponge/configs/banmanager/config.yml @@ -1,5 +1,9 @@ # # Aliases will be found and blocked automatically, e.g. msg will block tell +locale: + default: en + perPlayer: true + debug: false databases: local: diff --git a/e2e/platforms/sponge/configs/banmanager/messages.yml b/e2e/platforms/sponge/configs/banmanager/messages.yml deleted file mode 100644 index cd7f4290c..000000000 --- a/e2e/platforms/sponge/configs/banmanager/messages.yml +++ /dev/null @@ -1,418 +0,0 @@ -# Variables -# [reason] = Ban/Mute reason -# [player] = The name of the player -# [ip] = The banned ip -# [actor] = Who banned/muted -# [expires] = How long until the ban/mute ends - -messages: - duplicateIP: '&cWarning: [player] has the same IP as the following banned players:\n&6[players]' - duplicateIPAlts: '&cWarning: [player] has the same IP as the following players:\n&6[players]' - configReloaded: '�ff00Configuration &#ff5733reloaded &asuccessfully!' - deniedNotify: - player: '&cWarning: [player] attempted to join the server but was denied due to - &4[reason]' - ip: '&cWarning: [ip] attempted to join the server but was denied due to &4[reason]' - deniedMaxIp: '&cToo many players with your ip address online' - deniedMultiaccounts: '&cToo many players with your ip address logged in recently' - deniedCountry: '&cYou may not connect from your region' - time: - now: now - year: year - years: years - month: month - months: months - week: week - weeks: weeks - day: day - days: days - hour: hour - hours: hours - minute: minute - minutes: minutes - second: second - seconds: seconds - never: never - error: - invalid: '&cYour time length is invalid' - limit: '&cYou cannot perform this action for that length of time' - none: none - sender: - error: - notFound: '&c[player] not found, are you sure they exist?' - offline: '&c[player] is offline' - noSelf: '&cYou cannot perform that action on yourself!' - exception: '&cAn error occured whilst attempting to perform this command. Please - check the console for further details.' - invalidIp: '&cInvalid IP address, expecting w.x.y.z format' - offlinePermission: '&cYou are not allowed to perform this action on an offline - player' - exempt: '&c[player] is exempt from that action' - noPermission: '&cYou do not have permission to perform that action' - invalidReason: '&c[reason] is no valid reason.' - alts: - header: 'Possible alts found:' - export: - error: - inProgress: '&cAn export is already in progress, please wait' - player: - started: '&aPlayer ban export started' - finished: '&aPlayer ban export finished, file [file] created' - ip: - started: '&aIP ban export started' - finished: '&aIP ban export finished, file [file] created' - import: - error: - inProgress: '&cAn import is already in progress, please wait' - player: - started: '&aPlayer ban import started' - finished: '&aPlayer ban import finished' - ip: - started: '&aIP ban import started' - finished: '&aIP ban import finished' - advancedban: - started: '&aAdvancedBan import started' - finished: '&aAdvancedBan import finished' - h2: - started: '&aH2 import started' - finished: '&aH2 import finished, please restart the server' - litebans: - started: '&aLiteBans import started' - finished: '&aLiteBans import finished' - info: - error: - invalidIndex: '&cInvalid player option used' - indexRequired: '&cMultiple players named [name] found, please select a player - by providing an index between 1 and [size], e.g. /bminfo [name] 1' - index: '&7#[index] - &6[name] - &4[uuid]' - stats: - player: '&6[player] has been banned [bans] times, muted [mutes] times, kicked - [kicks] times and warned [warns] times ([warnPoints] Points), has [notes] - notes and been reported [reports] times' - ip: '&6This ip has been banned [bans] times, muted [mutes] times and range banned - [rangebans] times' - connection: '&6Their last connection was with [ip] on [lastSeen]' - geoip: 'Country: [country] City: [city]' - ban: - permanent: '&6Currently banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently banned for &4[reason]&6 by [actor] at [created] which - expires in [expires]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - ipban: - permanent: '&6Currently banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently banned for &4[reason]&6 by [actor] at [created] which - expires in [expires]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - iprangeban: - permanent: '&6[from] - [to] banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6[from] - [to] banned for &4[reason]&6 by [actor] at [created] - which expires in [expires]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - ipmute: - permanent: '&6Currently muted for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently muted for &4[reason]&6 by [actor] at [created] which - expires in [expires]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - mute: - permanent: '&6Currently muted for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently muted for &4[reason]&6 by [actor] at [created] which - expires in [expires]' - temporaryOnline: '&6Currently muted for &4[reason]&6 by [actor] at [created] which - expires in [expires] (online time)' - temporaryOnlinePaused: '&6Currently muted for &4[reason]&6 by [actor] at [created] - with [remaining] remaining (online time, paused)' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - website: - player: https://yourdomain.com/player/[uuid] - ip: http://yourdomain.com/index.php?action=viewip&ip=[ip]&server=0 - history: - row: '&7#[id] &a[&f[type]&a] &6[actor]&f [meta] [reason] - &e[created]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - noResults: '&cNo results found' - ips: - row: '&e[ip] - &6[join] - [leave]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - kick: - player: - noReason: '&6You have been kicked' - reason: '&6You have been kicked for &4[reason]' - notify: - noReason: '&6[player] has been kicked by [actor]' - reason: '&6[player] has been kicked by [actor] for &4[reason]' - kickall: - player: - noReason: '&6You have been kicked' - reason: '&6You have been kicked for &4[reason]' - notify: - noReason: All players have been kicked by [actor] - reason: All players have been kicked by [actor] for &4[reason] - ban: - player: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[player] has been permanently banned by [actor] for &4[reason]' - error: - exists: '&c[player] is already banned' - cooldown: '&cThis player was banned too recently, try again later' - banall: - notify: '&6[player] will be permanently banned by [actor] for &4[reason]' - tempban: - player: - disallowed: '&6You have been temporarily banned from this server for &4[reason] - \n&6It expires in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[player] has been temporarily banned for [expires] by [actor] for &4[reason]' - tempbanall: - notify: '&6[player] will be temporarily banned for [expires] by [actor] for &4[reason]' - unban: - notify: '&6[player] has been unbanned by [actor]' - error: - noExists: '&c[player] is not banned' - notOwn: '&c[player] was not banned by you, unable to unban' - unbanall: - notify: '&6[player] will be unbanned by [actor]' - mute: - player: - blocked: '&cYou may not use the [command] command whilst muted!' - disallowed: '&6You have been permanently muted for &4[reason] &6by [actor]' - broadcast: '&4[Muted] [player]&7 [message]' - notify: '&6[player] has been permanently muted by [actor] for &4[reason]' - error: - exists: '&c[player] is already muted' - cooldown: '&cThis player was muted too recently, try again later' - muteip: - ip: - disallowed: '&6You have been permanently muted for &4[reason] &6by [actor]' - broadcast: '&4[Muted] [player]&7 [message]' - notify: '&6[ip] ([players]) have been permanently muted by [actor] for &4[reason]' - error: - exists: '&c[ip] is already muted' - muteall: - notify: '&6[player] will be permanently muted by [actor] for &4[reason]' - tempmute: - player: - disallowed: '&6You have been temporarily muted for &4[reason] &6by [actor] which - expires in [expires]' - disallowedOnline: '&6You have been temporarily muted for &4[reason] &6by [actor] which - expires in [expires] (online time)' - notify: '&6[player] has been temporarily muted for [expires] by [actor] for &4[reason]' - notifyOnline: '&6[player] has been temporarily muted for [expires] (online time) by [actor] for &4[reason]' - error: - exists: '&c[player] is already muted' - tempmuteip: - ip: - disallowed: '&6You have been temporarily muted for &4[reason] &6by [actor] which - expires in [expires]' - notify: '&6[ip] ([players]) have been temporarily muted for [expires] by [actor] - for &4[reason]' - error: - exists: '&c[ip] is already muted' - tempmuteall: - notify: '&6[player] will be temporarily muted for [expires] by [actor] for &4[reason]' - unmute: - notify: '&6[player] has been unmuted by [actor]' - player: '&6You have been unmuted by [actor]' - error: - noExists: '&c[player] is not muted' - notOwn: '&c[player] was not muted by you, unable to unmute' - unmuteip: - notify: '&6[ip] has been unmuted by [actor]' - error: - noExists: '&c[ip] is not muted' - notOwn: '&c[ip] was not muted by you, unable to unmute' - unmuteall: - notify: '&6[player] will be unmuted by [actor]' - banname: - name: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6Name [name] has been permanently banned by [actor] for &4[reason]' - error: - exists: '&cName [name] is already banned' - tempbanname: - name: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires - in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6Name [name] has been temporarily banned for [expires] by [actor] for - &4[reason]' - unbanname: - notify: '&6Name [name] has been unbanned by [actor]' - error: - noExists: '&cName [name] is not banned' - banip: - ip: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[ip] ([players]) has been permanently banned by [actor] for &4[reason]' - error: - exists: '&c[ip] is already banned' - cooldown: '&cThis ip was banned too recently, try again later' - baniprange: - error: - invalid: '&cInvalid range, please use cidr notation 192.168.0.1/16 or wildcard - 192.168.*.*' - minMax: '&cRange must be lowest to highest' - exists: '&cA ban containing those ranges already exists' - ip: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[from] - [to] have been banned by [actor]' - tempbaniprange: - notify: '&6[from] - [to] has been temporarily banned for [expires] by [actor]' - ip: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires - in [expires]' - kick: '&6You have been temporarily banned for [expires] by [actor] for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - unbaniprange: - notify: '&6[from] - [to] has been unbanned by [actor]' - banipall: - notify: '&6[ip] will be permanently banned by [actor] for &4[reason]' - tempbanip: - ip: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires - in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[ip] ([players]) has been temporarily banned for [expires] by [actor] - for &4[reason]' - tempbanipall: - notify: '&6[ip] will be temporarily banned for [expires] by [actor] for &4[reason]' - unbanip: - notify: '&6[ip] has been unbanned by [actor]' - error: - noExists: '&c[ip] is not banned' - notOwn: '&c[ip] was not banned by you, unable to unban' - unbanipall: - notify: '&6[ip] will be unbanned by [actor]' - warn: - player: - warned: '&6You have been warned by [actor] for &4[reason]' - disallowed: - header: '&cYou may not speak until you have accepted your most recent warning. - Please type the following:' - reason: '&6[reason]' - removed: '&aThank you for your understanding, you may now speak again' - notify: '&6[player] has been warned by [actor] for &4[reason]' - error: - cooldown: '&cThis player was warned too recently, try again later' - tempwarn: - player: - warned: '&6You have been warned for [expires] by [actor] for &4[reason]' - notify: '&6[player] has been warned for [expires] by [actor] for &4[reason]' - dwarn: - player: - notify: '&6Your most recent warning has been deleted by &4[actor]' - notify: '&cThe most recent warning for [player] has been deleted' - error: - noWarnings: '&c[player] has no warnings to delete' - bmclear: - notify: '&c[player] has had their [type] cleared' - error: - invalid: '&cInvalid type, please choose between banrecords, muterecords, kicks, - notes or warnings' - bmutils: - missingplayers: - notify: '&c[amount] missing players added' - noneFound: '&a0 missing players found' - found: '&c[amount] missing player data found. Fixing...' - error: - failedLookup: '&cFailed to lookup player [uuid], check server logs' - complete: '&a[amount] players resolved, please restart your server for failed - punishments to take affect' - duplicates: - lookup: - notFound: '&aNo duplicate player names found' - error: - invalidName: '&cInvalid name, must be 16 characters or less and contain only - letters, numbers and an underscore' - nameExists: '&cA player with that name already exists' - success: '&aPlayer name set to [player] successfully' - bmrollback: - notify: '&c[player] has had their [type] actions undone' - error: - invalid: '&cInvalid type [type], please choose between [types]' - sync: - player: - started: '&aStarting force [type] synchronisation' - finished: '&aForced [type] synchronisation complete' - update: - notify: '&6[BanManager] &aAn update is available' - notes: - header: '&6[player] has the following notes:' - joinAmount: '&6[player] has &e[amount] &6notes, click to view them' - note: '&6[[player]] &e[message] - &e[created]' - playerNote: '&a[[player]] &6[[actor]] &e[message] - &e[created]' - dateTimeFormat: dd-MM-yyyy - notify: '[player] has a new note attached by [actor]: [message]' - error: - noNotes: '&c[player] has no notes' - noOnlineNotes: '&cNo online players have notes' - report: - notify: '&6[player] has been reported by [actor] for &4[reason]' - error: - cooldown: '&cThis player was reported too recently, try again later' - assign: - player: '&aReport [id] assigned to [player]' - notify: '&aYou have been assigned report [id] by [actor]' - unassign: - player: '&aReport [id] unassigned' - close: - notify: - closed: '&aReport [id] closed by [actor]' - command: '&aReport [id] closed by [actor] with [command]' - comment: '&aReport [id] closed by [actor] with [comment]' - dispatch: Executing command [command] - list: - noResults: '&cNo reports found' - error: - invalidState: '&cReport state [state] not found' - row: - dateTimeFormat: yyyy-MM-dd HH:mm:ss - header: '&e-- Reports ([count]) -- Page ([page]/[maxPage])' - all: '&7#[id] &e[[state]] &6- [created] - [player]' - tp: - error: - notFound: '&cReport not found' - worldNotFound: '&cWorld [world] could not be found' - invalidId: '&c[id] is not a valid report id' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: - report: '&7#[id] &6[actor] reported [player] for &4[reason]&6 at [created]' - location: '[world] - [x], [y], [z]' - info: - error: - notFound: '&cReport not found' - invalidId: '&c[id] is not a valid report id' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: - report: '&7#[id] &6[actor] reported [player] for &4[reason]&6 at [created]' - location: '[world] - [x], [y], [z]' - addnoteall: - notify: '&c[player] will have a new attached by [actor]: [message]' - banlist: - header: '&6There are [bans] [type] bans:' - bmactivity: - row: - all: '&a[&f[type]&a] &6[player]&f - &6[actor]&f - &e[created]' - player: '&a[&f[type]&a] &6[player]&f - &e[created]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - noResults: '&cNo results found' - bmdelete: - notify: '&a[rows] rows deleted' - error: - invalid: '&cInvalid type, please choose between banrecords, muterecords, kicks, - notes or warnings' - invalidId: '&c[id] is not a valid number' - denyalts: - player: - disallowed: '&cThe IP address you are joining from is linked to a banned player' - reasons: - row: '[hashtag] = [reason]' diff --git a/e2e/platforms/sponge/configs/banmanager/messages/messages_de.yml b/e2e/platforms/sponge/configs/banmanager/messages/messages_de.yml new file mode 100644 index 000000000..d813fecbc --- /dev/null +++ b/e2e/platforms/sponge/configs/banmanager/messages/messages_de.yml @@ -0,0 +1,16 @@ +messages: + configReloaded: '&aKonfiguration erfolgreich neu geladen!' + + ban: + player: + disallowed: '&6Du wurdest von diesem Server gebannt wegen &4[reason]' + kick: '&6Du wurdest dauerhaft gebannt wegen &4[reason]' + notify: '&6[player] wurde dauerhaft gebannt von [actor] wegen &4[reason]' + + unban: + notify: '&6[player] wurde von [actor] entbannt' + + mute: + player: + disallowed: '&6Du bist stummgeschaltet wegen &4[reason]' + notify: '&6[player] wurde dauerhaft stummgeschaltet von [actor] wegen &4[reason]' diff --git a/e2e/platforms/sponge/configs/banmanager/messages/messages_en.yml b/e2e/platforms/sponge/configs/banmanager/messages/messages_en.yml new file mode 100644 index 000000000..9da20bc47 --- /dev/null +++ b/e2e/platforms/sponge/configs/banmanager/messages/messages_en.yml @@ -0,0 +1,474 @@ +# Message templates use MiniMessage formatting: https://docs.advntr.dev/minimessage/format.html +# Placeholders use angle brackets, e.g. , , , , + +tokens: + appeal_url: 'https://yourdomain.com/appeal' + server_name: 'My Server' + discord_url: 'https://discord.gg/example' + rules_url: 'https://yourdomain.com/rules' + +messages: + duplicateIP: 'Warning: has the same IP as the following banned players:\n' + duplicateIPAlts: 'Warning: has the same IP as the following players:\n' + configReloaded: 'Configuration reloaded successfully!' + deniedNotify: + player: 'Warning: attempted to join the server but was denied due to ' + ip: 'Warning: attempted to join the server but was denied due to ' + deniedMaxIp: 'Too many players with your ip address online' + deniedMultiaccounts: 'Too many players with your ip address logged in recently' + deniedCountry: 'You may not connect from your region' + + time: + now: 'now' + year: 'year' + years: 'years' + month: 'month' + months: 'months' + week: 'week' + weeks: 'weeks' + day: 'day' + days: 'days' + hour: 'hour' + hours: 'hours' + minute: 'minute' + minutes: 'minutes' + second: 'second' + seconds: 'seconds' + never: 'never' + error: + invalid: 'Your time length is invalid' + limit: 'You cannot perform this action for that length of time' + + none: 'none' + # General command text + sender: + error: + notFound: ' not found, are you sure they exist?' + offline: ' is offline' + noSelf: 'You cannot perform that action on yourself!' + exception: 'An error occured whilst attempting to perform this command. Please check the console for further details.' + invalidIp: 'Invalid IP address, expecting w.x.y.z format' + offlinePermission: 'You are not allowed to perform this action on an offline player' + ambiguousPlayer: 'Multiple players match "". Please use their full name.' + exempt: ' is exempt from that action' + noPermission: 'You do not have permission to perform that action' + noConsole: 'This command cannot be used from console' + invalidReason: ' is not a valid reason.' + # Commands + alts: + header: 'Possible alts found:' + entry: '">' + separator: ', ' + + names: + header: 'Known names for :' + row: ' (first: , last: )' + interactive: ' (first: , last: )">">' + separator: ', ' + dateTimeFormat: 'dd-MM-yyyy' + none: 'No name history found' + + export: + error: + inProgress: 'An export is already in progress, please wait' + player: + started: 'Player ban export started' + finished: 'Player ban export finished, file created' + ip: + started: 'IP ban export started' + finished: 'IP ban export finished, file created' + + import: + error: + inProgress: 'An import is already in progress, please wait' + player: + started: 'Player ban import started' + finished: 'Player ban import finished' + ip: + started: 'IP ban import started' + finished: 'IP ban import finished' + advancedban: + started: 'AdvancedBan import started' + finished: 'AdvancedBan import finished' + h2: + started: 'H2 import started' + finished: 'H2 import finished, please restart the server' + litebans: + started: 'LiteBans import started' + finished: 'LiteBans import finished' + + info: + error: + invalidIndex: 'Invalid player option used' + indexRequired: 'Multiple players named found, please select a player by providing an index between 1 and , e.g. /bminfo 1' + index: '# - - ' + stats: + player: ' has been banned times, muted times, kicked times and warned + times ( Points), has notes and been reported times' + ip: 'This ip has been banned times, muted times and range banned times' + connection: 'Their last connection was with on ' + geoip: 'Country: City: ' + ban: + permanent: 'Currently banned for by at ' + temporary: 'Currently banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + ipban: + permanent: 'Currently banned for by at ' + temporary: 'Currently banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + iprangeban: + permanent: ' - banned for by at ' + temporary: ' - banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + ipmute: + permanent: 'Currently muted for by at ' + temporary: 'Currently muted for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + mute: + permanent: 'Currently muted for by at ' + temporary: 'Currently muted for by at which expires in ' + temporaryOnline: 'Currently muted for by at which expires in (online time)' + temporaryOnlinePaused: 'Currently muted for by at with remaining (online time, paused)' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + website: + player: 'https://yourdomain.com/player/' + ip: 'http://yourdomain.com/index.php?action=viewip&ip=&server=0' + history: + row: '# [] - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + noResults: 'No results found' + ips: + row: ' - - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + + kick: + player: + noReason: 'You have been kicked' + reason: 'You have been kicked for ' + notify: + noReason: ' has been kicked by ">View player info">[Info]' + reason: ' has been kicked by for ">View player info">[Info]' + + kickall: + player: + noReason: 'You have been kicked' + reason: 'You have been kicked for ' + notify: + noReason: 'All players have been kicked by ' + reason: 'All players have been kicked by for ' + + ban: + player: + disallowed: 'You are banned from this server\n \nReason: \nBanned by: \nDate: \n \nAppeal at ' + kick: 'You have been banned\n \nReason: \nBanned by: \nDate: \n \nAppeal at ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' has been permanently banned by for ">View player info">[Info] ">Unban player">[Unban]' + error: + exists: ' is already banned' + cooldown: 'This player was banned too recently, try again later' + + banall: + notify: ' will be permanently banned by for ' + + tempban: + player: + disallowed: 'You are temporarily banned from this server\n \nReason: \nBanned by: \nExpires: \nDate: \n \nAppeal at ' + kick: 'You have been temporarily banned\n \nReason: \nBanned by: \nExpires: \nDate: \n \nAppeal at ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' has been temporarily banned for by for ">View player info">[Info] ">Unban player">[Unban]' + + tempbanall: + notify: ' will be temporarily banned for by for ' + + unban: + notify: ' has been unbanned by ' + error: + noExists: ' is not banned' + notOwn: ' was not banned by you, unable to unban' + + unbanall: + notify: ' will be unbanned by ' + + mute: + player: + blocked: 'You may not use the command whilst muted!' + disallowed: 'You have been permanently muted for by ' + broadcast: '[Muted] ' + notify: ' has been permanently muted by for ">View player info">[Info] ">Unmute player">[Unmute]' + error: + exists: ' is already muted' + cooldown: 'This player was muted too recently, try again later' + + muteip: + ip: + disallowed: 'You have been permanently muted for by ' + broadcast: '[Muted] ' + notify: ' () have been permanently muted by for ' + error: + exists: ' is already muted' + + muteall: + notify: ' will be permanently muted by for ' + + tempmute: + player: + disallowed: 'You have been temporarily muted for by which expires in ' + disallowedOnline: 'You have been temporarily muted for by which expires in (online time)' + notify: ' has been temporarily muted for by for ">View player info">[Info] ">Unmute player">[Unmute]' + notifyOnline: ' has been temporarily muted for (online time) by for ' + error: + exists: ' is already muted' + + tempmuteip: + ip: + disallowed: 'You have been temporarily muted for by which expires in ' + notify: ' () have been temporarily muted for by for ' + error: + exists: ' is already muted' + + tempmuteall: + notify: ' will be temporarily muted for by for ' + + unmute: + notify: ' has been unmuted by ' + player: 'You have been unmuted by ' + error: + noExists: ' is not muted' + notOwn: ' was not muted by you, unable to unmute' + + unmuteip: + notify: ' has been unmuted by ' + error: + noExists: ' is not muted' + notOwn: ' was not muted by you, unable to unmute' + + unmuteall: + notify: ' will be unmuted by ' + + banname: + name: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: 'Name has been permanently banned by for ' + error: + exists: 'Name is already banned' + + tempbanname: + name: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: 'Name has been temporarily banned for by for ' + + unbanname: + notify: 'Name has been unbanned by ' + error: + noExists: 'Name is not banned' + + banip: + ip: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' () has been permanently banned by for ' + error: + exists: ' is already banned' + cooldown: 'This ip was banned too recently, try again later' + + baniprange: + error: + invalid: 'Invalid range, please use cidr notation 192.168.0.1/16 or wildcard 192.168.*.*' + minMax: 'Range must be lowest to highest' + exists: 'A ban containing those ranges already exists' + ip: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' - have been banned by ' + + tempbaniprange: + notify: ' - has been temporarily banned for by ' + ip: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for by for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + + unbaniprange: + notify: ' - has been unbanned by ' + + banipall: + notify: ' will be permanently banned by for ' + + tempbanip: + ip: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' () has been temporarily banned for by for ' + + tempbanipall: + notify: ' will be temporarily banned for by for ' + + unbanip: + notify: ' has been unbanned by ' + error: + noExists: ' is not banned' + notOwn: ' was not banned by you, unable to unban' + + unbanipall: + notify: ' will be unbanned by ' + + warn: + player: + warned: 'You have been warned by for ' + disallowed: + header: 'You may not speak until you have accepted your most recent warning. Please type the following:' + reason: '' + removed: 'Thank you for your understanding, you may now speak again' + notify: ' has been warned by for ">View player info">[Info]' + error: + cooldown: 'This player was warned too recently, try again later' + + tempwarn: + player: + warned: 'You have been warned for by for ' + notify: ' has been warned for by for ">View player info">[Info]' + + dwarn: + player: + notify: 'Your most recent warning has been deleted by ' + notify: 'The most recent warning for has been deleted' + error: + noWarnings: ' has no warnings to delete' + + bmclear: + notify: ' has had their cleared' + error: + invalid: 'Invalid type, please choose between banrecords, muterecords, kicks, notes or warnings' + + bmutils: + missingplayers: + notify: ' missing players added' + noneFound: '0 missing players found' + found: ' missing player data found. Fixing...' + error: + failedLookup: 'Failed to lookup player , check server logs' + complete: ' players resolved, please restart your server for failed punishments to take affect' + duplicates: + lookup: + notFound: 'No duplicate player names found' + error: + invalidName: 'Invalid name, must be 16 characters or less and contain only letters, numbers and an underscore' + nameExists: 'A player with that name already exists' + success: 'Player name set to successfully' + + bmrollback: + notify: ' has had their actions undone' + error: + invalid: 'Invalid type , please choose between ' + + sync: + player: + started: 'Starting force synchronisation' + finished: 'Forced synchronisation complete' + + update: + notify: '[BanManager] An update is available' + + notes: + header: ' has the following notes:' + joinAmount: '"> has notes, click to view them' + note: '[] - ' + playerNote: '[] [] - ' + dateTimeFormat: 'dd-MM-yyyy' + notify: ' has a new note attached by : ' + error: + noNotes: ' has no notes' + noOnlineNotes: 'No online players have notes' + + report: + notify: ' has been reported by for ' + error: + cooldown: 'This player was reported too recently, try again later' + assign: + player: 'Report assigned to ' + notify: 'You have been assigned report by ' + unassign: + player: 'Report unassigned' + close: + notify: + closed: 'Report closed by ' + command: 'Report closed by with ' + comment: 'Report closed by with ' + dispatch: 'Executing command ' + list: + noResults: 'No reports found' + error: + invalidState: 'Report state not found' + row: + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + header: '-- Reports () -- Page (/)' + all: '">Click to view details"># [] - - ' + tp: + error: + notFound: 'Report not found' + worldNotFound: 'World could not be found' + invalidId: ' is not a valid report id' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: + report: '# reported for at ' + location: ' - , , ' + info: + error: + notFound: 'Report not found' + invalidId: ' is not a valid report id' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: + report: '# reported for at ' + location: ' - , , ' + actions: + assign: '">Assign to yourself">[Assign]' + close: '">Close this report">[Close]' + tp: '">Teleport to location">[TP]' + feedback: + assigned: 'Your report # has been assigned to ' + closed: 'Your report # has been closed by ' + + addnoteall: + notify: ' will have a new note attached by : ' + + banlist: + header: 'There are bans:' + row: + player: '">Click for info"> - ' + ip: ' - ' + iprange: ' - - ' + + bmactivity: + row: + all: '[] - - ' + player: '[] - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + noResults: 'No results found' + + bmdelete: + notify: ' rows deleted' + error: + invalid: 'Invalid type, please choose between banrecords, muterecords, kicks, notes or warnings' + invalidId: ' is not a valid number' + + denyalts: + player: + disallowed: 'The IP address you are joining from is linked to a banned player' + + reasons: + row: ' = ' + + dashboard: + header: ' Staff Dashboard ' + activeBans: 'Active Bans: ' + activeMutes: 'Active Mutes: ' + openReports: 'Open Reports: View reports">[View]' + recentActivity: 'Recent Activity (24h): ' + footer: ' ' diff --git a/e2e/platforms/sponge/configs/banmanager/notifications.yml b/e2e/platforms/sponge/configs/banmanager/notifications.yml new file mode 100644 index 000000000..75b1fb646 --- /dev/null +++ b/e2e/platforms/sponge/configs/banmanager/notifications.yml @@ -0,0 +1,81 @@ +# Notifications Configuration +# Controls how punishment notifications are delivered to staff and players +# +# Each notification event can specify delivery channels: +# chat: true/false - Send via chat message (default: true) +# actionbar: true/false - Send via action bar (disappears after a few seconds) +# title: true/false - Send via title/subtitle overlay +# sound: '' - Sound to play (empty to disable). Use Minecraft sound names e.g. entity.experience_orb.pickup +# +# Title settings (only used when title: true): +# titleFadeIn: ticks for fade in (20 ticks = 1 second) +# titleStay: ticks to stay on screen +# titleFadeOut: ticks for fade out +# +# Sound settings: +# soundVolume: 0.0 - 1.0 +# soundPitch: 0.0 - 2.0 +# +# Platform notes: +# - BungeeCord: title, showTitle and playSound are not supported (ignored silently) +# - Sponge API7: playSound is not supported (ignored silently) +# - All other platforms (Bukkit/Paper, Velocity, Fabric, Sponge API8+) support all channels + +staff: + ban: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + tempban: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + mute: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + tempmute: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + warn: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + report: + chat: true + actionbar: false + title: false + sound: 'block.note_block.pling' + soundVolume: 1.0 + soundPitch: 1.0 + duplicateIp: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + +player: + muted: + actionbar: true + warned: + sound: 'entity.villager.no' + soundVolume: 1.0 + soundPitch: 1.0 diff --git a/e2e/platforms/sponge7/configs/banmanager/config.yml b/e2e/platforms/sponge7/configs/banmanager/config.yml deleted file mode 100644 index 41de43066..000000000 --- a/e2e/platforms/sponge7/configs/banmanager/config.yml +++ /dev/null @@ -1,138 +0,0 @@ -# -# Aliases will be found and blocked automatically, e.g. msg will block tell -debug: false -databases: - local: - storageType: mariadb - host: mariadb - port: 3306 - name: banmanager - user: banmanager - password: banmanager - maxConnections: 10 - useSSL: false - allowPublicKeyRetrieval: true - verifyServerCertificate: false - maxLifetime: 1800000 - connectionTimeout: 30000 - tables: - players: bm_players - playerBans: bm_player_bans - playerBanRecords: bm_player_ban_records - playerMutes: bm_player_mutes - playerMuteRecords: bm_player_mute_records - playerKicks: bm_player_kicks - playerNotes: bm_player_notes - playerHistory: bm_player_history - playerReports: bm_player_reports - playerReportLocations: bm_player_report_locations - playerReportStates: bm_player_report_states - playerReportCommands: bm_player_report_commands - playerReportComments: bm_player_report_comments - playerWarnings: bm_player_warnings - ipBans: bm_ip_bans - ipBanRecords: bm_ip_ban_records - ipMutes: bm_ip_mutes - ipMuteRecords: bm_ip_mute_records - ipRangeBans: bm_ip_range_bans - ipRangeBanRecords: bm_ip_range_ban_records - rollbacks: bm_rollbacks - nameBans: bm_name_bans - nameBanRecords: bm_name_ban_records - global: - enabled: true - storageType: mysql - host: mariadb - port: 3306 - name: banmanager - user: banmanager - password: banmanager - maxConnections: 10 - useSSL: false - allowPublicKeyRetrieval: true - verifyServerCertificate: false - leakDetection: 3000 - maxLifetime: 1800000 - connectionTimeout: 30000 - tables: - playerBans: bm_player_ban_all - playerUnbans: bm_player_unban_all - playerMutes: bm_player_mute_all - playerUnmutes: bm_player_unmute_all - playerNotes: bm_player_note_all - ipBans: bm_ip_ban_all - ipUnbans: bm_ip_unban_all -mutedCommandBlacklist: -- msg -softMutedCommandBlacklist: -- msg -duplicateIpCheck: false -bypassDuplicateChecks: -- 0.0.0.0 -- 127.0.0.1 -logKicks: false -logIps: true -displayNotifications: true -broadcastOnSync: false -timeLimits: - playerMutes: {} - playerBans: {} - playerWarnings: {} - ipBans: {} - ipMutes: {} - rollbacks: {} - nameBans: {} -cooldowns: - ban: 0 - tempban: 0 - mute: 0 - tempmute: 0 - banip: 0 - tempbanip: 0 - warn: 0 - tempwarn: 0 - report: 0 -warningActions: - enabled: true - actions: - 3: - - cmd: "say warning-action-triggered-[player]" - delay: 0 -warningMute: false -hooks: - enabled: true - events: - mute: - post: - - cmd: say hook-fired-mute - delay: 2 -checkForUpdates: false -offlineAutoComplete: true -punishAlts: false -denyAlts: false -timeAssociatedAlts: 0 -cleanUp: - kicks: 0 - banRecords: 0 - ipBanRecords: 0 - ipMuteRecords: 0 - muteRecords: 0 - readWarnings: 0 - unreadWarnings: 0 - playerHistory: 0 -maxOnlinePerIp: 0 -maxMultiaccountsRecently: 0 -multiaccountsTime: 300 -checkOnJoin: false -createNoteReasons: false -onlineMode: false -chatPriority: normal -blockInvalidReasons: false -uuidFetcher: - idToName: - url: https://sessionserver.mojang.com/session/minecraft/profile/[uuid] - key: name - nameToId: - url: https://api.mojang.com/users/profiles/minecraft/[name] - key: id -geyserPrefix: . diff --git a/e2e/platforms/sponge7/configs/banmanager/console.yml b/e2e/platforms/sponge7/configs/banmanager/console.yml deleted file mode 100644 index 6eea2c458..000000000 --- a/e2e/platforms/sponge7/configs/banmanager/console.yml +++ /dev/null @@ -1,4 +0,0 @@ -# This is used to identify the server when it makes bans etc -# Do not change the uuid, it is generated automatically! -name: Console -uuid: 390f29f5-9773-43c0-b729-930927098048 diff --git a/e2e/platforms/sponge7/configs/banmanager/exemptions.yml b/e2e/platforms/sponge7/configs/banmanager/exemptions.yml deleted file mode 100644 index 463a5f031..000000000 --- a/e2e/platforms/sponge7/configs/banmanager/exemptions.yml +++ /dev/null @@ -1,16 +0,0 @@ -# Example: -# The following player is exempt from bans, mutes and warnings. True means exempt. -# uuid-here: -# ban: true -# tempban: true -# baniprange: true -# tempbaniprange: true -# mute: true -# tempmute: true -# warn: true -# tempwarn: true -# alts: true -# deniedNotify: true - -47d8e47b-11c1-393b-8611-7c34449ba1b1: - deniedNotify: true diff --git a/e2e/platforms/sponge7/configs/banmanager/geoip.yml b/e2e/platforms/sponge7/configs/banmanager/geoip.yml deleted file mode 100644 index 93006a579..000000000 --- a/e2e/platforms/sponge7/configs/banmanager/geoip.yml +++ /dev/null @@ -1,10 +0,0 @@ -# -# Allow only certain countries on the server -enabled: false -download: - city: https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=[licenseKey]&suffix=tar.gz - country: https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=[licenseKey]&suffix=tar.gz - lastUpdated: 0 - licenseKey: '' -countries: - type: deny diff --git a/e2e/platforms/sponge7/configs/banmanager/messages.yml b/e2e/platforms/sponge7/configs/banmanager/messages.yml deleted file mode 100644 index cd7f4290c..000000000 --- a/e2e/platforms/sponge7/configs/banmanager/messages.yml +++ /dev/null @@ -1,418 +0,0 @@ -# Variables -# [reason] = Ban/Mute reason -# [player] = The name of the player -# [ip] = The banned ip -# [actor] = Who banned/muted -# [expires] = How long until the ban/mute ends - -messages: - duplicateIP: '&cWarning: [player] has the same IP as the following banned players:\n&6[players]' - duplicateIPAlts: '&cWarning: [player] has the same IP as the following players:\n&6[players]' - configReloaded: '�ff00Configuration &#ff5733reloaded &asuccessfully!' - deniedNotify: - player: '&cWarning: [player] attempted to join the server but was denied due to - &4[reason]' - ip: '&cWarning: [ip] attempted to join the server but was denied due to &4[reason]' - deniedMaxIp: '&cToo many players with your ip address online' - deniedMultiaccounts: '&cToo many players with your ip address logged in recently' - deniedCountry: '&cYou may not connect from your region' - time: - now: now - year: year - years: years - month: month - months: months - week: week - weeks: weeks - day: day - days: days - hour: hour - hours: hours - minute: minute - minutes: minutes - second: second - seconds: seconds - never: never - error: - invalid: '&cYour time length is invalid' - limit: '&cYou cannot perform this action for that length of time' - none: none - sender: - error: - notFound: '&c[player] not found, are you sure they exist?' - offline: '&c[player] is offline' - noSelf: '&cYou cannot perform that action on yourself!' - exception: '&cAn error occured whilst attempting to perform this command. Please - check the console for further details.' - invalidIp: '&cInvalid IP address, expecting w.x.y.z format' - offlinePermission: '&cYou are not allowed to perform this action on an offline - player' - exempt: '&c[player] is exempt from that action' - noPermission: '&cYou do not have permission to perform that action' - invalidReason: '&c[reason] is no valid reason.' - alts: - header: 'Possible alts found:' - export: - error: - inProgress: '&cAn export is already in progress, please wait' - player: - started: '&aPlayer ban export started' - finished: '&aPlayer ban export finished, file [file] created' - ip: - started: '&aIP ban export started' - finished: '&aIP ban export finished, file [file] created' - import: - error: - inProgress: '&cAn import is already in progress, please wait' - player: - started: '&aPlayer ban import started' - finished: '&aPlayer ban import finished' - ip: - started: '&aIP ban import started' - finished: '&aIP ban import finished' - advancedban: - started: '&aAdvancedBan import started' - finished: '&aAdvancedBan import finished' - h2: - started: '&aH2 import started' - finished: '&aH2 import finished, please restart the server' - litebans: - started: '&aLiteBans import started' - finished: '&aLiteBans import finished' - info: - error: - invalidIndex: '&cInvalid player option used' - indexRequired: '&cMultiple players named [name] found, please select a player - by providing an index between 1 and [size], e.g. /bminfo [name] 1' - index: '&7#[index] - &6[name] - &4[uuid]' - stats: - player: '&6[player] has been banned [bans] times, muted [mutes] times, kicked - [kicks] times and warned [warns] times ([warnPoints] Points), has [notes] - notes and been reported [reports] times' - ip: '&6This ip has been banned [bans] times, muted [mutes] times and range banned - [rangebans] times' - connection: '&6Their last connection was with [ip] on [lastSeen]' - geoip: 'Country: [country] City: [city]' - ban: - permanent: '&6Currently banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently banned for &4[reason]&6 by [actor] at [created] which - expires in [expires]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - ipban: - permanent: '&6Currently banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently banned for &4[reason]&6 by [actor] at [created] which - expires in [expires]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - iprangeban: - permanent: '&6[from] - [to] banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6[from] - [to] banned for &4[reason]&6 by [actor] at [created] - which expires in [expires]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - ipmute: - permanent: '&6Currently muted for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently muted for &4[reason]&6 by [actor] at [created] which - expires in [expires]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - mute: - permanent: '&6Currently muted for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently muted for &4[reason]&6 by [actor] at [created] which - expires in [expires]' - temporaryOnline: '&6Currently muted for &4[reason]&6 by [actor] at [created] which - expires in [expires] (online time)' - temporaryOnlinePaused: '&6Currently muted for &4[reason]&6 by [actor] at [created] - with [remaining] remaining (online time, paused)' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - website: - player: https://yourdomain.com/player/[uuid] - ip: http://yourdomain.com/index.php?action=viewip&ip=[ip]&server=0 - history: - row: '&7#[id] &a[&f[type]&a] &6[actor]&f [meta] [reason] - &e[created]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - noResults: '&cNo results found' - ips: - row: '&e[ip] - &6[join] - [leave]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - kick: - player: - noReason: '&6You have been kicked' - reason: '&6You have been kicked for &4[reason]' - notify: - noReason: '&6[player] has been kicked by [actor]' - reason: '&6[player] has been kicked by [actor] for &4[reason]' - kickall: - player: - noReason: '&6You have been kicked' - reason: '&6You have been kicked for &4[reason]' - notify: - noReason: All players have been kicked by [actor] - reason: All players have been kicked by [actor] for &4[reason] - ban: - player: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[player] has been permanently banned by [actor] for &4[reason]' - error: - exists: '&c[player] is already banned' - cooldown: '&cThis player was banned too recently, try again later' - banall: - notify: '&6[player] will be permanently banned by [actor] for &4[reason]' - tempban: - player: - disallowed: '&6You have been temporarily banned from this server for &4[reason] - \n&6It expires in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[player] has been temporarily banned for [expires] by [actor] for &4[reason]' - tempbanall: - notify: '&6[player] will be temporarily banned for [expires] by [actor] for &4[reason]' - unban: - notify: '&6[player] has been unbanned by [actor]' - error: - noExists: '&c[player] is not banned' - notOwn: '&c[player] was not banned by you, unable to unban' - unbanall: - notify: '&6[player] will be unbanned by [actor]' - mute: - player: - blocked: '&cYou may not use the [command] command whilst muted!' - disallowed: '&6You have been permanently muted for &4[reason] &6by [actor]' - broadcast: '&4[Muted] [player]&7 [message]' - notify: '&6[player] has been permanently muted by [actor] for &4[reason]' - error: - exists: '&c[player] is already muted' - cooldown: '&cThis player was muted too recently, try again later' - muteip: - ip: - disallowed: '&6You have been permanently muted for &4[reason] &6by [actor]' - broadcast: '&4[Muted] [player]&7 [message]' - notify: '&6[ip] ([players]) have been permanently muted by [actor] for &4[reason]' - error: - exists: '&c[ip] is already muted' - muteall: - notify: '&6[player] will be permanently muted by [actor] for &4[reason]' - tempmute: - player: - disallowed: '&6You have been temporarily muted for &4[reason] &6by [actor] which - expires in [expires]' - disallowedOnline: '&6You have been temporarily muted for &4[reason] &6by [actor] which - expires in [expires] (online time)' - notify: '&6[player] has been temporarily muted for [expires] by [actor] for &4[reason]' - notifyOnline: '&6[player] has been temporarily muted for [expires] (online time) by [actor] for &4[reason]' - error: - exists: '&c[player] is already muted' - tempmuteip: - ip: - disallowed: '&6You have been temporarily muted for &4[reason] &6by [actor] which - expires in [expires]' - notify: '&6[ip] ([players]) have been temporarily muted for [expires] by [actor] - for &4[reason]' - error: - exists: '&c[ip] is already muted' - tempmuteall: - notify: '&6[player] will be temporarily muted for [expires] by [actor] for &4[reason]' - unmute: - notify: '&6[player] has been unmuted by [actor]' - player: '&6You have been unmuted by [actor]' - error: - noExists: '&c[player] is not muted' - notOwn: '&c[player] was not muted by you, unable to unmute' - unmuteip: - notify: '&6[ip] has been unmuted by [actor]' - error: - noExists: '&c[ip] is not muted' - notOwn: '&c[ip] was not muted by you, unable to unmute' - unmuteall: - notify: '&6[player] will be unmuted by [actor]' - banname: - name: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6Name [name] has been permanently banned by [actor] for &4[reason]' - error: - exists: '&cName [name] is already banned' - tempbanname: - name: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires - in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6Name [name] has been temporarily banned for [expires] by [actor] for - &4[reason]' - unbanname: - notify: '&6Name [name] has been unbanned by [actor]' - error: - noExists: '&cName [name] is not banned' - banip: - ip: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[ip] ([players]) has been permanently banned by [actor] for &4[reason]' - error: - exists: '&c[ip] is already banned' - cooldown: '&cThis ip was banned too recently, try again later' - baniprange: - error: - invalid: '&cInvalid range, please use cidr notation 192.168.0.1/16 or wildcard - 192.168.*.*' - minMax: '&cRange must be lowest to highest' - exists: '&cA ban containing those ranges already exists' - ip: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[from] - [to] have been banned by [actor]' - tempbaniprange: - notify: '&6[from] - [to] has been temporarily banned for [expires] by [actor]' - ip: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires - in [expires]' - kick: '&6You have been temporarily banned for [expires] by [actor] for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - unbaniprange: - notify: '&6[from] - [to] has been unbanned by [actor]' - banipall: - notify: '&6[ip] will be permanently banned by [actor] for &4[reason]' - tempbanip: - ip: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires - in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[ip] ([players]) has been temporarily banned for [expires] by [actor] - for &4[reason]' - tempbanipall: - notify: '&6[ip] will be temporarily banned for [expires] by [actor] for &4[reason]' - unbanip: - notify: '&6[ip] has been unbanned by [actor]' - error: - noExists: '&c[ip] is not banned' - notOwn: '&c[ip] was not banned by you, unable to unban' - unbanipall: - notify: '&6[ip] will be unbanned by [actor]' - warn: - player: - warned: '&6You have been warned by [actor] for &4[reason]' - disallowed: - header: '&cYou may not speak until you have accepted your most recent warning. - Please type the following:' - reason: '&6[reason]' - removed: '&aThank you for your understanding, you may now speak again' - notify: '&6[player] has been warned by [actor] for &4[reason]' - error: - cooldown: '&cThis player was warned too recently, try again later' - tempwarn: - player: - warned: '&6You have been warned for [expires] by [actor] for &4[reason]' - notify: '&6[player] has been warned for [expires] by [actor] for &4[reason]' - dwarn: - player: - notify: '&6Your most recent warning has been deleted by &4[actor]' - notify: '&cThe most recent warning for [player] has been deleted' - error: - noWarnings: '&c[player] has no warnings to delete' - bmclear: - notify: '&c[player] has had their [type] cleared' - error: - invalid: '&cInvalid type, please choose between banrecords, muterecords, kicks, - notes or warnings' - bmutils: - missingplayers: - notify: '&c[amount] missing players added' - noneFound: '&a0 missing players found' - found: '&c[amount] missing player data found. Fixing...' - error: - failedLookup: '&cFailed to lookup player [uuid], check server logs' - complete: '&a[amount] players resolved, please restart your server for failed - punishments to take affect' - duplicates: - lookup: - notFound: '&aNo duplicate player names found' - error: - invalidName: '&cInvalid name, must be 16 characters or less and contain only - letters, numbers and an underscore' - nameExists: '&cA player with that name already exists' - success: '&aPlayer name set to [player] successfully' - bmrollback: - notify: '&c[player] has had their [type] actions undone' - error: - invalid: '&cInvalid type [type], please choose between [types]' - sync: - player: - started: '&aStarting force [type] synchronisation' - finished: '&aForced [type] synchronisation complete' - update: - notify: '&6[BanManager] &aAn update is available' - notes: - header: '&6[player] has the following notes:' - joinAmount: '&6[player] has &e[amount] &6notes, click to view them' - note: '&6[[player]] &e[message] - &e[created]' - playerNote: '&a[[player]] &6[[actor]] &e[message] - &e[created]' - dateTimeFormat: dd-MM-yyyy - notify: '[player] has a new note attached by [actor]: [message]' - error: - noNotes: '&c[player] has no notes' - noOnlineNotes: '&cNo online players have notes' - report: - notify: '&6[player] has been reported by [actor] for &4[reason]' - error: - cooldown: '&cThis player was reported too recently, try again later' - assign: - player: '&aReport [id] assigned to [player]' - notify: '&aYou have been assigned report [id] by [actor]' - unassign: - player: '&aReport [id] unassigned' - close: - notify: - closed: '&aReport [id] closed by [actor]' - command: '&aReport [id] closed by [actor] with [command]' - comment: '&aReport [id] closed by [actor] with [comment]' - dispatch: Executing command [command] - list: - noResults: '&cNo reports found' - error: - invalidState: '&cReport state [state] not found' - row: - dateTimeFormat: yyyy-MM-dd HH:mm:ss - header: '&e-- Reports ([count]) -- Page ([page]/[maxPage])' - all: '&7#[id] &e[[state]] &6- [created] - [player]' - tp: - error: - notFound: '&cReport not found' - worldNotFound: '&cWorld [world] could not be found' - invalidId: '&c[id] is not a valid report id' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: - report: '&7#[id] &6[actor] reported [player] for &4[reason]&6 at [created]' - location: '[world] - [x], [y], [z]' - info: - error: - notFound: '&cReport not found' - invalidId: '&c[id] is not a valid report id' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: - report: '&7#[id] &6[actor] reported [player] for &4[reason]&6 at [created]' - location: '[world] - [x], [y], [z]' - addnoteall: - notify: '&c[player] will have a new attached by [actor]: [message]' - banlist: - header: '&6There are [bans] [type] bans:' - bmactivity: - row: - all: '&a[&f[type]&a] &6[player]&f - &6[actor]&f - &e[created]' - player: '&a[&f[type]&a] &6[player]&f - &e[created]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - noResults: '&cNo results found' - bmdelete: - notify: '&a[rows] rows deleted' - error: - invalid: '&cInvalid type, please choose between banrecords, muterecords, kicks, - notes or warnings' - invalidId: '&c[id] is not a valid number' - denyalts: - player: - disallowed: '&cThe IP address you are joining from is linked to a banned player' - reasons: - row: '[hashtag] = [reason]' diff --git a/e2e/platforms/sponge7/configs/banmanager/reasons.yml b/e2e/platforms/sponge7/configs/banmanager/reasons.yml deleted file mode 100644 index 32f826fd1..000000000 --- a/e2e/platforms/sponge7/configs/banmanager/reasons.yml +++ /dev/null @@ -1,4 +0,0 @@ -# Example: -# hacking: "Using a hacked client" -# /ban confuser #hacking - diff --git a/e2e/platforms/sponge7/configs/banmanager/schedules.yml b/e2e/platforms/sponge7/configs/banmanager/schedules.yml deleted file mode 100644 index c03e2a80e..000000000 --- a/e2e/platforms/sponge7/configs/banmanager/schedules.yml +++ /dev/null @@ -1,30 +0,0 @@ -# Scheduler intervals in seconds, recommended to leave as default values. -# Setting to 0 disables the scheduler from running. -# Only change if you know what you are doing! -scheduler: - expiresCheck: 5 - playerBans: 5 - playerMutes: 5 - playerWarnings: 5 - ipBans: 5 - ipRangeBans: 5 - rollbacks: 30 - nameBans: 5 - externalPlayerBans: 5 - externalPlayerMutes: 5 - externalPlayerNotes: 5 - externalIpBans: 5 - saveLastChecked: 60 -lastChecked: - playerMutes: 0 - expiresCheck: 0 - nameBans: 0 - playerBans: 0 - playerWarnings: 0 - externalPlayerNotes: 0 - ipRangeBans: 0 - externalPlayerMutes: 0 - rollbacks: 0 - externalPlayerBans: 0 - externalIpBans: 0 - ipBans: 0 diff --git a/e2e/platforms/sponge7/configs/banmanager/webhooks.yml b/e2e/platforms/sponge7/configs/banmanager/webhooks.yml deleted file mode 100644 index 29eb572eb..000000000 --- a/e2e/platforms/sponge7/configs/banmanager/webhooks.yml +++ /dev/null @@ -1,255 +0,0 @@ -# More info at https://banmanagement.com/docs/banmanager/configuration/discord-yml -hooks: - enabled: true - punishments: - ban: - url: http://webhook-sink:8080/webhook - ignoreSilent: true - payload: - embeds: - - title: '[player] banned' - description: '[reason]' - color: 10033947 - author: - name: BanManager - url: https://banmanagement.com - icon_url: https://banmanagement.com/images/banmanager-icon.png - footer: - text: 'By: [actor]' - icon_url: https://crafthead.net/helm/[actorId]/128 - thumbnail: - url: https://crafthead.net/helm/[playerId]/128 - tempban: - url: http://webhook-sink:8080/webhook - ignoreSilent: true - payload: - embeds: - - title: '[player] banned' - description: '[reason]' - color: 15680580 - fields: - - name: Duration - value: '[expires]' - inline: true - author: - name: BanManager - url: https://banmanagement.com - icon_url: https://banmanagement.com/images/banmanager-icon.png - footer: - text: 'By: [actor]' - icon_url: https://crafthead.net/helm/[actorId]/128 - thumbnail: - url: https://crafthead.net/helm/[playerId]/128 - unban: - url: https://discord.com/api/webhooks/changeMe - ignoreSilent: true - payload: - embeds: - - title: '[player] unbanned' - description: '[reason]' - color: 2278750 - author: - name: BanManager - url: https://banmanagement.com - icon_url: https://banmanagement.com/images/banmanager-icon.png - footer: - text: 'By: [actor]' - icon_url: https://crafthead.net/helm/[actorId]/128 - thumbnail: - url: https://crafthead.net/helm/[playerId]/128 - banip: - url: https://discord.com/api/webhooks/changeMe - ignoreSilent: true - payload: - embeds: - - title: '[ip] Banned' - description: '[reason]' - color: 10033947 - author: - name: BanManager - url: https://banmanagement.com - icon_url: https://banmanagement.com/images/banmanager-icon.png - footer: - text: 'By: [actor]' - icon_url: https://crafthead.net/helm/[actorId]/128 - thumbnail: - url: https://crafthead.net/helm/[playerId]/128 - tempbanip: - url: https://discord.com/api/webhooks/changeMe - ignoreSilent: true - payload: - embeds: - - title: '[ip] banned' - description: '[reason]' - color: 15680580 - fields: - - name: Duration - value: '[expires]' - inline: true - author: - name: BanManager - url: https://banmanagement.com - icon_url: https://banmanagement.com/images/banmanager-icon.png - footer: - text: 'By: [actor]' - icon_url: https://crafthead.net/helm/[actorId]/128 - thumbnail: - url: https://crafthead.net/helm/[playerId]/128 - unbanip: - url: https://discord.com/api/webhooks/changeMe - ignoreSilent: true - payload: - embeds: - - title: '[ip] Unbanned' - description: '[reason]' - color: 2278750 - author: - name: BanManager - url: https://banmanagement.com - icon_url: https://banmanagement.com/images/banmanager-icon.png - footer: - text: 'By: [actor]' - icon_url: https://crafthead.net/helm/[actorId]/128 - thumbnail: - url: https://crafthead.net/helm/[playerId]/128 - kick: - url: https://discord.com/api/webhooks/changeMe - ignoreSilent: true - payload: - embeds: - - title: '[player] kicked' - description: '[reason]' - color: 16776960 - author: - name: BanManager - url: https://banmanagement.com - icon_url: https://banmanagement.com/images/banmanager-icon.png - footer: - text: 'By: [actor]' - icon_url: https://crafthead.net/helm/[actorId]/128 - thumbnail: - url: https://crafthead.net/helm/[playerId]/128 - mute: - url: https://discord.com/api/webhooks/changeMe - ignoreSilent: true - payload: - embeds: - - title: '[player] muted' - description: '[reason]' - color: 3616931 - author: - name: BanManager - url: https://banmanagement.com - icon_url: https://banmanagement.com/images/banmanager-icon.png - footer: - text: 'By: [actor]' - icon_url: https://crafthead.net/helm/[actorId]/128 - thumbnail: - url: https://crafthead.net/helm/[playerId]/128 - tempmute: - url: https://discord.com/api/webhooks/changeMe - ignoreSilent: true - payload: - embeds: - - title: '[player] muted' - description: '[reason]' - color: 6514417 - fields: - - name: Duration - value: '[expires]' - inline: true - author: - name: BanManager - url: https://banmanagement.com - icon_url: https://banmanagement.com/images/banmanager-icon.png - footer: - text: 'By: [actor]' - icon_url: https://crafthead.net/helm/[actorId]/128 - thumbnail: - url: https://crafthead.net/helm/[playerId]/128 - unmute: - url: https://discord.com/api/webhooks/changeMe - ignoreSilent: true - payload: - embeds: - - title: '[player] unmuted' - description: '[reason]' - color: 2278750 - author: - name: BanManager - url: https://banmanagement.com - icon_url: https://banmanagement.com/images/banmanager-icon.png - footer: - text: 'By: [actor]' - icon_url: https://crafthead.net/helm/[actorId]/128 - thumbnail: - url: https://crafthead.net/helm/[playerId]/128 - tempwarning: - url: https://discord.com/api/webhooks/changeMe - ignoreSilent: true - payload: - embeds: - - title: '[player] warned' - description: '[reason]' - color: 16096779 - fields: - - name: Duration - value: '[expires]' - inline: true - - name: Points - value: '[points]' - inline: true - author: - name: BanManager - url: https://banmanagement.com - icon_url: https://banmanagement.com/images/banmanager-icon.png - footer: - text: 'By: [actor]' - icon_url: https://crafthead.net/helm/[actorId]/128 - thumbnail: - url: https://crafthead.net/helm/[playerId]/128 - warning: - url: https://discord.com/api/webhooks/changeMe - ignoreSilent: true - payload: - embeds: - - title: '[player] warned' - description: '[reason]' - color: 9584654 - fields: - - name: Points - value: '[points]' - inline: true - author: - name: BanManager - url: https://banmanagement.com - icon_url: https://banmanagement.com/images/banmanager-icon.png - footer: - text: 'By: [actor]' - icon_url: https://crafthead.net/helm/[actorId]/128 - thumbnail: - url: https://crafthead.net/helm/[playerId]/128 - report: - url: https://discord.com/api/webhooks/changeMe - ignoreSilent: true - payload: - embeds: - - title: '[player] reported' - description: '[reason]' - color: 16737894 - fields: - - name: '[player] location' - value: '[playerX] [playerY] [playerZ] [playerPitch] [playerYaw] [playerWorld]' - inline: true - - name: '[actor] location' - value: '[actorX] [actorY] [actorZ] [actorPitch] [actorYaw] [actorWorld]' - inline: true - author: - name: BanManager - url: https://banmanagement.com - icon_url: https://banmanagement.com/images/banmanager-icon.png - footer: - text: 'By: [actor]' - icon_url: https://crafthead.net/helm/[actorId]/128 - thumbnail: - url: https://crafthead.net/helm/[playerId]/128 diff --git a/e2e/platforms/sponge7/docker-compose.yml b/e2e/platforms/sponge7/docker-compose.yml deleted file mode 100644 index ff84e05db..000000000 --- a/e2e/platforms/sponge7/docker-compose.yml +++ /dev/null @@ -1,113 +0,0 @@ -# Sponge API 7 (Minecraft 1.12.2) E2E testing for BanManager -# Note: This is a legacy platform for backwards compatibility testing - -name: bm-sponge7 - -services: - webhook-sink: - image: node:22-alpine - working_dir: /app - command: ["node", "server.js"] - volumes: - - ../webhook-sink:/app:ro - healthcheck: - test: - [ - "CMD", - "node", - "-e", - "fetch('http://localhost:8080/health').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))", - ] - interval: 5s - timeout: 3s - retries: 20 - networks: - - banmanager - - mariadb: - image: mariadb:10.11 - environment: - MYSQL_ROOT_PASSWORD: root - MYSQL_DATABASE: banmanager - MYSQL_USER: banmanager - MYSQL_PASSWORD: banmanager - healthcheck: - test: ["CMD", "mariadb", "-uroot", "-proot", "-e", "SELECT 1"] - interval: 5s - timeout: 5s - retries: 10 - networks: - - banmanager - - sponge7: - image: itzg/minecraft-server:java8 - environment: - EULA: "TRUE" - TYPE: "CUSTOM" - # SpongeVanilla 1.12.2-7.3.0 is the latest stable for API 7 - CUSTOM_SERVER: "https://repo.spongepowered.org/repository/legacy-transfer/org/spongepowered/spongevanilla/1.12.2-7.3.0/spongevanilla-1.12.2-7.3.0.jar" - ONLINE_MODE: "false" - SKIP_SERVER_JAR_HASH_CHECK: "true" - ENABLE_RCON: "true" - RCON_PASSWORD: "testing" - RCON_PORT: 25575 - MEMORY: "2G" - SPAWN_PROTECTION: 0 - VIEW_DISTANCE: 4 - MAX_WORLD_SIZE: 100 - LEVEL_TYPE: "flat" - GENERATE_STRUCTURES: "false" - COPY_MODS_SRC: "/mods-src" - COPY_MODS_DEST: "/data/mods" - COPY_CONFIG_SRC: "/config-src" - COPY_CONFIG_DEST: "/data/config" - SYNC_SKIP_NEWER_IN_DESTINATION: "false" - volumes: - - ../../../sponge-api7/build/libs/BanManagerSponge7.jar:/mods-src/BanManager.jar:ro - - ./configs/banmanager:/config-src/banmanager:ro - - ./configs/sponge:/config-src/sponge:ro - - sponge7-data:/data - depends_on: - webhook-sink: - condition: service_healthy - mariadb: - condition: service_healthy - healthcheck: - test: ["CMD", "rcon-cli", "--password", "testing", "list"] - interval: 10s - timeout: 5s - retries: 30 - start_period: 180s - networks: - - banmanager - - tests: - image: ${E2E_TEST_IMAGE:-ghcr.io/banmanagement/banmanager-e2e-tests:main} - build: - context: ../.. - dockerfile: Dockerfile.tests - depends_on: - sponge7: - condition: service_healthy - webhook-sink: - condition: service_healthy - environment: - SERVER_HOST: sponge7 - SERVER_PORT: 25565 - RCON_HOST: sponge7 - RCON_PORT: 25575 - RCON_PASSWORD: testing - MC_VERSION: "1.12.2" - WEBHOOK_SINK_URL: "http://webhook-sink:8080" - volumes: - - jest-cache:/tmp/jest_cache - networks: - - banmanager - -networks: - banmanager: - driver: bridge - -volumes: - sponge7-data: - jest-cache: diff --git a/e2e/platforms/velocity/configs/banmanager/config.yml b/e2e/platforms/velocity/configs/banmanager/config.yml index 8581b02e3..4c59ef67e 100644 --- a/e2e/platforms/velocity/configs/banmanager/config.yml +++ b/e2e/platforms/velocity/configs/banmanager/config.yml @@ -1,5 +1,9 @@ # # Aliases will be found and blocked automatically, e.g. msg will block tell +locale: + default: en + perPlayer: true + debug: false databases: local: diff --git a/e2e/platforms/velocity/configs/banmanager/messages.yml b/e2e/platforms/velocity/configs/banmanager/messages.yml deleted file mode 100644 index 689b5c8c8..000000000 --- a/e2e/platforms/velocity/configs/banmanager/messages.yml +++ /dev/null @@ -1,424 +0,0 @@ -# Variables -# [reason] = Ban/Mute reason -# [player] = The name of the player -# [ip] = The banned ip -# [actor] = Who banned/muted -# [expires] = How long until the ban/mute ends - -messages: - duplicateIP: '&cWarning: [player] has the same IP as the following banned players:\n&6[players]' - duplicateIPAlts: '&cWarning: [player] has the same IP as the following players:\n&6[players]' - configReloaded: '�ff00Configuration &#ff5733reloaded &asuccessfully!' - deniedNotify: - player: '&cWarning: [player] attempted to join the server but was denied due to - &4[reason]' - ip: '&cWarning: [ip] attempted to join the server but was denied due to &4[reason]' - deniedMaxIp: '&cToo many players with your ip address online' - deniedMultiaccounts: '&cToo many players with your ip address logged in recently' - deniedCountry: '&cYou may not connect from your region' - time: - now: now - year: year - years: years - month: month - months: months - week: week - weeks: weeks - day: day - days: days - hour: hour - hours: hours - minute: minute - minutes: minutes - second: second - seconds: seconds - never: never - error: - invalid: '&cYour time length is invalid' - limit: '&cYou cannot perform this action for that length of time' - none: none - sender: - error: - notFound: '&c[player] not found, are you sure they exist?' - offline: '&c[player] is offline' - noSelf: '&cYou cannot perform that action on yourself!' - exception: '&cAn error occured whilst attempting to perform this command. Please - check the console for further details.' - invalidIp: '&cInvalid IP address, expecting w.x.y.z format' - offlinePermission: '&cYou are not allowed to perform this action on an offline - player' - exempt: '&c[player] is exempt from that action' - noPermission: '&cYou do not have permission to perform that action' - invalidReason: '&c[reason] is no valid reason.' - alts: - header: 'Possible alts found:' - names: - header: 'Known names for [player]:' - row: '&e[name] &7(first: [firstSeen], last: [lastSeen])' - dateTimeFormat: dd-MM-yyyy - none: '&7No name history found' - export: - error: - inProgress: '&cAn export is already in progress, please wait' - player: - started: '&aPlayer ban export started' - finished: '&aPlayer ban export finished, file [file] created' - ip: - started: '&aIP ban export started' - finished: '&aIP ban export finished, file [file] created' - import: - error: - inProgress: '&cAn import is already in progress, please wait' - player: - started: '&aPlayer ban import started' - finished: '&aPlayer ban import finished' - ip: - started: '&aIP ban import started' - finished: '&aIP ban import finished' - advancedban: - started: '&aAdvancedBan import started' - finished: '&aAdvancedBan import finished' - h2: - started: '&aH2 import started' - finished: '&aH2 import finished, please restart the server' - litebans: - started: '&aLiteBans import started' - finished: '&aLiteBans import finished' - info: - error: - invalidIndex: '&cInvalid player option used' - indexRequired: '&cMultiple players named [name] found, please select a player - by providing an index between 1 and [size], e.g. /bminfo [name] 1' - index: '&7#[index] - &6[name] - &4[uuid]' - stats: - player: '&6[player] has been banned [bans] times, muted [mutes] times, kicked - [kicks] times and warned [warns] times ([warnPoints] Points), has [notes] - notes and been reported [reports] times' - ip: '&6This ip has been banned [bans] times, muted [mutes] times and range banned - [rangebans] times' - connection: '&6Their last connection was with [ip] on [lastSeen]' - geoip: 'Country: [country] City: [city]' - ban: - permanent: '&6Currently banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently banned for &4[reason]&6 by [actor] at [created] which - expires in [expires]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - ipban: - permanent: '&6Currently banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently banned for &4[reason]&6 by [actor] at [created] which - expires in [expires]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - iprangeban: - permanent: '&6[from] - [to] banned for &4[reason]&6 by [actor] at [created]' - temporary: '&6[from] - [to] banned for &4[reason]&6 by [actor] at [created] - which expires in [expires]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - ipmute: - permanent: '&6Currently muted for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently muted for &4[reason]&6 by [actor] at [created] which - expires in [expires]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - mute: - permanent: '&6Currently muted for &4[reason]&6 by [actor] at [created]' - temporary: '&6Currently muted for &4[reason]&6 by [actor] at [created] which - expires in [expires]' - temporaryOnline: '&6Currently muted for &4[reason]&6 by [actor] at [created] - which expires in [expires] (online time)' - temporaryOnlinePaused: '&6Currently muted for &4[reason]&6 by [actor] at [created] - with [remaining] remaining (online time, paused)' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - website: - player: https://yourdomain.com/player/[uuid] - ip: http://yourdomain.com/index.php?action=viewip&ip=[ip]&server=0 - history: - row: '&7#[id] &a[&f[type]&a] &6[actor]&f [meta] [reason] - &e[created]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - noResults: '&cNo results found' - ips: - row: '&e[ip] - &6[join] - [leave]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - kick: - player: - noReason: '&6You have been kicked' - reason: '&6You have been kicked for &4[reason]' - notify: - noReason: '&6[player] has been kicked by [actor]' - reason: '&6[player] has been kicked by [actor] for &4[reason]' - kickall: - player: - noReason: '&6You have been kicked' - reason: '&6You have been kicked for &4[reason]' - notify: - noReason: All players have been kicked by [actor] - reason: All players have been kicked by [actor] for &4[reason] - ban: - player: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[player] has been permanently banned by [actor] for &4[reason]' - error: - exists: '&c[player] is already banned' - cooldown: '&cThis player was banned too recently, try again later' - banall: - notify: '&6[player] will be permanently banned by [actor] for &4[reason]' - tempban: - player: - disallowed: '&6You have been temporarily banned from this server for &4[reason] - \n&6It expires in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[player] has been temporarily banned for [expires] by [actor] for &4[reason]' - tempbanall: - notify: '&6[player] will be temporarily banned for [expires] by [actor] for &4[reason]' - unban: - notify: '&6[player] has been unbanned by [actor]' - error: - noExists: '&c[player] is not banned' - notOwn: '&c[player] was not banned by you, unable to unban' - unbanall: - notify: '&6[player] will be unbanned by [actor]' - mute: - player: - blocked: '&cYou may not use the [command] command whilst muted!' - disallowed: '&6You have been permanently muted for &4[reason] &6by [actor]' - broadcast: '&4[Muted] [player]&7 [message]' - notify: '&6[player] has been permanently muted by [actor] for &4[reason]' - error: - exists: '&c[player] is already muted' - cooldown: '&cThis player was muted too recently, try again later' - muteip: - ip: - disallowed: '&6You have been permanently muted for &4[reason] &6by [actor]' - broadcast: '&4[Muted] [player]&7 [message]' - notify: '&6[ip] ([players]) have been permanently muted by [actor] for &4[reason]' - error: - exists: '&c[ip] is already muted' - muteall: - notify: '&6[player] will be permanently muted by [actor] for &4[reason]' - tempmute: - player: - disallowed: '&6You have been temporarily muted for &4[reason] &6by [actor] which - expires in [expires]' - disallowedOnline: '&6You have been temporarily muted for &4[reason] &6by [actor] - which expires in [expires] (online time)' - notify: '&6[player] has been temporarily muted for [expires] by [actor] for &4[reason]' - notifyOnline: '&6[player] has been temporarily muted for [expires] (online time) - by [actor] for &4[reason]' - error: - exists: '&c[player] is already muted' - tempmuteip: - ip: - disallowed: '&6You have been temporarily muted for &4[reason] &6by [actor] which - expires in [expires]' - notify: '&6[ip] ([players]) have been temporarily muted for [expires] by [actor] - for &4[reason]' - error: - exists: '&c[ip] is already muted' - tempmuteall: - notify: '&6[player] will be temporarily muted for [expires] by [actor] for &4[reason]' - unmute: - notify: '&6[player] has been unmuted by [actor]' - player: '&6You have been unmuted by [actor]' - error: - noExists: '&c[player] is not muted' - notOwn: '&c[player] was not muted by you, unable to unmute' - unmuteip: - notify: '&6[ip] has been unmuted by [actor]' - error: - noExists: '&c[ip] is not muted' - notOwn: '&c[ip] was not muted by you, unable to unmute' - unmuteall: - notify: '&6[player] will be unmuted by [actor]' - banname: - name: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6Name [name] has been permanently banned by [actor] for &4[reason]' - error: - exists: '&cName [name] is already banned' - tempbanname: - name: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires - in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6Name [name] has been temporarily banned for [expires] by [actor] for - &4[reason]' - unbanname: - notify: '&6Name [name] has been unbanned by [actor]' - error: - noExists: '&cName [name] is not banned' - banip: - ip: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[ip] ([players]) has been permanently banned by [actor] for &4[reason]' - error: - exists: '&c[ip] is already banned' - cooldown: '&cThis ip was banned too recently, try again later' - baniprange: - error: - invalid: '&cInvalid range, please use cidr notation 192.168.0.1/16 or wildcard - 192.168.*.*' - minMax: '&cRange must be lowest to highest' - exists: '&cA ban containing those ranges already exists' - ip: - disallowed: '&6You have been banned from this server for &4[reason]' - kick: '&6You have been banned permanently for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[from] - [to] have been banned by [actor]' - tempbaniprange: - notify: '&6[from] - [to] has been temporarily banned for [expires] by [actor]' - ip: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires - in [expires]' - kick: '&6You have been temporarily banned for [expires] by [actor] for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - unbaniprange: - notify: '&6[from] - [to] has been unbanned by [actor]' - banipall: - notify: '&6[ip] will be permanently banned by [actor] for &4[reason]' - tempbanip: - ip: - disallowed: '&6You have been banned from this server for &4[reason] \n&6It expires - in [expires]' - kick: '&6You have been temporarily banned for &4[reason]' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: '&6[ip] ([players]) has been temporarily banned for [expires] by [actor] - for &4[reason]' - tempbanipall: - notify: '&6[ip] will be temporarily banned for [expires] by [actor] for &4[reason]' - unbanip: - notify: '&6[ip] has been unbanned by [actor]' - error: - noExists: '&c[ip] is not banned' - notOwn: '&c[ip] was not banned by you, unable to unban' - unbanipall: - notify: '&6[ip] will be unbanned by [actor]' - warn: - player: - warned: '&6You have been warned by [actor] for &4[reason]' - disallowed: - header: '&cYou may not speak until you have accepted your most recent warning. - Please type the following:' - reason: '&6[reason]' - removed: '&aThank you for your understanding, you may now speak again' - notify: '&6[player] has been warned by [actor] for &4[reason]' - error: - cooldown: '&cThis player was warned too recently, try again later' - tempwarn: - player: - warned: '&6You have been warned for [expires] by [actor] for &4[reason]' - notify: '&6[player] has been warned for [expires] by [actor] for &4[reason]' - dwarn: - player: - notify: '&6Your most recent warning has been deleted by &4[actor]' - notify: '&cThe most recent warning for [player] has been deleted' - error: - noWarnings: '&c[player] has no warnings to delete' - bmclear: - notify: '&c[player] has had their [type] cleared' - error: - invalid: '&cInvalid type, please choose between banrecords, muterecords, kicks, - notes or warnings' - bmutils: - missingplayers: - notify: '&c[amount] missing players added' - noneFound: '&a0 missing players found' - found: '&c[amount] missing player data found. Fixing...' - error: - failedLookup: '&cFailed to lookup player [uuid], check server logs' - complete: '&a[amount] players resolved, please restart your server for failed - punishments to take affect' - duplicates: - lookup: - notFound: '&aNo duplicate player names found' - error: - invalidName: '&cInvalid name, must be 16 characters or less and contain only - letters, numbers and an underscore' - nameExists: '&cA player with that name already exists' - success: '&aPlayer name set to [player] successfully' - bmrollback: - notify: '&c[player] has had their [type] actions undone' - error: - invalid: '&cInvalid type [type], please choose between [types]' - sync: - player: - started: '&aStarting force [type] synchronisation' - finished: '&aForced [type] synchronisation complete' - update: - notify: '&6[BanManager] &aAn update is available' - notes: - header: '&6[player] has the following notes:' - joinAmount: '&6[player] has &e[amount] &6notes, click to view them' - note: '&6[[player]] &e[message] - &e[created]' - playerNote: '&a[[player]] &6[[actor]] &e[message] - &e[created]' - dateTimeFormat: dd-MM-yyyy - notify: '[player] has a new note attached by [actor]: [message]' - error: - noNotes: '&c[player] has no notes' - noOnlineNotes: '&cNo online players have notes' - report: - notify: '&6[player] has been reported by [actor] for &4[reason]' - error: - cooldown: '&cThis player was reported too recently, try again later' - assign: - player: '&aReport [id] assigned to [player]' - notify: '&aYou have been assigned report [id] by [actor]' - unassign: - player: '&aReport [id] unassigned' - close: - notify: - closed: '&aReport [id] closed by [actor]' - command: '&aReport [id] closed by [actor] with [command]' - comment: '&aReport [id] closed by [actor] with [comment]' - dispatch: Executing command [command] - list: - noResults: '&cNo reports found' - error: - invalidState: '&cReport state [state] not found' - row: - dateTimeFormat: yyyy-MM-dd HH:mm:ss - header: '&e-- Reports ([count]) -- Page ([page]/[maxPage])' - all: '&7#[id] &e[[state]] &6- [created] - [player]' - tp: - error: - notFound: '&cReport not found' - worldNotFound: '&cWorld [world] could not be found' - invalidId: '&c[id] is not a valid report id' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: - report: '&7#[id] &6[actor] reported [player] for &4[reason]&6 at [created]' - location: '[world] - [x], [y], [z]' - info: - error: - notFound: '&cReport not found' - invalidId: '&c[id] is not a valid report id' - dateTimeFormat: yyyy-MM-dd HH:mm:ss - notify: - report: '&7#[id] &6[actor] reported [player] for &4[reason]&6 at [created]' - location: '[world] - [x], [y], [z]' - addnoteall: - notify: '&c[player] will have a new attached by [actor]: [message]' - banlist: - header: '&6There are [bans] [type] bans:' - bmactivity: - row: - all: '&a[&f[type]&a] &6[player]&f - &6[actor]&f - &e[created]' - player: '&a[&f[type]&a] &6[player]&f - &e[created]' - dateTimeFormat: dd-MM-yyyy HH:mm:ss - noResults: '&cNo results found' - bmdelete: - notify: '&a[rows] rows deleted' - error: - invalid: '&cInvalid type, please choose between banrecords, muterecords, kicks, - notes or warnings' - invalidId: '&c[id] is not a valid number' - denyalts: - player: - disallowed: '&cThe IP address you are joining from is linked to a banned player' - reasons: - row: '[hashtag] = [reason]' diff --git a/e2e/platforms/velocity/configs/banmanager/messages/messages_de.yml b/e2e/platforms/velocity/configs/banmanager/messages/messages_de.yml new file mode 100644 index 000000000..d813fecbc --- /dev/null +++ b/e2e/platforms/velocity/configs/banmanager/messages/messages_de.yml @@ -0,0 +1,16 @@ +messages: + configReloaded: '&aKonfiguration erfolgreich neu geladen!' + + ban: + player: + disallowed: '&6Du wurdest von diesem Server gebannt wegen &4[reason]' + kick: '&6Du wurdest dauerhaft gebannt wegen &4[reason]' + notify: '&6[player] wurde dauerhaft gebannt von [actor] wegen &4[reason]' + + unban: + notify: '&6[player] wurde von [actor] entbannt' + + mute: + player: + disallowed: '&6Du bist stummgeschaltet wegen &4[reason]' + notify: '&6[player] wurde dauerhaft stummgeschaltet von [actor] wegen &4[reason]' diff --git a/e2e/platforms/velocity/configs/banmanager/messages/messages_en.yml b/e2e/platforms/velocity/configs/banmanager/messages/messages_en.yml new file mode 100644 index 000000000..9da20bc47 --- /dev/null +++ b/e2e/platforms/velocity/configs/banmanager/messages/messages_en.yml @@ -0,0 +1,474 @@ +# Message templates use MiniMessage formatting: https://docs.advntr.dev/minimessage/format.html +# Placeholders use angle brackets, e.g. , , , , + +tokens: + appeal_url: 'https://yourdomain.com/appeal' + server_name: 'My Server' + discord_url: 'https://discord.gg/example' + rules_url: 'https://yourdomain.com/rules' + +messages: + duplicateIP: 'Warning: has the same IP as the following banned players:\n' + duplicateIPAlts: 'Warning: has the same IP as the following players:\n' + configReloaded: 'Configuration reloaded successfully!' + deniedNotify: + player: 'Warning: attempted to join the server but was denied due to ' + ip: 'Warning: attempted to join the server but was denied due to ' + deniedMaxIp: 'Too many players with your ip address online' + deniedMultiaccounts: 'Too many players with your ip address logged in recently' + deniedCountry: 'You may not connect from your region' + + time: + now: 'now' + year: 'year' + years: 'years' + month: 'month' + months: 'months' + week: 'week' + weeks: 'weeks' + day: 'day' + days: 'days' + hour: 'hour' + hours: 'hours' + minute: 'minute' + minutes: 'minutes' + second: 'second' + seconds: 'seconds' + never: 'never' + error: + invalid: 'Your time length is invalid' + limit: 'You cannot perform this action for that length of time' + + none: 'none' + # General command text + sender: + error: + notFound: ' not found, are you sure they exist?' + offline: ' is offline' + noSelf: 'You cannot perform that action on yourself!' + exception: 'An error occured whilst attempting to perform this command. Please check the console for further details.' + invalidIp: 'Invalid IP address, expecting w.x.y.z format' + offlinePermission: 'You are not allowed to perform this action on an offline player' + ambiguousPlayer: 'Multiple players match "". Please use their full name.' + exempt: ' is exempt from that action' + noPermission: 'You do not have permission to perform that action' + noConsole: 'This command cannot be used from console' + invalidReason: ' is not a valid reason.' + # Commands + alts: + header: 'Possible alts found:' + entry: '">' + separator: ', ' + + names: + header: 'Known names for :' + row: ' (first: , last: )' + interactive: ' (first: , last: )">">' + separator: ', ' + dateTimeFormat: 'dd-MM-yyyy' + none: 'No name history found' + + export: + error: + inProgress: 'An export is already in progress, please wait' + player: + started: 'Player ban export started' + finished: 'Player ban export finished, file created' + ip: + started: 'IP ban export started' + finished: 'IP ban export finished, file created' + + import: + error: + inProgress: 'An import is already in progress, please wait' + player: + started: 'Player ban import started' + finished: 'Player ban import finished' + ip: + started: 'IP ban import started' + finished: 'IP ban import finished' + advancedban: + started: 'AdvancedBan import started' + finished: 'AdvancedBan import finished' + h2: + started: 'H2 import started' + finished: 'H2 import finished, please restart the server' + litebans: + started: 'LiteBans import started' + finished: 'LiteBans import finished' + + info: + error: + invalidIndex: 'Invalid player option used' + indexRequired: 'Multiple players named found, please select a player by providing an index between 1 and , e.g. /bminfo 1' + index: '# - - ' + stats: + player: ' has been banned times, muted times, kicked times and warned + times ( Points), has notes and been reported times' + ip: 'This ip has been banned times, muted times and range banned times' + connection: 'Their last connection was with on ' + geoip: 'Country: City: ' + ban: + permanent: 'Currently banned for by at ' + temporary: 'Currently banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + ipban: + permanent: 'Currently banned for by at ' + temporary: 'Currently banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + iprangeban: + permanent: ' - banned for by at ' + temporary: ' - banned for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + ipmute: + permanent: 'Currently muted for by at ' + temporary: 'Currently muted for by at which expires in ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + mute: + permanent: 'Currently muted for by at ' + temporary: 'Currently muted for by at which expires in ' + temporaryOnline: 'Currently muted for by at which expires in (online time)' + temporaryOnlinePaused: 'Currently muted for by at with remaining (online time, paused)' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + website: + player: 'https://yourdomain.com/player/' + ip: 'http://yourdomain.com/index.php?action=viewip&ip=&server=0' + history: + row: '# [] - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + noResults: 'No results found' + ips: + row: ' - - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + + kick: + player: + noReason: 'You have been kicked' + reason: 'You have been kicked for ' + notify: + noReason: ' has been kicked by ">View player info">[Info]' + reason: ' has been kicked by for ">View player info">[Info]' + + kickall: + player: + noReason: 'You have been kicked' + reason: 'You have been kicked for ' + notify: + noReason: 'All players have been kicked by ' + reason: 'All players have been kicked by for ' + + ban: + player: + disallowed: 'You are banned from this server\n \nReason: \nBanned by: \nDate: \n \nAppeal at ' + kick: 'You have been banned\n \nReason: \nBanned by: \nDate: \n \nAppeal at ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' has been permanently banned by for ">View player info">[Info] ">Unban player">[Unban]' + error: + exists: ' is already banned' + cooldown: 'This player was banned too recently, try again later' + + banall: + notify: ' will be permanently banned by for ' + + tempban: + player: + disallowed: 'You are temporarily banned from this server\n \nReason: \nBanned by: \nExpires: \nDate: \n \nAppeal at ' + kick: 'You have been temporarily banned\n \nReason: \nBanned by: \nExpires: \nDate: \n \nAppeal at ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' has been temporarily banned for by for ">View player info">[Info] ">Unban player">[Unban]' + + tempbanall: + notify: ' will be temporarily banned for by for ' + + unban: + notify: ' has been unbanned by ' + error: + noExists: ' is not banned' + notOwn: ' was not banned by you, unable to unban' + + unbanall: + notify: ' will be unbanned by ' + + mute: + player: + blocked: 'You may not use the command whilst muted!' + disallowed: 'You have been permanently muted for by ' + broadcast: '[Muted] ' + notify: ' has been permanently muted by for ">View player info">[Info] ">Unmute player">[Unmute]' + error: + exists: ' is already muted' + cooldown: 'This player was muted too recently, try again later' + + muteip: + ip: + disallowed: 'You have been permanently muted for by ' + broadcast: '[Muted] ' + notify: ' () have been permanently muted by for ' + error: + exists: ' is already muted' + + muteall: + notify: ' will be permanently muted by for ' + + tempmute: + player: + disallowed: 'You have been temporarily muted for by which expires in ' + disallowedOnline: 'You have been temporarily muted for by which expires in (online time)' + notify: ' has been temporarily muted for by for ">View player info">[Info] ">Unmute player">[Unmute]' + notifyOnline: ' has been temporarily muted for (online time) by for ' + error: + exists: ' is already muted' + + tempmuteip: + ip: + disallowed: 'You have been temporarily muted for by which expires in ' + notify: ' () have been temporarily muted for by for ' + error: + exists: ' is already muted' + + tempmuteall: + notify: ' will be temporarily muted for by for ' + + unmute: + notify: ' has been unmuted by ' + player: 'You have been unmuted by ' + error: + noExists: ' is not muted' + notOwn: ' was not muted by you, unable to unmute' + + unmuteip: + notify: ' has been unmuted by ' + error: + noExists: ' is not muted' + notOwn: ' was not muted by you, unable to unmute' + + unmuteall: + notify: ' will be unmuted by ' + + banname: + name: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: 'Name has been permanently banned by for ' + error: + exists: 'Name is already banned' + + tempbanname: + name: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: 'Name has been temporarily banned for by for ' + + unbanname: + notify: 'Name has been unbanned by ' + error: + noExists: 'Name is not banned' + + banip: + ip: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' () has been permanently banned by for ' + error: + exists: ' is already banned' + cooldown: 'This ip was banned too recently, try again later' + + baniprange: + error: + invalid: 'Invalid range, please use cidr notation 192.168.0.1/16 or wildcard 192.168.*.*' + minMax: 'Range must be lowest to highest' + exists: 'A ban containing those ranges already exists' + ip: + disallowed: 'You have been banned from this server for ' + kick: 'You have been banned permanently for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' - have been banned by ' + + tempbaniprange: + notify: ' - has been temporarily banned for by ' + ip: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for by for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + + unbaniprange: + notify: ' - has been unbanned by ' + + banipall: + notify: ' will be permanently banned by for ' + + tempbanip: + ip: + disallowed: 'You have been banned from this server for \nIt expires in ' + kick: 'You have been temporarily banned for ' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: ' () has been temporarily banned for by for ' + + tempbanipall: + notify: ' will be temporarily banned for by for ' + + unbanip: + notify: ' has been unbanned by ' + error: + noExists: ' is not banned' + notOwn: ' was not banned by you, unable to unban' + + unbanipall: + notify: ' will be unbanned by ' + + warn: + player: + warned: 'You have been warned by for ' + disallowed: + header: 'You may not speak until you have accepted your most recent warning. Please type the following:' + reason: '' + removed: 'Thank you for your understanding, you may now speak again' + notify: ' has been warned by for ">View player info">[Info]' + error: + cooldown: 'This player was warned too recently, try again later' + + tempwarn: + player: + warned: 'You have been warned for by for ' + notify: ' has been warned for by for ">View player info">[Info]' + + dwarn: + player: + notify: 'Your most recent warning has been deleted by ' + notify: 'The most recent warning for has been deleted' + error: + noWarnings: ' has no warnings to delete' + + bmclear: + notify: ' has had their cleared' + error: + invalid: 'Invalid type, please choose between banrecords, muterecords, kicks, notes or warnings' + + bmutils: + missingplayers: + notify: ' missing players added' + noneFound: '0 missing players found' + found: ' missing player data found. Fixing...' + error: + failedLookup: 'Failed to lookup player , check server logs' + complete: ' players resolved, please restart your server for failed punishments to take affect' + duplicates: + lookup: + notFound: 'No duplicate player names found' + error: + invalidName: 'Invalid name, must be 16 characters or less and contain only letters, numbers and an underscore' + nameExists: 'A player with that name already exists' + success: 'Player name set to successfully' + + bmrollback: + notify: ' has had their actions undone' + error: + invalid: 'Invalid type , please choose between ' + + sync: + player: + started: 'Starting force synchronisation' + finished: 'Forced synchronisation complete' + + update: + notify: '[BanManager] An update is available' + + notes: + header: ' has the following notes:' + joinAmount: '"> has notes, click to view them' + note: '[] - ' + playerNote: '[] [] - ' + dateTimeFormat: 'dd-MM-yyyy' + notify: ' has a new note attached by : ' + error: + noNotes: ' has no notes' + noOnlineNotes: 'No online players have notes' + + report: + notify: ' has been reported by for ' + error: + cooldown: 'This player was reported too recently, try again later' + assign: + player: 'Report assigned to ' + notify: 'You have been assigned report by ' + unassign: + player: 'Report unassigned' + close: + notify: + closed: 'Report closed by ' + command: 'Report closed by with ' + comment: 'Report closed by with ' + dispatch: 'Executing command ' + list: + noResults: 'No reports found' + error: + invalidState: 'Report state not found' + row: + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + header: '-- Reports () -- Page (/)' + all: '">Click to view details"># [] - - ' + tp: + error: + notFound: 'Report not found' + worldNotFound: 'World could not be found' + invalidId: ' is not a valid report id' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: + report: '# reported for at ' + location: ' - , , ' + info: + error: + notFound: 'Report not found' + invalidId: ' is not a valid report id' + dateTimeFormat: 'yyyy-MM-dd HH:mm:ss' + notify: + report: '# reported for at ' + location: ' - , , ' + actions: + assign: '">Assign to yourself">[Assign]' + close: '">Close this report">[Close]' + tp: '">Teleport to location">[TP]' + feedback: + assigned: 'Your report # has been assigned to ' + closed: 'Your report # has been closed by ' + + addnoteall: + notify: ' will have a new note attached by : ' + + banlist: + header: 'There are bans:' + row: + player: '">Click for info"> - ' + ip: ' - ' + iprange: ' - - ' + + bmactivity: + row: + all: '[] - - ' + player: '[] - ' + dateTimeFormat: 'dd-MM-yyyy HH:mm:ss' + noResults: 'No results found' + + bmdelete: + notify: ' rows deleted' + error: + invalid: 'Invalid type, please choose between banrecords, muterecords, kicks, notes or warnings' + invalidId: ' is not a valid number' + + denyalts: + player: + disallowed: 'The IP address you are joining from is linked to a banned player' + + reasons: + row: ' = ' + + dashboard: + header: ' Staff Dashboard ' + activeBans: 'Active Bans: ' + activeMutes: 'Active Mutes: ' + openReports: 'Open Reports: View reports">[View]' + recentActivity: 'Recent Activity (24h): ' + footer: ' ' diff --git a/e2e/platforms/velocity/configs/banmanager/notifications.yml b/e2e/platforms/velocity/configs/banmanager/notifications.yml new file mode 100644 index 000000000..75b1fb646 --- /dev/null +++ b/e2e/platforms/velocity/configs/banmanager/notifications.yml @@ -0,0 +1,81 @@ +# Notifications Configuration +# Controls how punishment notifications are delivered to staff and players +# +# Each notification event can specify delivery channels: +# chat: true/false - Send via chat message (default: true) +# actionbar: true/false - Send via action bar (disappears after a few seconds) +# title: true/false - Send via title/subtitle overlay +# sound: '' - Sound to play (empty to disable). Use Minecraft sound names e.g. entity.experience_orb.pickup +# +# Title settings (only used when title: true): +# titleFadeIn: ticks for fade in (20 ticks = 1 second) +# titleStay: ticks to stay on screen +# titleFadeOut: ticks for fade out +# +# Sound settings: +# soundVolume: 0.0 - 1.0 +# soundPitch: 0.0 - 2.0 +# +# Platform notes: +# - BungeeCord: title, showTitle and playSound are not supported (ignored silently) +# - Sponge API7: playSound is not supported (ignored silently) +# - All other platforms (Bukkit/Paper, Velocity, Fabric, Sponge API8+) support all channels + +staff: + ban: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + tempban: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + mute: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + tempmute: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + warn: + chat: true + actionbar: false + title: false + sound: 'entity.experience_orb.pickup' + soundVolume: 1.0 + soundPitch: 1.0 + report: + chat: true + actionbar: false + title: false + sound: 'block.note_block.pling' + soundVolume: 1.0 + soundPitch: 1.0 + duplicateIp: + chat: true + actionbar: false + title: false + sound: '' + soundVolume: 1.0 + soundPitch: 1.0 + +player: + muted: + actionbar: true + warned: + sound: 'entity.villager.no' + soundVolume: 1.0 + soundPitch: 1.0 diff --git a/e2e/sync-configs.sh b/e2e/sync-configs.sh index b4869e2e3..c15036687 100755 --- a/e2e/sync-configs.sh +++ b/e2e/sync-configs.sh @@ -7,15 +7,10 @@ set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" COMMON_RESOURCES="$SCRIPT_DIR/../common/src/main/resources" -# Files that are shared across platforms (don't need test-specific modifications) +# Only sync files that are truly shared and don't contain test-specific settings. +# Most E2E config files (webhooks.yml, schedules.yml, etc.) are maintained +# per-platform with test-specific values (e.g. webhook-sink URLs, timing). SHARED_FILES=( - "console.yml" - "webhooks.yml" - "exemptions.yml" - "geoip.yml" - "messages.yml" - "reasons.yml" - "schedules.yml" ) # Platform config directories @@ -23,7 +18,6 @@ PLATFORM_CONFIGS=( "$SCRIPT_DIR/platforms/bukkit/configs" "$SCRIPT_DIR/platforms/fabric/configs" "$SCRIPT_DIR/platforms/sponge/configs/banmanager" - "$SCRIPT_DIR/platforms/sponge7/configs/banmanager" "$SCRIPT_DIR/platforms/velocity/configs/banmanager" "$SCRIPT_DIR/platforms/bungee/configs/banmanager" ) @@ -38,10 +32,15 @@ for config_dir in "${PLATFORM_CONFIGS[@]}"; do cp "$COMMON_RESOURCES/$file" "$config_dir/" fi done + + if [ -d "$COMMON_RESOURCES/messages" ]; then + mkdir -p "$config_dir/messages" + cp "$COMMON_RESOURCES/messages/"*.yml "$config_dir/messages/" + fi fi done -echo "Done! Synced ${#SHARED_FILES[@]} files to ${#PLATFORM_CONFIGS[@]} locations." +echo "Done! Synced messages/ directory to ${#PLATFORM_CONFIGS[@]} locations." echo "" -echo "Note: config.yml files are NOT synced as they contain test-specific settings" -echo " (database host, chatPriority, etc.)" +echo "Note: Only the messages/ directory is synced automatically." +echo " Other config files are maintained per-platform with test-specific settings." diff --git a/e2e/tests/src/hex-colors.test.ts b/e2e/tests/src/hex-colors.test.ts index 817f197c7..6d1b8d72e 100644 --- a/e2e/tests/src/hex-colors.test.ts +++ b/e2e/tests/src/hex-colors.test.ts @@ -37,7 +37,7 @@ describe('Hex Color Support E2E Tests', () => { }) test('hex color message is received correctly', async () => { - // configReloaded in messages.yml uses &#rrggbb hex colors + // configReloaded in messages.yml uses MiniMessage hex colors (<#rrggbb>) await bot.sendChat('/bmreload') await waitFor( @@ -65,8 +65,8 @@ describe('Hex Color Support E2E Tests', () => { }, 30000) test('hex colors are processed correctly', async () => { - // configReloaded: '�ff00Configuration &#ff5733reloaded &asuccessfully!' - // - Bukkit/Bungee/Sponge: hex downsampled to legacy codes (&2, &c) + // configReloaded: '<#00ff00>Configuration <#ff5733>reloaded successfully!' + // - Bukkit/Bungee/Sponge: colors may downsample when sent to legacy clients // - Velocity/Fabric: full hex preserved in JSON await bot.sendChat('/bmreload') diff --git a/e2e/tests/src/locale-smoke.test.ts b/e2e/tests/src/locale-smoke.test.ts new file mode 100644 index 000000000..70d890955 --- /dev/null +++ b/e2e/tests/src/locale-smoke.test.ts @@ -0,0 +1,126 @@ +import { TestBot, createBot } from './helpers/bot' +import { + connectRcon, + disconnectRcon, + banPlayer, + unbanPlayer, + opPlayer, + reloadPlugin, + sendCommand, + isPlayerInList, + isProxy +} from './helpers/rcon' +import { sleep, waitFor } from './helpers/config' + +describe('Locale Smoke Tests', () => { + let staffBot: TestBot + const STAFF_USERNAME = 'LocaleStaff' + const TARGET_USERNAME = 'LocaleTarget' + + beforeAll(async () => { + await connectRcon() + + staffBot = await createBot(STAFF_USERNAME) + await waitFor( + async () => isPlayerInList(STAFF_USERNAME), + { timeout: 10000, interval: 500, message: 'Staff bot not in player list' } + ) + + await opPlayer(STAFF_USERNAME) + await sleep(3500) + }, 120000) + + afterAll(async () => { + try { await unbanPlayer(TARGET_USERNAME) } catch { /* ignore */ } + if (staffBot != null) await staffBot.disconnect() + await disconnectRcon() + }) + + beforeEach(async () => { + staffBot.clearChatHistory() + staffBot.clearSystemMessages() + + try { await unbanPlayer(TARGET_USERNAME) } catch { /* ignore */ } + await sleep(3000) + }) + + test('ban notification uses default locale messages', async () => { + staffBot.clearSystemMessages() + + await banPlayer(TARGET_USERNAME, 'locale-test') + + await waitFor( + () => staffBot.getSystemMessages().some(m => + m.message.toLowerCase().includes('banned') && + m.message.toLowerCase().includes(TARGET_USERNAME.toLowerCase()) + ), + { timeout: 10000, interval: 200, message: 'Ban notification not received' } + ) + + const banNotification = staffBot.getSystemMessages().find(m => + m.message.toLowerCase().includes('banned') && + m.message.toLowerCase().includes(TARGET_USERNAME.toLowerCase()) + ) + + expect(banNotification).toBeDefined() + expect(banNotification!.message).toContain('permanently banned') + expect(banNotification!.message).toContain('locale-test') + }, 30000) + + test('messages survive bmreload', async () => { + await reloadPlugin() + await sleep(2000) + + staffBot.clearSystemMessages() + + await banPlayer(TARGET_USERNAME, 'post-reload') + + await waitFor( + () => staffBot.getSystemMessages().some(m => + m.message.toLowerCase().includes('banned') && + m.message.toLowerCase().includes(TARGET_USERNAME.toLowerCase()) + ), + { timeout: 10000, interval: 200, message: 'Ban notification not received after reload' } + ) + + const banNotification = staffBot.getSystemMessages().find(m => + m.message.toLowerCase().includes('banned') && + m.message.toLowerCase().includes(TARGET_USERNAME.toLowerCase()) + ) + + expect(banNotification).toBeDefined() + expect(banNotification!.message).toContain('permanently banned') + expect(banNotification!.message).toContain('post-reload') + }, 30000) + + test('non-default locale messages loaded after reload', async () => { + // Reload to ensure messages/ directory is scanned (including messages_de.yml) + const reloadResponse = await reloadPlugin() + await sleep(2000) + + // The reload should succeed without error, confirming the i18n + // message loading pipeline works with multiple locale files + const isSponge = (process.env.SERVER_HOST ?? 'localhost').toLowerCase().includes('sponge') + if (!isSponge) { + expect(reloadResponse.toLowerCase()).toContain('reloaded') + } + + // Verify the server still functions correctly after loading multiple locales + staffBot.clearSystemMessages() + await banPlayer(TARGET_USERNAME, 'multi-locale') + + await waitFor( + () => staffBot.getSystemMessages().some(m => + m.message.toLowerCase().includes(TARGET_USERNAME.toLowerCase()) + ), + { timeout: 10000, interval: 200, message: 'Ban notification not received with multiple locales loaded' } + ) + + const notification = staffBot.getSystemMessages().find(m => + m.message.toLowerCase().includes(TARGET_USERNAME.toLowerCase()) && + m.message.toLowerCase().includes('multi-locale') + ) + + expect(notification).toBeDefined() + }, 30000) +}) diff --git a/fabric/src/main/java/me/confuser/banmanager/fabric/BMFabricPlugin.java b/fabric/src/main/java/me/confuser/banmanager/fabric/BMFabricPlugin.java index 21fbc1762..f57eaa93b 100644 --- a/fabric/src/main/java/me/confuser/banmanager/fabric/BMFabricPlugin.java +++ b/fabric/src/main/java/me/confuser/banmanager/fabric/BMFabricPlugin.java @@ -49,7 +49,7 @@ public class BMFabricPlugin implements DedicatedServerModInitializer { "webhooks.yml", "exemptions.yml", "geoip.yml", - "messages.yml", + "notifications.yml", "reasons.yml", "schedules.yml" }; diff --git a/fabric/src/main/java/me/confuser/banmanager/fabric/FabricPlayer.java b/fabric/src/main/java/me/confuser/banmanager/fabric/FabricPlayer.java index a81e05645..fd25707e9 100644 --- a/fabric/src/main/java/me/confuser/banmanager/fabric/FabricPlayer.java +++ b/fabric/src/main/java/me/confuser/banmanager/fabric/FabricPlayer.java @@ -11,10 +11,13 @@ import me.confuser.banmanager.common.BanManagerPlugin; import me.confuser.banmanager.common.CommonPlayer; import me.confuser.banmanager.common.CommonWorld; +import me.confuser.banmanager.common.kyori.text.Component; import me.confuser.banmanager.common.kyori.text.TextComponent; import me.confuser.banmanager.common.kyori.text.serializer.gson.GsonComponentSerializer; import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.util.Message; +import me.confuser.banmanager.common.util.MessageRenderer; +import me.confuser.banmanager.common.util.MessageRegistry; import me.confuser.banmanager.common.util.UUIDUtils; //? if >=1.21.1 import net.minecraft.network.packet.s2c.play.PositionFlag; @@ -40,6 +43,11 @@ public void kick(String message) { this.player.networkHandler.disconnect(FabricServer.formatMessage(message)); } + @Override + public void kick(Component component) { + this.player.networkHandler.disconnect(FabricServer.formatJsonMessage(MessageRenderer.getInstance().toJson(component))); + } + public void sendMessage(String message) { if(message.isEmpty()) return; @@ -50,8 +58,51 @@ public void sendMessage(String message) { } } - public void sendMessage(Message message) { - sendMessage(message.toString()); + @Override + public void sendMessage(Component component) { + getPlayer().sendMessage(FabricServer.formatJsonMessage(MessageRenderer.getInstance().toJson(component))); + } + + @Override + public void sendActionBar(Component component) { + getPlayer().sendMessage(FabricServer.formatJsonMessage(MessageRenderer.getInstance().toJson(component)), true); + } + + @Override + public void showTitle(Component title, Component subtitle, int fadeIn, int stay, int fadeOut) { + ServerPlayerEntity p = getPlayer(); + if (p == null) return; + MessageRenderer renderer = MessageRenderer.getInstance(); + if (title != null) { + net.minecraft.text.Text titleText = FabricServer.formatJsonMessage(renderer.toJson(title)); + p.networkHandler.sendPacket(new net.minecraft.network.packet.s2c.play.TitleS2CPacket(titleText)); + } + if (subtitle != null) { + net.minecraft.text.Text subtitleText = FabricServer.formatJsonMessage(renderer.toJson(subtitle)); + p.networkHandler.sendPacket(new net.minecraft.network.packet.s2c.play.SubtitleS2CPacket(subtitleText)); + } + p.networkHandler.sendPacket(new net.minecraft.network.packet.s2c.play.TitleFadeS2CPacket(fadeIn, stay, fadeOut)); + } + + @Override + public void playSound(String sound, float volume, float pitch) { + ServerPlayerEntity p = getPlayer(); + if (p == null) return; + try { + //? if >=1.21 { + net.minecraft.util.Identifier id = net.minecraft.util.Identifier.of(sound); + //?} else { + /*net.minecraft.util.Identifier id = new net.minecraft.util.Identifier(sound); + *///?} + net.minecraft.sound.SoundEvent event = net.minecraft.sound.SoundEvent.of(id); + //? if >=1.21.11 { + p.getEntityWorld().playSound(null, p.getBlockPos(), event, net.minecraft.sound.SoundCategory.MASTER, volume, pitch); + //?} else { + /*p.getWorld().playSound(null, p.getBlockPos(), event, net.minecraft.sound.SoundCategory.MASTER, volume, pitch); + *///?} + } catch (IllegalArgumentException ignored) { + // Invalid sound key or identifier -- silently ignore + } } @Override @@ -134,6 +185,18 @@ public boolean isOnline() { return getPlayer() != null && !getPlayer().isDisconnected(); } + @Override + public String getLocale() { + ServerPlayerEntity p = getPlayer(); + if (p == null) return "en"; + //? if >=1.21 { + return MessageRegistry.normaliseLocale(p.getClientOptions().language()); + //?} else { + /*// No public API for client language pre-1.21; fall back to default + return "en"; + *///?} + } + private ServerPlayerEntity getPlayer() { if (player != null) return player; if (isOnlineMode()) return this.server.getPlayerManager().getPlayer(uuid); diff --git a/fabric/src/main/java/me/confuser/banmanager/fabric/FabricSender.java b/fabric/src/main/java/me/confuser/banmanager/fabric/FabricSender.java index 187f670d8..308884b69 100644 --- a/fabric/src/main/java/me/confuser/banmanager/fabric/FabricSender.java +++ b/fabric/src/main/java/me/confuser/banmanager/fabric/FabricSender.java @@ -35,11 +35,6 @@ public void sendMessage(String message) { sender.sendMessage(FabricServer.formatMessage(message)); } - @Override - public void sendMessage(Message message) { - sendMessage(message.toString()); - } - @Override public boolean isConsole() { return !sender.isExecutedByPlayer(); diff --git a/fabric/src/main/java/me/confuser/banmanager/fabric/FabricServer.java b/fabric/src/main/java/me/confuser/banmanager/fabric/FabricServer.java index b5d474e99..4ddef55f8 100644 --- a/fabric/src/main/java/me/confuser/banmanager/fabric/FabricServer.java +++ b/fabric/src/main/java/me/confuser/banmanager/fabric/FabricServer.java @@ -31,7 +31,7 @@ import me.confuser.banmanager.common.data.PlayerNoteData; import me.confuser.banmanager.common.data.PlayerReportData; import me.confuser.banmanager.common.data.PlayerWarnData; -import me.confuser.banmanager.common.kyori.text.TextComponent; +import me.confuser.banmanager.common.kyori.text.Component; import me.confuser.banmanager.common.kyori.text.serializer.gson.GsonComponentSerializer; import me.confuser.banmanager.common.kyori.text.serializer.legacy.LegacyComponentSerializer; import com.google.gson.JsonElement; @@ -96,12 +96,6 @@ public void broadcast(String message, String permission) { getConsoleSender().sendMessage(message); } - public void broadcastJSON(TextComponent message, String permission) { - Arrays.stream(getOnlinePlayers()) - .filter(player -> player.hasPermission(permission)) - .forEach(player -> player.sendJSONMessage(message)); - } - public void broadcast(String message, String permission, CommonSender sender) { broadcast(message, permission); @@ -350,10 +344,10 @@ public static Text formatMessage(String message) { } public static Text formatMessage(Message message) { - return formatMessage(message.toString()); + return formatMessage(message.resolveComponent()); } - public static Text formatMessage(TextComponent message) { + public static Text formatMessage(Component message) { //? if >=1.21 { return TextCodecs.CODEC .decode(JsonOps.INSTANCE, JsonParser.parseString(GsonComponentSerializer.gson().serialize(message))) diff --git a/fabric/src/main/java/me/confuser/banmanager/fabric/listeners/JoinListener.java b/fabric/src/main/java/me/confuser/banmanager/fabric/listeners/JoinListener.java index 85695a04d..8d5d38d0e 100644 --- a/fabric/src/main/java/me/confuser/banmanager/fabric/listeners/JoinListener.java +++ b/fabric/src/main/java/me/confuser/banmanager/fabric/listeners/JoinListener.java @@ -59,8 +59,9 @@ private class BanJoinHandler implements CommonJoinHandler { @Override public void handlePlayerDeny(PlayerData player, Message message) { plugin.getServer().callEvent("PlayerDeniedEvent", player, message); - - handleDeny(message); + String locale = player.getLocale() != null ? player.getLocale() : "en"; + isDenied = true; + handler.disconnect(FabricServer.formatMessage(message.resolveComponent(locale))); } @Override diff --git a/fabric/src/main/resources/messages b/fabric/src/main/resources/messages new file mode 120000 index 000000000..4f36bf40c --- /dev/null +++ b/fabric/src/main/resources/messages @@ -0,0 +1 @@ +../../../../common/src/main/resources/messages \ No newline at end of file diff --git a/fabric/src/main/resources/messages.yml b/fabric/src/main/resources/messages.yml deleted file mode 120000 index 2da3a2d0a..000000000 --- a/fabric/src/main/resources/messages.yml +++ /dev/null @@ -1 +0,0 @@ -../../../../common/src/main/resources/messages.yml \ No newline at end of file diff --git a/libs/build.gradle.kts b/libs/build.gradle.kts index bdffcc3f9..47058d1e5 100644 --- a/libs/build.gradle.kts +++ b/libs/build.gradle.kts @@ -5,8 +5,14 @@ applyLibrariesConfiguration() dependencies { "shade"("net.kyori:adventure-text-serializer-legacy:${Versions.ADVENTURE}") "shade"("net.kyori:adventure-text-serializer-gson:${Versions.ADVENTURE}") + "shade"("net.kyori:adventure-text-serializer-json:${Versions.ADVENTURE}") + "shade"("net.kyori:adventure-text-serializer-plain:${Versions.ADVENTURE}") + "shade"("net.kyori:adventure-text-minimessage:${Versions.ADVENTURE}") "shade"("net.kyori:adventure-api:${Versions.ADVENTURE}") + "shade"("net.kyori:adventure-text-serializer-commons:${Versions.ADVENTURE}") "shade"("net.kyori:examination-api:1.3.0") + "shade"("net.kyori:examination-string:1.3.0") + "shade"("net.kyori:option:1.1.0") "shade"("com.j256.ormlite:ormlite-core:5.1") "shade"("com.j256.ormlite:ormlite-jdbc:5.1") @@ -38,12 +44,21 @@ tasks.named("jar") { relocate("net.kyori.adventure", "me.confuser.banmanager.common.kyori") { include(dependency("net.kyori:adventure-text-serializer-legacy")) include(dependency("net.kyori:adventure-text-serializer-gson")) + include(dependency("net.kyori:adventure-text-serializer-json")) + include(dependency("net.kyori:adventure-text-serializer-plain")) + include(dependency("net.kyori:adventure-text-serializer-commons")) + include(dependency("net.kyori:adventure-text-minimessage")) include(dependency("net.kyori:adventure-api")) include(dependency("net.kyori:adventure-key")) } relocate("net.kyori.examination", "me.confuser.banmanager.common.kyori.examination") { include(dependency("net.kyori:examination-api")) + include(dependency("net.kyori:examination-string")) + } + + relocate("net.kyori.option", "me.confuser.banmanager.common.kyori.option") { + include(dependency("net.kyori:option")) } relocate("org.yaml.snakeyaml", "me.confuser.banmanager.common.snakeyaml") { diff --git a/settings.gradle.kts b/settings.gradle.kts index 633212835..692a30d36 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -18,7 +18,6 @@ include(":BanManagerCommon") include(":BanManagerBukkit") include(":BanManagerBungee") include(":BanManagerSponge") -include(":BanManagerSponge7") include(":BanManagerLibs") include(":BanManagerVelocity") include(":BanManagerE2E") @@ -27,7 +26,6 @@ project(":BanManagerCommon").projectDir = file("common") project(":BanManagerBukkit").projectDir = file("bukkit") project(":BanManagerBungee").projectDir = file("bungee") project(":BanManagerSponge").projectDir = file("sponge") -project(":BanManagerSponge7").projectDir = file("sponge-api7") project(":BanManagerLibs").projectDir = file("libs") project(":BanManagerVelocity").projectDir = file("velocity") project(":BanManagerE2E").projectDir = file("e2e") diff --git a/sponge-api7/build.gradle.kts b/sponge-api7/build.gradle.kts deleted file mode 100644 index eea753630..000000000 --- a/sponge-api7/build.gradle.kts +++ /dev/null @@ -1,182 +0,0 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import org.spongepowered.gradle.plugin.config.PluginLoaders -import org.spongepowered.plugin.metadata.model.PluginDependency -import com.vanniktech.maven.publish.JavaLibrary -import com.vanniktech.maven.publish.JavadocJar - -plugins { - `java-library` - id("org.spongepowered.gradle.plugin") - id("net.kyori.blossom") version "2.2.0" - id("com.vanniktech.maven.publish") -} - -applyPlatformAndCoreConfiguration() -applyShadowConfiguration() - -mavenPublishing { - publishToMavenCentral() - if (project.hasProperty("signingInMemoryKey")) { - signAllPublications() - } - - configure(JavaLibrary( - javadocJar = JavadocJar.Javadoc(), - sourcesJar = true - )) - - pom { - name.set("BanManagerSponge7") - description.set("BanManager for Sponge API 7 (Legacy)") - url.set("https://github.com/BanManagement/BanManager/") - licenses { - license { - name.set("Creative Commons Attribution-NonCommercial-ShareAlike 2.0 UK: England & Wales") - url.set("https://github.com/BanManagement/BanManager/blob/master/LICENCE") - } - } - developers { - developer { - id.set("confuser") - name.set("James Mortemore") - email.set("jamesmortemore@gmail.com") - } - } - scm { - connection.set("scm:git:git://github.com/BanManagement/BanManager.git") - developerConnection.set("scm:git:ssh://git@github.com/BanManagement/BanManager.git") - url.set("https://github.com/BanManagement/BanManager/") - } - } -} - -sourceSets { - main { - blossom { - resources { - property("@projectVersion@", (project.ext["internalVersion"] as String)) - } - } - } -} - -sponge { - apiVersion("7.2.0") - loader { - name(PluginLoaders.JAVA_PLAIN) - version("1.0") - } - - license("Creative Commons Attribution-NonCommercial-ShareAlike 2.0 UK: England & Wales") - - plugin("banmanager") { - displayName("BanManager") - entrypoint("me.confuser.banmanager.sponge.BMSpongePlugin") - description("A database driven punishment system") - links { - homepage("https://banmanagement.com/") - source("https://github.com/BanManagment/BanManager") - issues("https://github.com/BanManagment/BanManager") - } - contributor("confuser") { - description("Lead Developer") - } - dependency("spongeapi") { - loadOrder(PluginDependency.LoadOrder.AFTER) - optional(false) - version("7.2.0") - } - } -} - -repositories { - maven { - name = "sponge" - url = uri("https://repo.spongepowered.org/maven/") - } - maven { - name = "jitpack" - url = uri("https://jitpack.io/") - metadataSources { - artifact() //Look directly for artifact - } - } - maven { - name = "jcenter" - url = uri("https://jcenter.bintray.com/") - } -} - -configurations { - compileClasspath.get().extendsFrom(create("shadeOnly")) -} - -dependencies { - compileOnly("org.spongepowered:spongeapi:7.2.0") - - api(project(":BanManagerCommon")) { - isTransitive = true - } - "shadeOnly"("org.bstats:bstats-sponge:2.2.1") -} - -val javaTarget = 8 // Sponge targets a minimum of Java 8 -java { - sourceCompatibility = JavaVersion.toVersion(javaTarget) - targetCompatibility = JavaVersion.toVersion(javaTarget) -} - -tasks.named("processResources") { - val internalVersion = project.ext["internalVersion"] as String - - inputs.property("internalVersion", internalVersion) - - filesMatching("plugin.yml") { - expand("internalVersion" to internalVersion, "mainPath" to "me.confuser.banmanager.sponge.BMSpongePlugin") - } -} - -tasks.named("jar") { - val projectVersion = project.version - inputs.property("projectVersion", projectVersion) - manifest { - attributes("Implementation-Version" to projectVersion) - } -} - -tasks.named("shadowJar") { - configurations = listOf(project.configurations["shadeOnly"], project.configurations["runtimeClasspath"]) - - archiveBaseName.set("BanManagerSponge7") - archiveClassifier.set("") - archiveVersion.set("") - - dependencies { - include(dependency(":BanManagerCommon")) - include(dependency(":BanManagerLibs")) - include(dependency("org.bstats:.*:.*")) - - relocate("org.bstats", "me.confuser.banmanager.common.bstats") - } - - exclude("GradleStart**") - exclude(".cache"); - exclude("LICENSE*") - exclude("META-INF/services/**") - exclude("META-INF/maven/**") - exclude("META-INF/versions/**") - exclude("org/intellij/**") - exclude("org/jetbrains/**") - exclude("**/module-info.class") - exclude("*.yml") - exclude("assets/banmanager/bungeecord.yml") - exclude("assets/banmanager/velocity.yml") - - minimize { - exclude(dependency("org.bstats:.*:.*")) - } -} - -tasks.named("assemble").configure { - dependsOn("shadowJar") -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/BMSpongePlugin.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/BMSpongePlugin.java deleted file mode 100644 index efb180955..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/BMSpongePlugin.java +++ /dev/null @@ -1,264 +0,0 @@ -package me.confuser.banmanager.sponge; - -import com.google.inject.Inject; -import me.confuser.banmanager.common.BanManagerPlugin; -import me.confuser.banmanager.common.CommonLogger; -import me.confuser.banmanager.common.commands.CommonCommand; -import me.confuser.banmanager.common.configs.PluginInfo; -import me.confuser.banmanager.common.configuration.ConfigurationSection; -import me.confuser.banmanager.common.configuration.file.YamlConfiguration; -import me.confuser.banmanager.common.runnables.*; -import me.confuser.banmanager.sponge.listeners.*; -import org.bstats.sponge.Metrics; -import org.slf4j.Logger; -import org.spongepowered.api.Sponge; -import org.spongepowered.api.config.ConfigDir; -import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.Order; -import org.spongepowered.api.event.game.state.GameLoadCompleteEvent; -import org.spongepowered.api.event.game.state.GamePreInitializationEvent; -import org.spongepowered.api.event.game.state.GameStoppingServerEvent; -import org.spongepowered.api.event.message.MessageChannelEvent; -import org.spongepowered.api.plugin.Plugin; -import org.spongepowered.api.plugin.PluginContainer; -import org.spongepowered.api.plugin.Dependency; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.time.Duration; -import java.util.HashMap; - -@Plugin( - id = "banmanager", - name = "BanManager", - version = "@projectVersion@", - authors = "confuser", - description = "A punishment plugin", - url = "https://banmanagement.com", - dependencies = {} -) -public class BMSpongePlugin { - - private CommonLogger logger; - private BanManagerPlugin plugin; - private Metrics metrics; - private ChatListener chatListener; - private SpongeScheduler scheduler; - - @Inject - @ConfigDir(sharedRoot = false) - private Path dataFolder; - - @Inject - private PluginContainer pluginContainer; - - private String[] configs = new String[]{ - "config.yml", - "console.yml", - "webhooks.yml", - "exemptions.yml", - "geoip.yml", - "messages.yml", - "reasons.yml", - "schedules.yml" - }; - - @Inject - public BMSpongePlugin(Logger logger, Metrics.Factory metrics) { - this.logger = new PluginLogger(logger); - this.metrics = metrics.make(6413); - } - - @Listener - public void onDisable(GameStoppingServerEvent event) { - scheduler.cancelAll(); - - if (plugin != null) plugin.disable(); - } - - @Listener - public void onEnable(GamePreInitializationEvent event) { - SpongeServer server = new SpongeServer(); - PluginInfo pluginInfo; - try { - pluginInfo = setupConfigs(); - } catch (IOException e) { - logger.warning("Failed to set up plugin configuration", e); - return; - } - - this.scheduler = new SpongeScheduler(this); - this.plugin = new BanManagerPlugin(pluginInfo, this.logger, dataFolder.toFile(), scheduler, server, new SpongeMetrics(metrics)); - - server.enable(plugin); - - try { - plugin.enable(); - } catch (Exception e) { - logger.severe("Unable to start BanManager"); - logger.warning("Failed to enable BanManager", e); - return; - } - - - setupListeners(); - setupCommands(); - setupRunnables(); - } - - @Listener - public void onStart(GameLoadCompleteEvent event) { - plugin.getLogger().info("The following commands are blocked whilst muted:"); - plugin.getConfig().handleBlockedCommands(plugin, plugin.getConfig().getMutedBlacklistCommands()); - - plugin.getLogger().info("The following commands are blocked whilst soft muted:"); - plugin.getConfig().handleBlockedCommands(plugin, plugin.getConfig().getSoftMutedBlacklistCommands()); - } - - public CommonLogger getLogger() { - return logger; - } - - private PluginInfo setupConfigs() throws IOException { - for (String name : configs) { - File file = new File(dataFolder.toFile(), name); - if (file.exists()) { - try (InputStream in = pluginContainer.getAsset(name).get().getUrl().openStream(); - Reader defConfigStream = new InputStreamReader(in, StandardCharsets.UTF_8)) { - YamlConfiguration conf = YamlConfiguration.loadConfiguration(file); - YamlConfiguration defConfig = YamlConfiguration.loadConfiguration(defConfigStream); - conf.setDefaults(defConfig); - conf.options().copyDefaults(true); - conf.save(file); - } - } else { - pluginContainer.getAsset(name).get().copyToDirectory(dataFolder); - } - } - - PluginInfo pluginInfo = new PluginInfo(); - try (InputStream in = pluginContainer.getAsset("plugin.yml").get().getUrl().openStream(); - Reader defConfigStream = new InputStreamReader(in, StandardCharsets.UTF_8)) { - YamlConfiguration conf = YamlConfiguration.loadConfiguration(defConfigStream); - ConfigurationSection commands = conf.getConfigurationSection("commands"); - String pluginName = conf.getString("name"); - - if (!pluginName.equals("BanManager")) { - throw new IOException("Unable to start BanManager as " + pluginName + " has broken resource loading forcing BanManager to load their plugin.yml file; please alert the author to resolve this issue"); - } - - for (String command : commands.getKeys(false)) { - ConfigurationSection cmd = commands.getConfigurationSection(command); - pluginInfo.setCommand(new PluginInfo.CommandInfo(command, cmd.getString("permission"), cmd.getString("usage"), cmd.getStringList("aliases"))); - } - } - - return pluginInfo; - } - - public void setupListeners() { - registerEvent(new JoinListener(plugin)); - registerEvent(new LeaveListener(plugin)); - registerEvent(new CommandListener(plugin)); - registerEvent(new HookListener(plugin)); - - registerChatListener(); - - registerEvent(new ReloadListener(this)); - - if (plugin.getConfig().isDisplayNotificationsEnabled()) { - registerEvent(new BanListener(plugin)); - registerEvent(new MuteListener(plugin)); - registerEvent(new NoteListener(plugin)); - registerEvent(new ReportListener(plugin)); - } - - if (plugin.getWebhookConfig().isHooksEnabled()) { - registerEvent(new WebhookListener(plugin)); - } - } - - private void unregisterChatListener() { - if (chatListener != null) { - Sponge.getEventManager().unregisterListeners(chatListener); - chatListener = null; - } - } - - public void registerChatListener() { - unregisterChatListener(); - - String chatPriority = plugin.getConfig().getChatPriority(); - if (!chatPriority.equals("NONE")) { - chatListener = new ChatListener(plugin); - - // Map Bukkit EventPriority to Sponge Order - HashMap orders = new HashMap() {{ - put("LOWEST", Order.FIRST); - put("LOW", Order.EARLY); - put("NORMAL", Order.DEFAULT); - put("HIGH", Order.LATE); - put("HIGHEST", Order.LATE); - put("MONITOR", Order.LAST); - }}; - - Order priority = orders.getOrDefault(chatPriority, Order.DEFAULT); - - Sponge.getEventManager().registerListener(this, MessageChannelEvent.Chat.class, priority, chatListener); - } - } - - private void registerEvent(Object listener) { - Sponge.getEventManager().registerListeners(this, listener); - } - - public void setupCommands() { - for (CommonCommand cmd : plugin.getCommands()) { - new SpongeCommand(this, cmd); - } - - if (plugin.getGlobalConn() != null) { - for (CommonCommand cmd : plugin.getGlobalCommands()) { - new SpongeCommand(this, cmd); - } - } - } - - public void setupRunnables() { - Runner syncRunner; - - if (plugin.getGlobalConn() == null) { - syncRunner = new Runner(new BanSync(plugin), new MuteSync(plugin), new IpSync(plugin), new IpRangeSync(plugin), new ExpiresSync(plugin), - new WarningSync(plugin), new RollbackSync(plugin), new NameSync(plugin)); - } else { - syncRunner = new Runner(new BanSync(plugin), new MuteSync(plugin), new IpSync(plugin), new IpRangeSync(plugin), new ExpiresSync(plugin), - new WarningSync(plugin), new RollbackSync(plugin), new NameSync(plugin), - new GlobalBanSync(plugin), new GlobalMuteSync(plugin), new GlobalIpSync(plugin), new GlobalNoteSync(plugin)); - } - - plugin.setSyncRunner(syncRunner); - - // Runner loop: run every 1 second on all platforms - Duration runnerPeriod = Duration.ofSeconds(1); - plugin.getScheduler().runAsyncRepeating(syncRunner, runnerPeriod, runnerPeriod); - - /* - * This task should be ran last with a small offset as it gets modified - * above. Use +50ms (1 tick) offset for consistency across platforms. - */ - int saveLastCheckedSeconds = plugin.getSchedulesConfig().getSchedule("saveLastChecked"); - if (saveLastCheckedSeconds > 0) { - Duration period = Duration.ofSeconds(saveLastCheckedSeconds); - Duration initialDelay = period.plusMillis(50); - plugin.getScheduler().runAsyncRepeating(new SaveLastChecked(plugin), initialDelay, period); - } - - // Purge - plugin.getScheduler().runAsync(new Purge(plugin)); - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/PluginLogger.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/PluginLogger.java deleted file mode 100644 index a84cc3aef..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/PluginLogger.java +++ /dev/null @@ -1,35 +0,0 @@ -package me.confuser.banmanager.sponge; - -import me.confuser.banmanager.common.CommonLogger; -import org.slf4j.Logger; - -public class PluginLogger implements CommonLogger { - - private final Logger logger; - - public PluginLogger(Logger logger) { - this.logger = logger; - } - - public void info(String msg) { - logger.info(msg); - } - - public void warning(String msg) { - logger.warn(msg); - } - - public void severe(String msg) { - logger.error(msg); - } - - @Override - public void severe(String msg, Throwable t) { - logger.error(msg, t); - } - - @Override - public void warning(String msg, Throwable t) { - logger.warn(msg, t); - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongeCommand.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongeCommand.java deleted file mode 100644 index 91fd8c14a..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongeCommand.java +++ /dev/null @@ -1,110 +0,0 @@ -package me.confuser.banmanager.sponge; - -import me.confuser.banmanager.common.BanManagerPlugin; -import me.confuser.banmanager.common.commands.CommonCommand; -import me.confuser.banmanager.common.commands.CommonSender; -import org.spongepowered.api.Sponge; -import org.spongepowered.api.command.CommandCallable; -import org.spongepowered.api.command.CommandResult; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.command.args.ArgumentParseException; -import org.spongepowered.api.command.args.parsing.InputTokenizer; -import org.spongepowered.api.command.args.parsing.SingleArg; -import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.world.Location; -import org.spongepowered.api.world.World; - -import java.lang.reflect.InvocationTargetException; -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -public class SpongeCommand implements CommandCallable { - - private BMSpongePlugin plugin; - private CommonCommand command; - private static final InputTokenizer tokeniser = InputTokenizer.spaceSplitString(); - - public SpongeCommand(BMSpongePlugin plugin, CommonCommand command) { - this.plugin = plugin; - this.command = command; - - register(); - } - - public void register() { - // Register with primary command name and all aliases - java.util.List allNames = new java.util.ArrayList<>(); - allNames.add(command.getCommandName()); - allNames.addAll(command.getAliases()); - Sponge.getCommandManager().register(plugin, this, allNames); - } - - @Override - public CommandResult process(CommandSource source, String arguments) { - CommonSender sender = getSender(source); - boolean result = execute(sender, arguments); - - if (!result) { - sender.sendMessage(command.getUsage()); - return CommandResult.empty(); - } - - return CommandResult.success(); - } - - private boolean execute(CommonSender sender, String arguments) { - try { - if (sender.hasPermission(command.getPermission())) { - return this.command.onCommand(sender, this.command.getParser(parseArgs(arguments))); - } else { - sender.sendMessage("&cYou do not have permission to use this command"); - return true; - } - } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException | ArgumentParseException e) { - plugin.getLogger().warning("Failed to execute command", e); - } - - return false; - } - - private String[] parseArgs(String arguments) throws ArgumentParseException { - return tokeniser.tokenize(arguments, false).stream().map(SingleArg::getValue).toArray(String[]::new); - } - - @Override - public List getSuggestions(CommandSource source, String arguments, Location targetPosition) { - if (!command.isEnableTabCompletion()) return Collections.emptyList(); - - return command.handlePlayerNameTabComplete(getSender(source), arguments.split(" ")); - } - - private CommonSender getSender(CommandSource source) { - if (source instanceof Player) { - return new SpongePlayer((Player) source, BanManagerPlugin.getInstance().getConfig().isOnlineMode()); - } else { - return new SpongeSender(BanManagerPlugin.getInstance(), source); - } - } - - @Override - public boolean testPermission(CommandSource source) { - return source.hasPermission(command.getPermission()); - } - - @Override - public Optional getShortDescription(CommandSource source) { - return Optional.empty(); - } - - @Override - public Optional getHelp(CommandSource source) { - return Optional.empty(); - } - - @Override - public Text getUsage(CommandSource source) { - return Text.of(command.getUsage()); - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongeMetrics.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongeMetrics.java deleted file mode 100755 index 0be630656..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongeMetrics.java +++ /dev/null @@ -1,60 +0,0 @@ -package me.confuser.banmanager.sponge; - -import me.confuser.banmanager.common.CommonMetrics; -import org.bstats.charts.DrilldownPie; -import org.bstats.charts.SimplePie; -import org.bstats.sponge.Metrics; - -import java.util.HashMap; -import java.util.Map; - -public class SpongeMetrics implements CommonMetrics { - private final Metrics metrics; - - public SpongeMetrics(Metrics metrics) { - this.metrics = metrics; - } - - @Override - public void submitOnlineMode(boolean online) { - metrics.addCustomChart((new SimplePie("banmanagerMode", () -> online ? "online" : "offline"))); - } - - @Override - public void submitStorageType(String storageType) { - metrics.addCustomChart((new SimplePie("storageType", () -> storageType))); - } - - @Override - public void submitStorageVersion(String version) { - metrics.addCustomChart((new DrilldownPie("storageVersion", () -> { - Map> map = new HashMap<>(); - - Map entry = new HashMap<>(); - entry.put(version, 1); - - if (version.contains("Maria")) { - map.put("MariaDB", entry); - } else { - map.put("MySQL", entry); - } - - return map; - }))); - } - - @Override - public void submitGlobalMode(boolean enabled) { - metrics.addCustomChart((new SimplePie("globalMode", () -> enabled ? "enabled" : "disabled"))); - } - - @Override - public void submitGeoMode(boolean enabled) { - metrics.addCustomChart((new SimplePie("geoMode", () -> enabled ? "enabled" : "disabled"))); - } - - @Override - public void submitDiscordMode(boolean enabled) { - metrics.addCustomChart((new SimplePie("discordMode", () -> enabled ? "enabled" : "disabled"))); - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongePlayer.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongePlayer.java deleted file mode 100644 index 47ac7a78d..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongePlayer.java +++ /dev/null @@ -1,156 +0,0 @@ -package me.confuser.banmanager.sponge; - -import me.confuser.banmanager.common.BanManagerPlugin; -import me.confuser.banmanager.common.CommonPlayer; -import me.confuser.banmanager.common.CommonWorld; -import me.confuser.banmanager.common.data.PlayerData; -import me.confuser.banmanager.common.kyori.text.TextComponent; -import me.confuser.banmanager.common.kyori.text.serializer.gson.GsonComponentSerializer; -import me.confuser.banmanager.common.util.Message; -import me.confuser.banmanager.common.util.UUIDUtils; -import org.spongepowered.api.Sponge; -import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.entity.living.player.User; -import org.spongepowered.api.text.serializer.TextSerializers; -import org.spongepowered.api.world.Location; -import org.spongepowered.api.world.World; - -import java.net.InetAddress; -import java.sql.SQLException; -import java.util.Optional; -import java.util.UUID; - -public class SpongePlayer implements CommonPlayer { - private User user; - private final UUID uuid; - private final boolean onlineMode; - private InetAddress address; - - public SpongePlayer(UUID uuid, String name, boolean onlineMode) { - this.uuid = uuid; - this.onlineMode = onlineMode; - } - - public SpongePlayer(Player player, boolean onlineMode) { - this(player.getUniqueId(), player.getName(), onlineMode); - } - - public SpongePlayer(User user, boolean onlineMode, InetAddress address) { - this(user.getUniqueId(), user.getName(), onlineMode); - - this.user = user; - this.address = address; - } - - @Override - public void kick(String message) { - getPlayer().kick(SpongeServer.formatMessage(message)); - } - - @Override - public void sendMessage(String message) { - if(message.isEmpty()) return; - - if(Message.isJSONMessage(message)) { - sendJSONMessage(message); - } else { - getPlayer().sendMessage(SpongeServer.formatMessage(message)); - } - } - - @Override - public void sendMessage(Message message) { - sendMessage(message.toString()); - } - - @Override - public void sendJSONMessage(TextComponent jsonString) { - getPlayer().sendMessage(TextSerializers.JSON.deserialize(GsonComponentSerializer.gson().serialize(jsonString))); - } - - @Override - public void sendJSONMessage(String jsonString) { - getPlayer().sendMessage(TextSerializers.JSON.deserialize(jsonString)); - } - - @Override - public boolean isConsole() { - return false; - } - - @Override - public PlayerData getData() { - try { - return BanManagerPlugin.getInstance().getPlayerStorage().queryForId(UUIDUtils.toBytes(getUniqueId())); - } catch (SQLException e) { - BanManagerPlugin.getInstance().getLogger().warning("Failed to load player data", e); - sendMessage(Message.get("sender.error.exception").toString()); - return null; - } - } - - @Override - public boolean isOnlineMode() { - return onlineMode; - } - - public boolean isOnline() { - return getPlayer() != null; - } - - @Override - public boolean hasPermission(String permission) { - if (user != null) return user.hasPermission(permission); - - return getPlayer().hasPermission(permission); - } - - @Override - public String getDisplayName() { - return getPlayer().getDisplayNameData().displayName().get().toPlain(); - } - - @Override - public String getName() { - return getPlayer().getName(); - } - - @Override - public InetAddress getAddress() { - if (address != null) return address; - return getPlayer().getConnection().getAddress().getAddress(); - } - - public UUID getUniqueId() { - return uuid; - } - - public boolean teleport(CommonWorld world, double x, double y, double z, float pitch, float yaw) { - Location location = Sponge.getServer().getWorld(world.getName()).get().getLocation(x, y, z); - - return getPlayer().setLocation(location); - } - - @Override - public boolean canSee(CommonPlayer player) { - return getPlayer().canSee(Sponge.getServer().getPlayer(player.getUniqueId()).get()); - } - - private Player getPlayer() { - if (isOnlineMode()) { - Optional player = Sponge.getServer().getPlayer(uuid); - - if (player.isPresent()) { - return player.get(); - } else { - return null; - } - } - - for (Player onlinePlayer : Sponge.getServer().getOnlinePlayers()) { - if (UUIDUtils.createOfflineUUID(onlinePlayer.getName()).equals(uuid)) return onlinePlayer; - } - - return null; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongeScheduler.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongeScheduler.java deleted file mode 100644 index 09081394b..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongeScheduler.java +++ /dev/null @@ -1,61 +0,0 @@ -package me.confuser.banmanager.sponge; - -import me.confuser.banmanager.common.CommonScheduler; -import me.confuser.banmanager.common.util.SchedulerTime; -import org.spongepowered.api.Sponge; -import org.spongepowered.api.scheduler.Task; - -import java.time.Duration; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -public class SpongeScheduler implements CommonScheduler { - private Object plugin; - private final List repeatingTasks = new CopyOnWriteArrayList<>(); - - public SpongeScheduler(Object plugin) { - this.plugin = plugin; - } - - @Override - public void runAsync(Runnable task) { - Task.Builder builder = Sponge.getGame().getScheduler().createTaskBuilder(); - builder.async().execute(task).submit(plugin); - } - - @Override - public void runAsyncLater(Runnable task, Duration delay) { - long ticks = SchedulerTime.durationToTicksCeil(delay); - Task.Builder builder = Sponge.getGame().getScheduler().createTaskBuilder(); - builder.async().execute(task).delayTicks(ticks).submit(plugin); - } - - @Override - public void runSync(Runnable task) { - Task.Builder builder = Sponge.getGame().getScheduler().createTaskBuilder(); - builder.execute(task).submit(plugin); - } - - @Override - public void runSyncLater(Runnable task, Duration delay) { - long ticks = SchedulerTime.durationToTicksCeil(delay); - Task.Builder builder = Sponge.getGame().getScheduler().createTaskBuilder(); - builder.execute(task).delayTicks(ticks).submit(plugin); - } - - @Override - public void runAsyncRepeating(Runnable task, Duration initialDelay, Duration period) { - long initialTicks = SchedulerTime.durationToTicksCeil(initialDelay); - long periodTicks = SchedulerTime.durationToTicksCeil(period); - Task.Builder builder = Sponge.getGame().getScheduler().createTaskBuilder(); - repeatingTasks.add(builder.async().execute(task).delayTicks(initialTicks).intervalTicks(periodTicks).submit(plugin)); - } - - @Override - public void cancelAll() { - for (Task task : repeatingTasks) { - task.cancel(); - } - repeatingTasks.clear(); - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongeSender.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongeSender.java deleted file mode 100644 index 577889f8a..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongeSender.java +++ /dev/null @@ -1,60 +0,0 @@ -package me.confuser.banmanager.sponge; - -import me.confuser.banmanager.common.BanManagerPlugin; -import me.confuser.banmanager.common.commands.CommonSender; -import me.confuser.banmanager.common.data.PlayerData; -import me.confuser.banmanager.common.util.Message; -import me.confuser.banmanager.common.util.UUIDUtils; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.entity.living.player.Player; - -import java.sql.SQLException; - -public class SpongeSender implements CommonSender { - - private BanManagerPlugin plugin; - private CommandSource sender; - - public SpongeSender(BanManagerPlugin plugin, CommandSource sender) { - this.plugin = plugin; - this.sender = sender; - } - - @Override - public String getName() { - return sender.getName(); - } - - @Override - public boolean hasPermission(String permission) { - return sender.hasPermission(permission); - } - - @Override - public void sendMessage(String message) { - sender.sendMessage(SpongeServer.formatMessage(message)); - } - - @Override - public void sendMessage(Message message) { - sendMessage(message.toString()); - } - - @Override - public boolean isConsole() { - return !(sender instanceof Player); - } - - @Override - public PlayerData getData() { - if (isConsole()) return plugin.getPlayerStorage().getConsole(); - - try { - return plugin.getPlayerStorage().queryForId(UUIDUtils.toBytes(((Player) sender).getUniqueId())); - } catch (SQLException e) { - plugin.getLogger().warning("Failed to load player data", e); - sender.sendMessage(SpongeServer.formatMessage(Message.get("sender.error.exception").toString())); - return null; - } - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongeServer.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongeServer.java deleted file mode 100644 index a3ceafd3d..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/SpongeServer.java +++ /dev/null @@ -1,249 +0,0 @@ -package me.confuser.banmanager.sponge; - -import me.confuser.banmanager.common.*; -import me.confuser.banmanager.common.api.events.CommonEvent; -import me.confuser.banmanager.common.commands.CommonSender; -import me.confuser.banmanager.common.data.*; -import me.confuser.banmanager.common.kyori.text.serializer.gson.GsonComponentSerializer; -import me.confuser.banmanager.common.kyori.text.TextComponent; -import me.confuser.banmanager.common.util.ColorUtils; -import me.confuser.banmanager.common.util.Message; -import me.confuser.banmanager.sponge.api.events.*; -import org.spongepowered.api.Sponge; -import org.spongepowered.api.command.CommandMapping; -import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.text.serializer.TextSerializers; -import org.spongepowered.api.world.World; - -import java.util.*; -import java.util.stream.Collectors; - -public class SpongeServer implements CommonServer { - private BanManagerPlugin plugin; - - public void enable(BanManagerPlugin plugin) { - this.plugin = plugin; - } - - @Override - public CommonPlayer getPlayer(UUID uniqueId) { - Optional player = Sponge.getGame().getServer().getPlayer(uniqueId); - - return player.map(value -> new SpongePlayer(value, plugin.getConfig().isOnlineMode())).orElse(null); - - } - - @Override - public CommonPlayer getPlayer(String name) { - Optional player = Sponge.getGame().getServer().getPlayer(name); - - return player.map(value -> new SpongePlayer(value, plugin.getConfig().isOnlineMode())).orElse(null); - - } - - @Override - public CommonPlayer getPlayerExact(String name) { - return getPlayer(name); - } - - @Override - public CommonPlayer[] getOnlinePlayers() { - return Sponge.getServer().getOnlinePlayers().stream() - .map(player -> new SpongePlayer(player, plugin.getConfig().isOnlineMode())) - .collect(Collectors.toList()).toArray(new CommonPlayer[0]); - } - - @Override - public void broadcast(String message, String permission) { - if(message.isEmpty()) return; - - // @TODO can't figure out how to get message channels to work ¯\_(ツ)_/¯ - // MessageChannel.permission(permission).send(Sponge.getServer().getConsole(), Text.of(message)); - Arrays.stream(getOnlinePlayers()).forEach(player -> { - if (player.hasPermission(permission)) player.sendMessage(message); - }); - - Sponge.getServer().getConsole().sendMessage(Text.of(message)); - } - - @Override - public void broadcastJSON(TextComponent message, String permission) { - Arrays.stream(getOnlinePlayers()).forEach(player -> { - if (player.hasPermission(permission)) player.sendJSONMessage(message); - }); - } - - public void broadcast(String message, String permission, CommonSender sender) { - broadcast(message, permission); - - if (!sender.hasPermission(permission)) sender.sendMessage(message); - } - - public static Text formatMessage(String message) { - String json = ColorUtils.toDownsampledJson(message); - return TextSerializers.JSON.deserialize(json); - } - - public static Text formatMessage(TextComponent message) { - String json = GsonComponentSerializer.colorDownsamplingGson().serialize(message); - return TextSerializers.JSON.deserialize(json); - } - - public CommonSender getConsoleSender() { - return new SpongeSender(plugin, Sponge.getServer().getConsole()); - } - - public boolean dispatchCommand(CommonSender sender, String command) { - if (sender.isConsole()) { - Sponge.getCommandManager().process(Sponge.getServer().getConsole(), command); - } else { - Sponge.getCommandManager().process(Sponge.getServer().getPlayer(sender.getName()).get(), command); - } - - return true; - } - - public CommonWorld getWorld(String name) { - Optional world = Sponge.getServer().getWorld(name); - - if (!world.isPresent()) return null; - - return new CommonWorld(name); - } - - @Override - public CommonEvent callEvent(String name, Object... args) { - // @TODO replace with a cleaner implementation - CustomEvent event = null; - CommonEvent commonEvent = new CommonEvent(false, true); - - switch (name) { - case "PlayerBanEvent": - event = new PlayerBanEvent((PlayerBanData) args[0], (boolean) args[1]); - break; - case "PlayerBannedEvent": - PlayerBannedEvent bannedEvent = new PlayerBannedEvent((PlayerBanData) args[0], (boolean) args[1]); - if (args.length > 2 && args[2] instanceof Message) { - bannedEvent.setKickMessage((Message) args[2]); - } - event = bannedEvent; - break; - case "PlayerUnbanEvent": - event = new PlayerUnbanEvent((PlayerBanData) args[0], (PlayerData) args[1], (String) args[2], (boolean) args[3]); - break; - - case "IpBanEvent": - event = new IpBanEvent((IpBanData) args[0], (boolean) args[1]); - break; - case "IpBannedEvent": - event = new IpBannedEvent((IpBanData) args[0], (boolean) args[1]); - break; - case "IpUnbanEvent": - event = new IpUnbanEvent((IpBanData) args[0], (PlayerData) args[1], (String) args[2], (boolean) args[3]); - break; - - case "IpMuteEvent": - event = new IpMuteEvent((IpMuteData) args[0], (boolean) args[1]); - break; - case "IpMutedEvent": - event = new IpMutedEvent((IpMuteData) args[0], (boolean) args[1]); - break; - case "IpUnmutedEvent": - event = new IpUnmutedEvent((IpMuteData) args[0], (PlayerData) args[1], (String) args[2], (boolean) args[3]); - break; - - case "PlayerKickedEvent": - event = new PlayerKickedEvent((PlayerKickData) args[0], (boolean) args[1]); - break; - - case "PlayerNoteCreatedEvent": - event = new PlayerNoteCreatedEvent((PlayerNoteData) args[0], args.length > 1 && (boolean) args[1]); - break; - - case "PlayerReportEvent": - event = new PlayerReportEvent((PlayerReportData) args[0], (boolean) args[1]); - break; - case "PlayerReportedEvent": - event = new PlayerReportedEvent((PlayerReportData) args[0], (boolean) args[1]); - break; - case "PlayerReportDeletedEvent": - event = new PlayerReportDeletedEvent((PlayerReportData) args[0]); - break; - - case "NameBanEvent": - event = new NameBanEvent((NameBanData) args[0], (boolean) args[1]); - break; - case "NameBannedEvent": - event = new NameBannedEvent((NameBanData) args[0], (boolean) args[1]); - break; - case "NameUnbanEvent": - event = new NameUnbanEvent((NameBanData) args[0], (PlayerData) args[1], (String) args[2], (boolean) args[3]); - break; - - case "PlayerWarnEvent": - event = new PlayerWarnEvent((PlayerWarnData) args[0], (boolean) args[1]); - break; - case "PlayerWarnedEvent": - event = new PlayerWarnedEvent((PlayerWarnData) args[0], (boolean) args[1]); - break; - - case "IpRangeBanEvent": - event = new IpRangeBanEvent((IpRangeBanData) args[0], (boolean) args[1]); - break; - case "IpRangeBannedEvent": - event = new IpRangeBannedEvent((IpRangeBanData) args[0], (boolean) args[1]); - break; - case "IpRangeUnbanEvent": - event = new IpRangeUnbanEvent((IpRangeBanData) args[0], (PlayerData) args[1], (String) args[2], (boolean) args[3]); - break; - - case "PlayerMuteEvent": - event = new PlayerMuteEvent((PlayerMuteData) args[0], (boolean) args[1]); - break; - case "PlayerMutedEvent": - event = new PlayerMutedEvent((PlayerMuteData) args[0], (boolean) args[1]); - break; - case "PlayerUnmuteEvent": - event = new PlayerUnmuteEvent((PlayerMuteData) args[0], (PlayerData) args[1], (String) args[2], (boolean) args[3]); - break; - - case "PluginReloadedEvent": - event = new PluginReloadedEvent((PlayerData) args[0]); - break; - - case "PlayerDeniedEvent": - event = new PlayerDeniedEvent((PlayerData) args[0], (Message) args[1]); - break; - } - - if (event == null) { - plugin.getLogger().warning("Unable to call missing event " + name); - - return commonEvent; - } - - Sponge.getEventManager().post(event); - - if (event instanceof SilentCancellableEvent) { - commonEvent = new CommonEvent(((SilentCancellableEvent) event).isCancelled(), ((SilentCancellableEvent) event).isSilent()); - } else if (event instanceof SilentEvent) { - commonEvent = new CommonEvent(false, ((SilentEvent) event).isSilent()); - } else if (event instanceof CustomCancellableEvent) { - commonEvent = new CommonEvent(((CustomCancellableEvent) event).isCancelled(), true); - } - - return commonEvent; - } - - @Override - public CommonExternalCommand getPluginCommand(String commandName) { - Optional commandMapping = Sponge.getCommandManager().get(commandName); - - if (!commandMapping.isPresent()) return null; - - CommandMapping cmd = commandMapping.get(); - - return new CommonExternalCommand(null, cmd.getPrimaryAlias(), new ArrayList<>(cmd.getAllAliases())); - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/CustomCancellableEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/CustomCancellableEvent.java deleted file mode 100644 index 1f2e4d763..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/CustomCancellableEvent.java +++ /dev/null @@ -1,16 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import lombok.Setter; -import org.spongepowered.api.event.Cancellable; - -public abstract class CustomCancellableEvent extends CustomEvent implements Cancellable { - - @Getter - @Setter - private boolean cancelled = false; - - public CustomCancellableEvent() { - super(); - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/CustomEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/CustomEvent.java deleted file mode 100644 index f3e3314c1..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/CustomEvent.java +++ /dev/null @@ -1,21 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import org.spongepowered.api.Sponge; -import org.spongepowered.api.event.cause.Cause; -import org.spongepowered.api.event.cause.EventContext; -import org.spongepowered.api.event.cause.EventContextKeys; -import org.spongepowered.api.event.impl.AbstractEvent; -import org.spongepowered.api.plugin.PluginContainer; - -public abstract class CustomEvent extends AbstractEvent { - @Getter - private final Cause cause; - - public CustomEvent() { - PluginContainer plugin = Sponge.getPluginManager().getPlugin("banmanager").get(); - EventContext eventContext = EventContext.builder().add(EventContextKeys.PLUGIN, plugin).build(); - - this.cause = Cause.of(eventContext, plugin); - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpBanEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpBanEvent.java deleted file mode 100644 index e0b758d90..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpBanEvent.java +++ /dev/null @@ -1,16 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.IpBanData; - -public class IpBanEvent extends SilentCancellableEvent { - - @Getter - private IpBanData ban; - - public IpBanEvent(IpBanData ban, boolean silent) { - super(silent); - - this.ban = ban; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpBannedEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpBannedEvent.java deleted file mode 100644 index c63dca9fd..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpBannedEvent.java +++ /dev/null @@ -1,15 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.IpBanData; - -public class IpBannedEvent extends SilentEvent { - - @Getter - private IpBanData ban; - - public IpBannedEvent(IpBanData ban, boolean silent) { - super(silent); - this.ban = ban; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpMuteEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpMuteEvent.java deleted file mode 100644 index 5f99f8f89..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpMuteEvent.java +++ /dev/null @@ -1,15 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.IpMuteData; - -public class IpMuteEvent extends SilentCancellableEvent { - - @Getter - private IpMuteData mute; - - public IpMuteEvent(IpMuteData mute, boolean silent) { - super(silent); - this.mute = mute; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpMutedEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpMutedEvent.java deleted file mode 100644 index 9b772d29b..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpMutedEvent.java +++ /dev/null @@ -1,15 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.IpMuteData; - -public class IpMutedEvent extends SilentEvent { - - @Getter - private IpMuteData mute; - - public IpMutedEvent(IpMuteData mute, boolean silent) { - super(silent); - this.mute = mute; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpRangeBanEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpRangeBanEvent.java deleted file mode 100644 index 8ebb1d0c6..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpRangeBanEvent.java +++ /dev/null @@ -1,15 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.IpRangeBanData; - -public class IpRangeBanEvent extends SilentCancellableEvent { - - @Getter - private IpRangeBanData ban; - - public IpRangeBanEvent(IpRangeBanData ban, boolean silent) { - super(silent); - this.ban = ban; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpRangeBannedEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpRangeBannedEvent.java deleted file mode 100644 index 073562232..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpRangeBannedEvent.java +++ /dev/null @@ -1,16 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.IpRangeBanData; - - -public class IpRangeBannedEvent extends SilentEvent { - - @Getter - private IpRangeBanData ban; - - public IpRangeBannedEvent(IpRangeBanData ban, boolean silent) { - super(silent); - this.ban = ban; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpRangeUnbanEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpRangeUnbanEvent.java deleted file mode 100644 index d5854cec1..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpRangeUnbanEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.IpRangeBanData; -import me.confuser.banmanager.common.data.PlayerData; - - -public class IpRangeUnbanEvent extends SilentCancellableEvent { - - @Getter - private IpRangeBanData ban; - @Getter - private PlayerData actor; - @Getter - private String reason; - public IpRangeUnbanEvent(IpRangeBanData ban, PlayerData actor, String reason) { - this(ban, actor, reason, false); - } - - public IpRangeUnbanEvent(IpRangeBanData ban, PlayerData actor, String reason, boolean silent) { - super(silent); - - this.ban = ban; - this.actor = actor; - this.reason = reason; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpUnbanEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpUnbanEvent.java deleted file mode 100644 index 327a17c2f..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpUnbanEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.IpBanData; -import me.confuser.banmanager.common.data.PlayerData; - - -public class IpUnbanEvent extends SilentCancellableEvent { - - @Getter - private IpBanData ban; - @Getter - private PlayerData actor; - @Getter - private String reason; - public IpUnbanEvent(IpBanData ban, PlayerData actor, String reason) { - this(ban, actor, reason, false); - } - - public IpUnbanEvent(IpBanData ban, PlayerData actor, String reason, boolean silent) { - super(silent); - - this.ban = ban; - this.actor = actor; - this.reason = reason; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpUnmutedEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpUnmutedEvent.java deleted file mode 100644 index 2c8046a72..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/IpUnmutedEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.IpMuteData; -import me.confuser.banmanager.common.data.PlayerData; - - -public class IpUnmutedEvent extends SilentCancellableEvent { - - @Getter - private IpMuteData mute; - @Getter - private PlayerData actor; - @Getter - private String reason; - public IpUnmutedEvent(IpMuteData mute, PlayerData actor, String reason) { - this(mute, actor, reason, false); - } - - public IpUnmutedEvent(IpMuteData mute, PlayerData actor, String reason, boolean silent) { - super(silent); - - this.mute = mute; - this.actor = actor; - this.reason = reason; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/NameBanEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/NameBanEvent.java deleted file mode 100644 index da3fcaffb..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/NameBanEvent.java +++ /dev/null @@ -1,17 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.NameBanData; - - -public class NameBanEvent extends SilentCancellableEvent { - - @Getter - private NameBanData ban; - - public NameBanEvent(NameBanData ban, boolean isSilent) { - super(isSilent); - this.ban = ban; - } - -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/NameBannedEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/NameBannedEvent.java deleted file mode 100644 index 334e1d4a6..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/NameBannedEvent.java +++ /dev/null @@ -1,16 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.NameBanData; - -public class NameBannedEvent extends SilentEvent { - - @Getter - private NameBanData ban; - - public NameBannedEvent(NameBanData ban, boolean isSilent) { - super(isSilent); - this.ban = ban; - } - -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/NameUnbanEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/NameUnbanEvent.java deleted file mode 100644 index 389ad6698..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/NameUnbanEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.NameBanData; -import me.confuser.banmanager.common.data.PlayerData; - - -public class NameUnbanEvent extends SilentCancellableEvent { - - @Getter - private NameBanData ban; - @Getter - private PlayerData actor; - @Getter - private String reason; - public NameUnbanEvent(NameBanData ban, PlayerData actor, String reason) { - this(ban, actor, reason, false); - } - - public NameUnbanEvent(NameBanData ban, PlayerData actor, String reason, boolean silent) { - super(silent); - - this.ban = ban; - this.actor = actor; - this.reason = reason; - } - -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerBanEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerBanEvent.java deleted file mode 100644 index bf8ad864e..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerBanEvent.java +++ /dev/null @@ -1,17 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.PlayerBanData; - - -public class PlayerBanEvent extends SilentCancellableEvent { - - @Getter - private PlayerBanData ban; - - public PlayerBanEvent(PlayerBanData ban, boolean isSilent) { - super(isSilent); - this.ban = ban; - } - -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerBannedEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerBannedEvent.java deleted file mode 100644 index 5664dd97d..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerBannedEvent.java +++ /dev/null @@ -1,23 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import lombok.Setter; -import me.confuser.banmanager.common.data.PlayerBanData; -import me.confuser.banmanager.common.util.Message; - - -public class PlayerBannedEvent extends SilentEvent { - - @Getter - private PlayerBanData ban; - - @Getter - @Setter - private Message kickMessage; - - public PlayerBannedEvent(PlayerBanData ban, boolean isSilent) { - super(isSilent); - this.ban = ban; - } - -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerDeniedEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerDeniedEvent.java deleted file mode 100644 index 48cf5c59f..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerDeniedEvent.java +++ /dev/null @@ -1,24 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import lombok.Setter; -import me.confuser.banmanager.common.util.Message; -import me.confuser.banmanager.common.data.PlayerData; - - -public class PlayerDeniedEvent extends CustomCancellableEvent { - - @Getter - @Setter - private Message message; - - @Getter - private PlayerData player; - - public PlayerDeniedEvent(PlayerData player, Message message) { - super(); - - this.player = player; - this.message = message; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerKickedEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerKickedEvent.java deleted file mode 100644 index 0cceb9407..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerKickedEvent.java +++ /dev/null @@ -1,15 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.PlayerKickData; - -public class PlayerKickedEvent extends SilentEvent { - - @Getter - private PlayerKickData kick; - - public PlayerKickedEvent(PlayerKickData kick, boolean isSilent) { - super(isSilent); - this.kick = kick; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerMuteEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerMuteEvent.java deleted file mode 100644 index 3b99b37d6..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerMuteEvent.java +++ /dev/null @@ -1,16 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.PlayerMuteData; - - -public class PlayerMuteEvent extends SilentCancellableEvent { - - @Getter - private PlayerMuteData mute; - - public PlayerMuteEvent(PlayerMuteData mute, boolean silent) { - super(silent); - this.mute = mute; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerMutedEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerMutedEvent.java deleted file mode 100644 index ecbf8cc41..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerMutedEvent.java +++ /dev/null @@ -1,16 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.PlayerMuteData; - - -public class PlayerMutedEvent extends SilentEvent { - - @Getter - private PlayerMuteData mute; - - public PlayerMutedEvent(PlayerMuteData mute, boolean silent) { - super(silent); - this.mute = mute; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerNoteCreatedEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerNoteCreatedEvent.java deleted file mode 100644 index fcea2ad34..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerNoteCreatedEvent.java +++ /dev/null @@ -1,20 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.PlayerNoteData; - - -public class PlayerNoteCreatedEvent extends SilentCancellableEvent { - - @Getter - private PlayerNoteData note; - - public PlayerNoteCreatedEvent(PlayerNoteData note) { - this(note, false); - } - - public PlayerNoteCreatedEvent(PlayerNoteData note, boolean silent) { - super(silent); - this.note = note; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerReportDeletedEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerReportDeletedEvent.java deleted file mode 100644 index fcf11424b..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerReportDeletedEvent.java +++ /dev/null @@ -1,15 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.PlayerReportData; - -public class PlayerReportDeletedEvent extends CustomEvent { - - @Getter - private PlayerReportData report; - - public PlayerReportDeletedEvent(PlayerReportData report) { - super(); - this.report = report; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerReportEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerReportEvent.java deleted file mode 100644 index 49ecfa57e..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerReportEvent.java +++ /dev/null @@ -1,17 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.PlayerReportData; - - -public class PlayerReportEvent extends SilentCancellableEvent { - - @Getter - private PlayerReportData report; - - public PlayerReportEvent(PlayerReportData report, boolean isSilent) { - super(isSilent); - this.report = report; - } - -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerReportedEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerReportedEvent.java deleted file mode 100644 index f0a48e2ae..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerReportedEvent.java +++ /dev/null @@ -1,17 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.PlayerReportData; - - -public class PlayerReportedEvent extends SilentEvent { - - @Getter - private PlayerReportData report; - - public PlayerReportedEvent(PlayerReportData report, boolean isSilent) { - super(isSilent); - this.report = report; - } - -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerUnbanEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerUnbanEvent.java deleted file mode 100644 index 38e073e2b..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerUnbanEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.PlayerBanData; -import me.confuser.banmanager.common.data.PlayerData; - - -public class PlayerUnbanEvent extends SilentCancellableEvent { - - @Getter - private PlayerBanData ban; - @Getter - private PlayerData actor; - @Getter - private String reason; - public PlayerUnbanEvent(PlayerBanData ban, PlayerData actor, String reason) { - this(ban, actor, reason, false); - } - - public PlayerUnbanEvent(PlayerBanData ban, PlayerData actor, String reason, boolean silent) { - super(silent); - - this.ban = ban; - this.actor = actor; - this.reason = reason; - } - -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerUnmuteEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerUnmuteEvent.java deleted file mode 100644 index 5aa25f6f2..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerUnmuteEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.PlayerData; -import me.confuser.banmanager.common.data.PlayerMuteData; - - -public class PlayerUnmuteEvent extends SilentCancellableEvent { - - @Getter - private PlayerMuteData mute; - @Getter - private PlayerData actor; - @Getter - private String reason; - public PlayerUnmuteEvent(PlayerMuteData mute, PlayerData actor, String reason) { - this(mute, actor, reason, false); - } - - public PlayerUnmuteEvent(PlayerMuteData mute, PlayerData actor, String reason, boolean silent) { - super(silent); - - this.mute = mute; - this.actor = actor; - this.reason = reason; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerWarnEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerWarnEvent.java deleted file mode 100644 index 8f219ed4e..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerWarnEvent.java +++ /dev/null @@ -1,16 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.PlayerWarnData; - - -public class PlayerWarnEvent extends SilentEvent { - - @Getter - private PlayerWarnData warning; - - public PlayerWarnEvent(PlayerWarnData warning, boolean silent) { - super(silent); - this.warning = warning; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerWarnedEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerWarnedEvent.java deleted file mode 100644 index d241d2d4a..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PlayerWarnedEvent.java +++ /dev/null @@ -1,16 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.PlayerWarnData; - - -public class PlayerWarnedEvent extends SilentEvent { - - @Getter - private PlayerWarnData warning; - - public PlayerWarnedEvent(PlayerWarnData warning, boolean silent) { - super(silent); - this.warning = warning; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PluginReloadedEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PluginReloadedEvent.java deleted file mode 100644 index 2206c9289..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/PluginReloadedEvent.java +++ /dev/null @@ -1,17 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import me.confuser.banmanager.common.data.PlayerData; - - -public class PluginReloadedEvent extends CustomCancellableEvent { - - @Getter - private PlayerData actor; - - public PluginReloadedEvent(PlayerData actor) { - super(); - - this.actor = actor; - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/SilentCancellableEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/SilentCancellableEvent.java deleted file mode 100644 index 3c8fe0200..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/SilentCancellableEvent.java +++ /dev/null @@ -1,18 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import lombok.Setter; - -public abstract class SilentCancellableEvent extends CustomCancellableEvent { - - @Getter - @Setter - private boolean silent; - - public SilentCancellableEvent(boolean silent) { - super(); - - this.silent = silent; - } - -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/SilentEvent.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/SilentEvent.java deleted file mode 100644 index 9dbf85763..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/api/events/SilentEvent.java +++ /dev/null @@ -1,16 +0,0 @@ -package me.confuser.banmanager.sponge.api.events; - -import lombok.Getter; -import lombok.Setter; - -public abstract class SilentEvent extends CustomEvent { - @Getter - @Setter - private boolean silent; - - public SilentEvent(boolean silent) { - super(); - this.silent = silent; - } - -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/BanListener.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/BanListener.java deleted file mode 100644 index a7ce0e28a..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/BanListener.java +++ /dev/null @@ -1,52 +0,0 @@ -package me.confuser.banmanager.sponge.listeners; - - -import me.confuser.banmanager.common.BanManagerPlugin; -import me.confuser.banmanager.common.CommonPlayer; -import me.confuser.banmanager.common.data.*; -import me.confuser.banmanager.common.listeners.CommonBanListener; -import me.confuser.banmanager.common.util.DateUtils; -import me.confuser.banmanager.common.util.IPUtils; -import me.confuser.banmanager.common.util.Message; -import me.confuser.banmanager.sponge.api.events.IpBannedEvent; -import me.confuser.banmanager.sponge.api.events.IpRangeBannedEvent; -import me.confuser.banmanager.sponge.api.events.NameBannedEvent; -import me.confuser.banmanager.sponge.api.events.PlayerBannedEvent; -import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.Order; -import org.spongepowered.api.event.filter.IsCancelled; -import org.spongepowered.api.util.Tristate; - -import java.util.List; - -public class BanListener { - private final CommonBanListener listener; - - public BanListener(BanManagerPlugin plugin) { - this.listener = new CommonBanListener(plugin); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void notifyOnBan(PlayerBannedEvent event) { - listener.notifyOnBan(event.getBan(), event.isSilent()); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void notifyOnIpBan(IpBannedEvent event) { - listener.notifyOnBan(event.getBan(), event.isSilent()); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void notifyOnIpRangeBan(IpRangeBannedEvent event) { - listener.notifyOnBan(event.getBan(), event.isSilent()); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void notifyOnNameBan(NameBannedEvent event) { - listener.notifyOnBan(event.getBan(), event.isSilent()); - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/ChatListener.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/ChatListener.java deleted file mode 100644 index 78f4e299d..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/ChatListener.java +++ /dev/null @@ -1,62 +0,0 @@ -package me.confuser.banmanager.sponge.listeners; - - -import java.util.Optional; - -import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.event.EventListener; -import org.spongepowered.api.event.message.MessageChannelEvent; - -import lombok.RequiredArgsConstructor; -import me.confuser.banmanager.common.BanManagerPlugin; -import me.confuser.banmanager.common.CommonPlayer; -import me.confuser.banmanager.common.listeners.CommonChatHandler; -import me.confuser.banmanager.common.listeners.CommonChatListener; - -public class ChatListener implements EventListener { - - private final CommonChatListener listener; - private BanManagerPlugin plugin; - - public ChatListener(BanManagerPlugin plugin) { - this.plugin = plugin; - this.listener = new CommonChatListener(plugin); - } - - public void onPlayerChat(MessageChannelEvent.Chat event, Player player) { - CommonPlayer commonPlayer = plugin.getServer().getPlayer(player.getUniqueId()); - - if (listener.onPlayerChat(commonPlayer, new ChatHandler(event, player), event.getMessage().toPlain())) { - event.setCancelled(true); - } - } - - public void onIpChat(MessageChannelEvent.Chat event, Player player) { - CommonPlayer commonPlayer = plugin.getServer().getPlayer(player.getUniqueId()); - - if (listener.onIpChat(commonPlayer, player.getConnection().getAddress().getAddress(), new ChatHandler(event, player), event.getMessage().toPlain())) { - event.setCancelled(true); - } - } - - @Override - public void handle(MessageChannelEvent.Chat event) throws Exception { - Optional firstPlayer = event.getCause().first(Player.class); - - if (!firstPlayer.isPresent()) return; - - onPlayerChat(event, firstPlayer.get()); - onIpChat(event, firstPlayer.get()); - } - - @RequiredArgsConstructor - private class ChatHandler implements CommonChatHandler { - private final MessageChannelEvent.Chat event; - private final Player player; - - @Override - public void handleSoftMute() { - event.setChannel(player.getMessageChannel()); - } - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/CommandListener.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/CommandListener.java deleted file mode 100644 index 8204cd5df..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/CommandListener.java +++ /dev/null @@ -1,34 +0,0 @@ -package me.confuser.banmanager.sponge.listeners; - - -import me.confuser.banmanager.common.BanManagerPlugin; -import me.confuser.banmanager.common.CommonPlayer; -import me.confuser.banmanager.common.listeners.CommonCommandListener; -import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.Order; -import org.spongepowered.api.event.command.SendCommandEvent; -import org.spongepowered.api.event.filter.cause.First; - -public class CommandListener { - - private final CommonCommandListener listener; - private BanManagerPlugin plugin; - - public CommandListener(BanManagerPlugin plugin) { - this.plugin = plugin; - this.listener = new CommonCommandListener(plugin); - } - - @Listener(order = Order.FIRST, beforeModifications = true) - public void onCommand(SendCommandEvent event, @First Player player) { - CommonPlayer commonPlayer = plugin.getServer().getPlayer(player.getUniqueId()); - // Split the command - String[] args = event.getArguments().split(" ", 6); - String cmd = event.getCommand().toLowerCase(); - - if (listener.onCommand(commonPlayer, cmd, args)) { - event.setCancelled(true); - } - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/HookListener.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/HookListener.java deleted file mode 100644 index 8b2630411..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/HookListener.java +++ /dev/null @@ -1,100 +0,0 @@ -package me.confuser.banmanager.sponge.listeners; - -import me.confuser.banmanager.common.BanManagerPlugin; -import me.confuser.banmanager.common.listeners.CommonHooksListener; -import me.confuser.banmanager.sponge.api.events.*; -import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.Order; - -public class HookListener { - private final CommonHooksListener listener; - - public HookListener(BanManagerPlugin plugin) { - this.listener = new CommonHooksListener(plugin); - } - - @Listener(order = Order.POST) - public void onBan(final PlayerBanEvent event) { - listener.onBan(event.getBan(), true, event.isSilent()); - } - - @Listener(order = Order.POST) - public void onBan(final PlayerBannedEvent event) { - listener.onBan(event.getBan(), false, event.isSilent()); - } - - @Listener(order = Order.POST) - public void onUnban(final PlayerUnbanEvent event) { - listener.onUnban(event.getBan(), event.getActor(), event.getReason(), event.isSilent()); - } - - @Listener(order = Order.POST) - public void onMute(final PlayerMuteEvent event) { - listener.onMute(event.getMute(), true, event.isSilent()); - } - - @Listener(order = Order.POST) - public void onMute(final PlayerMutedEvent event) { - listener.onMute(event.getMute(), false, event.isSilent()); - } - - @Listener(order = Order.POST) - public void onUnmute(final PlayerUnmuteEvent event) { - listener.onUnmute(event.getMute(), event.getActor(), event.getReason(), event.isSilent()); - } - - @Listener(order = Order.POST) - public void onBan(final IpBanEvent event) { - listener.onBan(event.getBan(), true, event.isSilent()); - } - - @Listener(order = Order.POST) - public void onBan(final IpBannedEvent event) { - listener.onBan(event.getBan(), false, event.isSilent()); - } - - @Listener(order = Order.POST) - public void onUnban(final IpUnbanEvent event) { - listener.onUnban(event.getBan(), event.getActor(), event.getReason(), event.isSilent()); - } - - @Listener(order = Order.POST) - public void onBan(final IpRangeBanEvent event) { - listener.onBan(event.getBan(), true, event.isSilent()); - } - - @Listener(order = Order.POST) - public void onBan(final IpRangeBannedEvent event) { - listener.onBan(event.getBan(), false, event.isSilent()); - } - - @Listener(order = Order.POST) - public void onUnban(final IpRangeUnbanEvent event) { - listener.onUnban(event.getBan(), event.getActor(), event.getReason(), event.isSilent()); - } - - @Listener(order = Order.POST) - public void onWarn(final PlayerWarnEvent event) { - listener.onWarn(event.getWarning(), true, event.isSilent()); - } - - @Listener(order = Order.POST) - public void onWarn(final PlayerWarnedEvent event) { - listener.onWarn(event.getWarning(), false, event.isSilent()); - } - - @Listener(order = Order.POST) - public void onNote(final PlayerNoteCreatedEvent event) { - listener.onNote(event.getNote(), event.isSilent()); - } - - @Listener(order = Order.POST) - public void onReport(final PlayerReportEvent event) { - listener.onReport(event.getReport(), true, event.isSilent()); - } - - @Listener(order = Order.POST) - public void onReport(final PlayerReportedEvent event) { - listener.onReport(event.getReport(), false, event.isSilent()); - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/JoinListener.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/JoinListener.java deleted file mode 100644 index a3664d6d8..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/JoinListener.java +++ /dev/null @@ -1,87 +0,0 @@ -package me.confuser.banmanager.sponge.listeners; - -import lombok.RequiredArgsConstructor; -import me.confuser.banmanager.common.BanManagerPlugin; -import me.confuser.banmanager.common.data.PlayerData; -import me.confuser.banmanager.common.listeners.CommonJoinHandler; -import me.confuser.banmanager.common.listeners.CommonJoinListener; -import me.confuser.banmanager.common.util.*; -import me.confuser.banmanager.sponge.SpongePlayer; -import me.confuser.banmanager.sponge.SpongeServer; -import org.spongepowered.api.entity.living.player.User; -import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.Order; -import org.spongepowered.api.event.network.ClientConnectionEvent; - -import java.net.InetAddress; - -public class JoinListener { - private final CommonJoinListener listener; - private BanManagerPlugin plugin; - - public JoinListener(BanManagerPlugin plugin) { - this.plugin = plugin; - this.listener = new CommonJoinListener(plugin); - } - - @Listener(order = Order.LAST) - public void banCheck(final ClientConnectionEvent.Auth event) { - InetAddress address = event.getConnection().getAddress().getAddress(); - String name = event.getProfile().getName().get(); - - listener.banCheck(event.getProfile().getUniqueId(), name, IPUtils.toIPAddress(address), new BanJoinHandler(plugin, event)); - } - - @Listener(order = Order.LAST) - public void onJoin(ClientConnectionEvent.Auth event) { - if (event.isCancelled()) return; - - this.listener.onPreJoin(event.getProfile().getUniqueId(), event.getProfile().getName().get(), IPUtils.toIPAddress(event.getConnection().getAddress().getAddress())); - } - - @Listener(order = Order.LAST) - public void onJoin(final ClientConnectionEvent.Join event) { - listener.onJoin(new SpongePlayer(event.getTargetEntity(), plugin.getConfig().isOnlineMode())); - } - - @Listener(order = Order.LAST) - public void onPlayerLogin(final ClientConnectionEvent.Login event) { - User user = event.getTargetUser(); - listener.onPlayerLogin(new SpongePlayer(user, plugin.getConfig().isOnlineMode(), event.getConnection().getAddress().getAddress()), new LoginHandler(event)); - } - - @RequiredArgsConstructor - private class BanJoinHandler implements CommonJoinHandler { - private final BanManagerPlugin plugin; - private final ClientConnectionEvent.Auth event; - - @Override - public void handlePlayerDeny(PlayerData player, Message message) { - plugin.getServer().callEvent("PlayerDeniedEvent", player, message); - - handleDeny(message); - } - - @Override - public void handleDeny(Message message) { - event.setCancelled(true); - event.setMessage(SpongeServer.formatMessage(message.toString())); - } - } - - @RequiredArgsConstructor - private class LoginHandler implements CommonJoinHandler { - private final ClientConnectionEvent.Login event; - - @Override - public void handlePlayerDeny(PlayerData player, Message message) { - handleDeny(message); - } - - @Override - public void handleDeny(Message message) { - event.setMessage(SpongeServer.formatMessage(message.toString())); - event.setCancelled(true); - } - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/LeaveListener.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/LeaveListener.java deleted file mode 100644 index 701f01134..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/LeaveListener.java +++ /dev/null @@ -1,20 +0,0 @@ -package me.confuser.banmanager.sponge.listeners; - - -import me.confuser.banmanager.common.BanManagerPlugin; -import me.confuser.banmanager.common.listeners.CommonLeaveListener; -import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.network.ClientConnectionEvent; - -public class LeaveListener { - private final CommonLeaveListener listener; - - public LeaveListener(BanManagerPlugin plugin) { - this.listener = new CommonLeaveListener(plugin); - } - - @Listener - public void onLeave(ClientConnectionEvent.Disconnect event) { - listener.onLeave(event.getTargetEntity().getUniqueId(), event.getTargetEntity().getName()); - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/MuteListener.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/MuteListener.java deleted file mode 100644 index 02389b0d9..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/MuteListener.java +++ /dev/null @@ -1,67 +0,0 @@ -package me.confuser.banmanager.sponge.listeners; - - -import me.confuser.banmanager.common.BanManagerPlugin; -import me.confuser.banmanager.common.listeners.CommonMuteListener; -import me.confuser.banmanager.sponge.api.events.IpMutedEvent; -import me.confuser.banmanager.sponge.api.events.PlayerMutedEvent; -import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.Order; -import org.spongepowered.api.event.block.tileentity.ChangeSignEvent; -import org.spongepowered.api.event.filter.IsCancelled; -import org.spongepowered.api.event.filter.cause.Root; -import org.spongepowered.api.util.Tristate; - -public class MuteListener { - private final BanManagerPlugin plugin; - private final CommonMuteListener listener; - - public MuteListener(BanManagerPlugin plugin) { - this.plugin = plugin; - this.listener = new CommonMuteListener(plugin); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void notifyOnMute(PlayerMutedEvent event) { - listener.notifyOnMute(event.getMute(), event.isSilent()); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void notifyOnMute(IpMutedEvent event) { - listener.notifyOnMute(event.getMute(), event.isSilent()); - } - - @Listener(order = Order.DEFAULT) - public void blockOnPlayerMute(ChangeSignEvent event, @Root Player player) { - if (plugin.getPlayerMuteStorage().isMuted(player.getUniqueId()) && player.hasPermission("bm.block.muted.sign")) { - event.getTargetTile().getLocation().removeBlock(); - event.setCancelled(true); - } - } - - @Listener(order = Order.DEFAULT) - public void blockOnIpMute(ChangeSignEvent event, @Root Player player) { - if (plugin.getIpMuteStorage().isMuted(player.getConnection().getAddress().getAddress()) && player.hasPermission("bm.block.ipmuted.sign")) { - event.getTargetTile().getLocation().removeBlock(); - event.setCancelled(true); - } - } - - // Book events unsupported by Sponge API -// @Listener(order = Order.DEFAULT) -// public void blockOnPlayerMute(PlayerEditBookEvent event, @Root Player player) { -// if (plugin.getPlayerMuteStorage().isMuted(player.getUniqueId()) && player.hasPermission("bm.block.muted.book")) { -// event.setCancelled(true); -// } -// } -// -// @Listener(order = Order.DEFAULT) -// public void blockOnIpMute(PlayerEditBookEvent event, @Root Player player) { -// if (plugin.getIpMuteStorage().isMuted(player.getConnection().getAddress().getAddress()) && player.hasPermission("bm.block.ipmuted.book")) { -// event.setCancelled(true); -// } -// } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/NoteListener.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/NoteListener.java deleted file mode 100644 index d507ac7a8..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/NoteListener.java +++ /dev/null @@ -1,25 +0,0 @@ -package me.confuser.banmanager.sponge.listeners; - - -import me.confuser.banmanager.common.BanManagerPlugin; -import me.confuser.banmanager.common.listeners.CommonNoteListener; -import me.confuser.banmanager.sponge.api.events.PlayerNoteCreatedEvent; -import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.Order; -import org.spongepowered.api.event.filter.IsCancelled; -import org.spongepowered.api.util.Tristate; - -public class NoteListener { - private final CommonNoteListener listener; - - public NoteListener(BanManagerPlugin plugin) { - this.listener = new CommonNoteListener(plugin); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void notifyOnNote(PlayerNoteCreatedEvent event) { - listener.notifyOnNote(event.getNote(), event.isSilent()); - } - -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/ReloadListener.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/ReloadListener.java deleted file mode 100644 index f547315bf..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/ReloadListener.java +++ /dev/null @@ -1,17 +0,0 @@ -package me.confuser.banmanager.sponge.listeners; - -import lombok.RequiredArgsConstructor; -import me.confuser.banmanager.sponge.BMSpongePlugin; -import me.confuser.banmanager.sponge.api.events.PluginReloadedEvent; -import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.Order; - -@RequiredArgsConstructor -public class ReloadListener { - private final BMSpongePlugin spongePlugin; - - @Listener(order = Order.POST) - public void onReload(final PluginReloadedEvent event) { - spongePlugin.registerChatListener(); - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/ReportListener.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/ReportListener.java deleted file mode 100644 index bc911a91e..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/ReportListener.java +++ /dev/null @@ -1,73 +0,0 @@ -package me.confuser.banmanager.sponge.listeners; - -import me.confuser.banmanager.common.BanManagerPlugin; -import me.confuser.banmanager.common.data.PlayerData; -import me.confuser.banmanager.common.data.PlayerReportData; -import me.confuser.banmanager.common.data.PlayerReportLocationData; -import me.confuser.banmanager.common.listeners.CommonReportListener; -import me.confuser.banmanager.common.util.UUIDUtils; -import me.confuser.banmanager.sponge.api.events.PlayerReportDeletedEvent; -import me.confuser.banmanager.sponge.api.events.PlayerReportedEvent; -import org.spongepowered.api.Sponge; -import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.Order; -import org.spongepowered.api.event.filter.IsCancelled; -import org.spongepowered.api.util.Tristate; -import org.spongepowered.api.world.Location; -import org.spongepowered.api.world.World; - -import java.sql.SQLException; -import java.util.Optional; - -public class ReportListener { - private final CommonReportListener listener; - private BanManagerPlugin plugin; - - public ReportListener(BanManagerPlugin plugin) { - this.plugin = plugin; - this.listener = new CommonReportListener(plugin); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void notifyOnReport(PlayerReportedEvent event) { - listener.notifyOnReport(event.getReport()); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void storeLocation(PlayerReportedEvent event) { - PlayerReportData report = event.getReport(); - - Optional player = Sponge.getServer().getPlayer(report.getPlayer().getUUID()); - Optional actor = Sponge.getServer().getPlayer(report.getActor().getUUID()); - - try { - if (player.isPresent()) createLocation(report, player.get()); - } catch (SQLException e) { - plugin.getLogger().warning("Failed to store report location for reported player", e); - } - - try { - if (actor.isPresent()) createLocation(report, actor.get()); - } catch (SQLException e) { - plugin.getLogger().warning("Failed to store report location for actor", e); - } - } - - private void createLocation(PlayerReportData report, Player player) throws SQLException { - if (player == null) return; - - PlayerData playerData = plugin.getPlayerStorage().queryForId(UUIDUtils.toBytes(player.getUniqueId())); - Location loc = player.getLocation(); - - plugin.getPlayerReportLocationStorage() - .create(new PlayerReportLocationData(report, playerData, player.getWorld().getName(), loc.getX(), loc.getY(), loc.getZ(), 0, 0)); - } - - @Listener - public void deleteReferences(PlayerReportDeletedEvent event) { - listener.deleteReferences(event.getReport()); - } -} diff --git a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/WebhookListener.java b/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/WebhookListener.java deleted file mode 100644 index e63b2e493..000000000 --- a/sponge-api7/src/main/java/me/confuser/banmanager/sponge/listeners/WebhookListener.java +++ /dev/null @@ -1,91 +0,0 @@ -package me.confuser.banmanager.sponge.listeners; - -import me.confuser.banmanager.common.BanManagerPlugin; -import me.confuser.banmanager.common.listeners.CommonWebhookListener; -import me.confuser.banmanager.common.listeners.CommonWebhookListener.WebhookData; -import me.confuser.banmanager.sponge.api.events.*; -import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.Order; -import org.spongepowered.api.event.filter.IsCancelled; -import org.spongepowered.api.util.Tristate; - -import java.util.List; - -public class WebhookListener { - private CommonWebhookListener listener; - - public WebhookListener(BanManagerPlugin plugin) { - this.listener = new CommonWebhookListener(plugin); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void notifyOnBan(PlayerBannedEvent event) { - List webhooks = listener.notifyOnBan(event.getBan()); - sendAll(webhooks, event.isSilent()); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void notifyOnMute(PlayerMutedEvent event) { - List webhooks = listener.notifyOnMute(event.getMute()); - sendAll(webhooks, event.isSilent()); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void notifyOnWarn(PlayerWarnedEvent event) { - List webhooks = listener.notifyOnWarn(event.getWarning()); - sendAll(webhooks, event.isSilent()); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void notifyOnBan(IpBannedEvent event) { - List webhooks = listener.notifyOnBan(event.getBan()); - sendAll(webhooks, event.isSilent()); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void notifyOnKick(PlayerKickedEvent event) { - List webhooks = listener.notifyOnKick(event.getKick()); - sendAll(webhooks, event.isSilent()); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void notifyOnUnban(PlayerUnbanEvent event) { - List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); - sendAll(webhooks, event.isSilent()); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void notifyOnUnban(IpUnbanEvent event) { - List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); - sendAll(webhooks, event.isSilent()); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void notifyOnUnmute(PlayerUnmuteEvent event) { - List webhooks = listener.notifyOnUnmute(event.getMute(), event.getActor(), event.getReason()); - sendAll(webhooks, event.isSilent()); - } - - @IsCancelled(Tristate.UNDEFINED) - @Listener(order = Order.POST) - public void notifyOnReport(PlayerReportedEvent event) { - List webhooks = listener.notifyOnReport(event.getReport(), event.getReport().getActor(), event.getReport().getReason()); - sendAll(webhooks, event.isSilent()); - } - - private void sendAll(List webhooks, boolean isSilent) { - for (WebhookData data : webhooks) { - if (isSilent && data.ignoreSilent) continue; - if (data.url == null || data.payload == null || data.url.isEmpty() || data.payload.isEmpty()) continue; - listener.sendAsync(data); - } - } -} diff --git a/sponge-api7/src/main/resources/assets/banmanager/bungeecord.yml b/sponge-api7/src/main/resources/assets/banmanager/bungeecord.yml deleted file mode 120000 index 742692bc8..000000000 --- a/sponge-api7/src/main/resources/assets/banmanager/bungeecord.yml +++ /dev/null @@ -1 +0,0 @@ -../../../../../../common/src/main/resources/bungeecord.yml \ No newline at end of file diff --git a/sponge-api7/src/main/resources/assets/banmanager/config.yml b/sponge-api7/src/main/resources/assets/banmanager/config.yml deleted file mode 120000 index 619878a08..000000000 --- a/sponge-api7/src/main/resources/assets/banmanager/config.yml +++ /dev/null @@ -1 +0,0 @@ -../../../../../../common/src/main/resources/config.yml \ No newline at end of file diff --git a/sponge-api7/src/main/resources/assets/banmanager/console.yml b/sponge-api7/src/main/resources/assets/banmanager/console.yml deleted file mode 120000 index fc487da89..000000000 --- a/sponge-api7/src/main/resources/assets/banmanager/console.yml +++ /dev/null @@ -1 +0,0 @@ -../../../../../../common/src/main/resources/console.yml \ No newline at end of file diff --git a/sponge-api7/src/main/resources/assets/banmanager/exemptions.yml b/sponge-api7/src/main/resources/assets/banmanager/exemptions.yml deleted file mode 120000 index c95f439b6..000000000 --- a/sponge-api7/src/main/resources/assets/banmanager/exemptions.yml +++ /dev/null @@ -1 +0,0 @@ -../../../../../../common/src/main/resources/exemptions.yml \ No newline at end of file diff --git a/sponge-api7/src/main/resources/assets/banmanager/geoip.yml b/sponge-api7/src/main/resources/assets/banmanager/geoip.yml deleted file mode 120000 index 0e6626141..000000000 --- a/sponge-api7/src/main/resources/assets/banmanager/geoip.yml +++ /dev/null @@ -1 +0,0 @@ -../../../../../../common/src/main/resources/geoip.yml \ No newline at end of file diff --git a/sponge-api7/src/main/resources/assets/banmanager/messages.yml b/sponge-api7/src/main/resources/assets/banmanager/messages.yml deleted file mode 120000 index 6485e7039..000000000 --- a/sponge-api7/src/main/resources/assets/banmanager/messages.yml +++ /dev/null @@ -1 +0,0 @@ -../../../../../../common/src/main/resources/messages.yml \ No newline at end of file diff --git a/sponge-api7/src/main/resources/assets/banmanager/plugin.yml b/sponge-api7/src/main/resources/assets/banmanager/plugin.yml deleted file mode 120000 index e5feab9d4..000000000 --- a/sponge-api7/src/main/resources/assets/banmanager/plugin.yml +++ /dev/null @@ -1 +0,0 @@ -../../../../../../common/src/main/resources/plugin.yml \ No newline at end of file diff --git a/sponge-api7/src/main/resources/assets/banmanager/reasons.yml b/sponge-api7/src/main/resources/assets/banmanager/reasons.yml deleted file mode 120000 index ac05a56ca..000000000 --- a/sponge-api7/src/main/resources/assets/banmanager/reasons.yml +++ /dev/null @@ -1 +0,0 @@ -../../../../../../common/src/main/resources/reasons.yml \ No newline at end of file diff --git a/sponge-api7/src/main/resources/assets/banmanager/schedules.yml b/sponge-api7/src/main/resources/assets/banmanager/schedules.yml deleted file mode 120000 index 56be43cd1..000000000 --- a/sponge-api7/src/main/resources/assets/banmanager/schedules.yml +++ /dev/null @@ -1 +0,0 @@ -../../../../../../common/src/main/resources/schedules.yml \ No newline at end of file diff --git a/sponge-api7/src/main/resources/assets/banmanager/velocity.yml b/sponge-api7/src/main/resources/assets/banmanager/velocity.yml deleted file mode 120000 index 3fc579b4e..000000000 --- a/sponge-api7/src/main/resources/assets/banmanager/velocity.yml +++ /dev/null @@ -1 +0,0 @@ -../../../../../../common/src/main/resources/velocity.yml \ No newline at end of file diff --git a/sponge-api7/src/main/resources/assets/banmanager/webhooks.yml b/sponge-api7/src/main/resources/assets/banmanager/webhooks.yml deleted file mode 120000 index f0bdbed4f..000000000 --- a/sponge-api7/src/main/resources/assets/banmanager/webhooks.yml +++ /dev/null @@ -1 +0,0 @@ -../../../../../../common/src/main/resources/webhooks.yml \ No newline at end of file diff --git a/sponge/src/main/java/me/confuser/banmanager/sponge/BMSpongePlugin.java b/sponge/src/main/java/me/confuser/banmanager/sponge/BMSpongePlugin.java index 4b4f8d737..95c124cfc 100644 --- a/sponge/src/main/java/me/confuser/banmanager/sponge/BMSpongePlugin.java +++ b/sponge/src/main/java/me/confuser/banmanager/sponge/BMSpongePlugin.java @@ -55,7 +55,7 @@ public class BMSpongePlugin { "webhooks.yml", "exemptions.yml", "geoip.yml", - "messages.yml", + "notifications.yml", "reasons.yml", "schedules.yml" }; diff --git a/sponge/src/main/java/me/confuser/banmanager/sponge/SpongePlayer.java b/sponge/src/main/java/me/confuser/banmanager/sponge/SpongePlayer.java index 82e04490b..e2e8fd7a8 100644 --- a/sponge/src/main/java/me/confuser/banmanager/sponge/SpongePlayer.java +++ b/sponge/src/main/java/me/confuser/banmanager/sponge/SpongePlayer.java @@ -6,14 +6,19 @@ import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.kyori.text.TextComponent; import me.confuser.banmanager.common.util.Message; +import me.confuser.banmanager.common.util.MessageRenderer; +import me.confuser.banmanager.common.util.MessageRegistry; import me.confuser.banmanager.common.util.UUIDUtils; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.kyori.adventure.title.Title; import org.spongepowered.api.Sponge; import org.spongepowered.api.entity.living.player.server.ServerPlayer; import org.spongepowered.api.world.server.ServerLocation; import org.spongepowered.api.world.server.ServerWorld; -import org.spongepowered.math.vector.Vector3d; import java.net.InetAddress; import java.sql.SQLException; @@ -46,6 +51,11 @@ public void kick(String message) { getPlayer().kick(SpongeServer.formatMessage(message)); } + @Override + public void kick(me.confuser.banmanager.common.kyori.text.Component component) { + getPlayer().kick(convertToNative(component)); + } + @Override public void sendMessage(String message) { if (message.isEmpty()) return; @@ -58,8 +68,38 @@ public void sendMessage(String message) { } @Override - public void sendMessage(Message message) { - sendMessage(message.toString()); + public void sendMessage(me.confuser.banmanager.common.kyori.text.Component component) { + getPlayer().sendMessage(convertToNative(component)); + } + + @Override + public void sendActionBar(me.confuser.banmanager.common.kyori.text.Component component) { + getPlayer().sendActionBar(convertToNative(component)); + } + + @Override + public void showTitle(me.confuser.banmanager.common.kyori.text.Component title, + me.confuser.banmanager.common.kyori.text.Component subtitle, + int fadeIn, int stay, int fadeOut) { + Component nativeTitle = title != null ? convertToNative(title) : Component.empty(); + Component nativeSubtitle = subtitle != null ? convertToNative(subtitle) : Component.empty(); + Title.Times times = Title.Times.times( + java.time.Duration.ofMillis(fadeIn * 50L), + java.time.Duration.ofMillis(stay * 50L), + java.time.Duration.ofMillis(fadeOut * 50L) + ); + getPlayer().showTitle(Title.title(nativeTitle, nativeSubtitle, times)); + } + + @Override + public void playSound(String sound, float volume, float pitch) { + ServerPlayer p = getPlayer(); + if (p == null) return; + try { + p.playSound(Sound.sound(Key.key(sound), Sound.Source.MASTER, volume, pitch)); + } catch (IllegalArgumentException ignored) { + // Invalid sound key -- silently ignore + } } @Override @@ -72,6 +112,11 @@ public void sendJSONMessage(String jsonString) { getPlayer().sendMessage(SpongeServer.formatJsonMessage(jsonString)); } + private Component convertToNative(me.confuser.banmanager.common.kyori.text.Component component) { + String json = MessageRenderer.getInstance().toJson(component); + return GsonComponentSerializer.gson().deserialize(json); + } + @Override public boolean isConsole() { return false; @@ -170,6 +215,13 @@ public boolean canSee(CommonPlayer player) { return target.map(serverPlayer -> p.canSee(serverPlayer)).orElse(false); } + @Override + public String getLocale() { + ServerPlayer p = getPlayer(); + if (p == null) return "en"; + return MessageRegistry.normaliseLocale(p.locale().toString()); + } + private ServerPlayer getPlayer() { if (player != null && !player.isRemoved()) { return player; diff --git a/sponge/src/main/java/me/confuser/banmanager/sponge/SpongeSender.java b/sponge/src/main/java/me/confuser/banmanager/sponge/SpongeSender.java index ff1db3334..cbb681024 100644 --- a/sponge/src/main/java/me/confuser/banmanager/sponge/SpongeSender.java +++ b/sponge/src/main/java/me/confuser/banmanager/sponge/SpongeSender.java @@ -61,11 +61,6 @@ public void sendMessage(String message) { audience.sendMessage(SpongeServer.formatMessage(message)); } - @Override - public void sendMessage(Message message) { - sendMessage(message.toString()); - } - @Override public boolean isConsole() { if (audience instanceof ServerPlayer) { diff --git a/sponge/src/main/java/me/confuser/banmanager/sponge/SpongeServer.java b/sponge/src/main/java/me/confuser/banmanager/sponge/SpongeServer.java index d7031da51..b10f3bc6d 100644 --- a/sponge/src/main/java/me/confuser/banmanager/sponge/SpongeServer.java +++ b/sponge/src/main/java/me/confuser/banmanager/sponge/SpongeServer.java @@ -4,7 +4,6 @@ import me.confuser.banmanager.common.api.events.CommonEvent; import me.confuser.banmanager.common.commands.CommonSender; import me.confuser.banmanager.common.data.*; -import me.confuser.banmanager.common.kyori.text.TextComponent; import me.confuser.banmanager.common.kyori.text.serializer.gson.GsonComponentSerializer; import me.confuser.banmanager.common.util.ColorUtils; import me.confuser.banmanager.common.util.Message; @@ -66,13 +65,6 @@ public void broadcast(String message, String permission) { Sponge.systemSubject().sendMessage(formatMessage(message)); } - @Override - public void broadcastJSON(TextComponent message, String permission) { - Arrays.stream(getOnlinePlayers()).forEach(player -> { - if (player.hasPermission(permission)) player.sendJSONMessage(message); - }); - } - public void broadcast(String message, String permission, CommonSender sender) { broadcast(message, permission); @@ -88,10 +80,10 @@ public static Component formatMessage(String message) { } public static Component formatMessage(Message message) { - return formatMessage(message.toString()); + return formatMessage(message.resolveComponent()); } - public static Component formatMessage(TextComponent message) { + public static Component formatMessage(me.confuser.banmanager.common.kyori.text.Component message) { String json = GsonComponentSerializer.gson().serialize(message); return net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().deserialize(json); } diff --git a/sponge/src/main/java/me/confuser/banmanager/sponge/listeners/JoinListener.java b/sponge/src/main/java/me/confuser/banmanager/sponge/listeners/JoinListener.java index 3c3b9567f..ea4749f44 100644 --- a/sponge/src/main/java/me/confuser/banmanager/sponge/listeners/JoinListener.java +++ b/sponge/src/main/java/me/confuser/banmanager/sponge/listeners/JoinListener.java @@ -79,14 +79,17 @@ private class BanJoinHandler implements CommonJoinHandler { @Override public void handlePlayerDeny(PlayerData player, Message message) { plugin.getServer().callEvent("PlayerDeniedEvent", player, message); - handleDeny(message); + String locale = player.getLocale() != null ? player.getLocale() : "en"; + isDenied = true; + event.setCancelled(true); + event.setMessage(SpongeServer.formatMessage(message.resolveComponent(locale))); } @Override public void handleDeny(Message message) { isDenied = true; event.setCancelled(true); - event.setMessage(SpongeServer.formatMessage(message.toString())); + event.setMessage(SpongeServer.formatMessage(message.resolveComponent())); } } @@ -101,7 +104,7 @@ public void handlePlayerDeny(PlayerData player, Message message) { @Override public void handleDeny(Message message) { - player.kick(SpongeServer.formatMessage(message.toString())); + new SpongePlayer(player, plugin.getConfig().isOnlineMode()).kick(message); } } } diff --git a/sponge/src/main/resources/assets/banmanager/messages b/sponge/src/main/resources/assets/banmanager/messages new file mode 120000 index 000000000..d4dc599aa --- /dev/null +++ b/sponge/src/main/resources/assets/banmanager/messages @@ -0,0 +1 @@ +../../../../../../common/src/main/resources/messages \ No newline at end of file diff --git a/sponge/src/main/resources/assets/banmanager/messages.yml b/sponge/src/main/resources/assets/banmanager/messages.yml deleted file mode 120000 index 6485e7039..000000000 --- a/sponge/src/main/resources/assets/banmanager/messages.yml +++ /dev/null @@ -1 +0,0 @@ -../../../../../../common/src/main/resources/messages.yml \ No newline at end of file diff --git a/velocity/src/main/java/me/confuser/banmanager/velocity/BMVelocityPlugin.java b/velocity/src/main/java/me/confuser/banmanager/velocity/BMVelocityPlugin.java index ffc4ae78b..e9e49511d 100644 --- a/velocity/src/main/java/me/confuser/banmanager/velocity/BMVelocityPlugin.java +++ b/velocity/src/main/java/me/confuser/banmanager/velocity/BMVelocityPlugin.java @@ -59,7 +59,7 @@ public class BMVelocityPlugin { "webhooks.yml", "exemptions.yml", "geoip.yml", - "messages.yml", + "notifications.yml", "reasons.yml", "schedules.yml" }; diff --git a/velocity/src/main/java/me/confuser/banmanager/velocity/VelocityPlayer.java b/velocity/src/main/java/me/confuser/banmanager/velocity/VelocityPlayer.java index c0de0b1ef..e2977477f 100644 --- a/velocity/src/main/java/me/confuser/banmanager/velocity/VelocityPlayer.java +++ b/velocity/src/main/java/me/confuser/banmanager/velocity/VelocityPlayer.java @@ -5,16 +5,25 @@ import me.confuser.banmanager.common.CommonWorld; import me.confuser.banmanager.common.commands.CommonCommand; import me.confuser.banmanager.common.data.PlayerData; -import me.confuser.banmanager.common.util.Message; +import me.confuser.banmanager.common.kyori.text.Component; import me.confuser.banmanager.common.kyori.text.TextComponent; +import me.confuser.banmanager.common.util.Message; +import me.confuser.banmanager.common.util.MessageRenderer; +import me.confuser.banmanager.common.util.MessageRegistry; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; - +import net.kyori.adventure.title.Title; import java.net.InetAddress; -import java.util.Optional; +import java.time.Duration; import java.util.UUID; public class VelocityPlayer implements CommonPlayer { + // Only used for legacy sendJSONMessage(String) path; Component methods use full-color gson + private static final GsonComponentSerializer DOWNSAMPLING_GSON = + GsonComponentSerializer.builder().downsampleColors().build(); + private final UUID uuid; private final boolean onlineMode; private final Player player; @@ -30,6 +39,11 @@ public void kick(String message) { player.disconnect(VelocityServer.formatMessage(message)); } + @Override + public void kick(Component component) { + player.disconnect(convertToNative(component)); + } + @Override public void sendMessage(String message) { if(message.isEmpty()) return; @@ -42,8 +56,37 @@ public void sendMessage(String message) { } @Override - public void sendMessage(Message message) { - sendMessage(message.toString()); + public void sendMessage(Component component) { + player.sendMessage(convertToNative(component)); + } + + @Override + public void sendActionBar(Component component) { + player.sendActionBar(convertToNative(component)); + } + + @Override + public void showTitle(Component title, Component subtitle, int fadeIn, int stay, int fadeOut) { + net.kyori.adventure.text.Component nativeTitle = title != null + ? convertToNative(title) : net.kyori.adventure.text.Component.empty(); + net.kyori.adventure.text.Component nativeSubtitle = subtitle != null + ? convertToNative(subtitle) : net.kyori.adventure.text.Component.empty(); + + Title.Times times = Title.Times.of( + Duration.ofMillis(fadeIn * 50L), + Duration.ofMillis(stay * 50L), + Duration.ofMillis(fadeOut * 50L) + ); + player.showTitle(Title.title(nativeTitle, nativeSubtitle, times)); + } + + @Override + public void playSound(String sound, float volume, float pitch) { + try { + player.playSound(Sound.sound(Key.key(sound), Sound.Source.MASTER, volume, pitch)); + } catch (IllegalArgumentException ignored) { + // Invalid sound key -- silently ignore + } } @Override @@ -53,7 +96,12 @@ public void sendJSONMessage(TextComponent jsonString) { @Override public void sendJSONMessage(String jsonString) { - player.sendMessage(GsonComponentSerializer.colorDownsamplingGson().deserialize(jsonString)); + player.sendMessage(DOWNSAMPLING_GSON.deserialize(jsonString)); + } + + private net.kyori.adventure.text.Component convertToNative(Component component) { + String json = MessageRenderer.getInstance().toJson(component); + return GsonComponentSerializer.gson().deserialize(json); } @Override @@ -98,7 +146,7 @@ public InetAddress getAddress() { @Override public UUID getUniqueId() { - return this.player.getUniqueId(); + return this.uuid; } @Override @@ -110,4 +158,11 @@ public boolean teleport(CommonWorld world, double x, double y, double z, float p public boolean canSee(CommonPlayer player) { return true; } + + @Override + public String getLocale() { + java.util.Locale locale = player.getEffectiveLocale(); + if (locale == null) return "en"; + return MessageRegistry.normaliseLocale(locale.toString()); + } } diff --git a/velocity/src/main/java/me/confuser/banmanager/velocity/VelocitySender.java b/velocity/src/main/java/me/confuser/banmanager/velocity/VelocitySender.java index af783e818..e7270df8e 100644 --- a/velocity/src/main/java/me/confuser/banmanager/velocity/VelocitySender.java +++ b/velocity/src/main/java/me/confuser/banmanager/velocity/VelocitySender.java @@ -6,7 +6,6 @@ import me.confuser.banmanager.common.commands.CommonCommand; import me.confuser.banmanager.common.commands.CommonSender; import me.confuser.banmanager.common.data.PlayerData; -import me.confuser.banmanager.common.util.Message; public class VelocitySender implements CommonSender { @@ -31,11 +30,6 @@ public void sendMessage(String message) { commandSource.sendMessage(VelocityServer.formatMessage(message)); } - @Override - public void sendMessage(Message message) { - sendMessage(message.toString()); - } - @Override public boolean isConsole() { return !(commandSource instanceof Player); diff --git a/velocity/src/main/java/me/confuser/banmanager/velocity/VelocityServer.java b/velocity/src/main/java/me/confuser/banmanager/velocity/VelocityServer.java index 129f723d1..f4357eacc 100644 --- a/velocity/src/main/java/me/confuser/banmanager/velocity/VelocityServer.java +++ b/velocity/src/main/java/me/confuser/banmanager/velocity/VelocityServer.java @@ -9,7 +9,6 @@ import me.confuser.banmanager.common.api.events.CommonEvent; import me.confuser.banmanager.common.commands.CommonSender; import me.confuser.banmanager.common.data.*; -import me.confuser.banmanager.common.kyori.text.TextComponent; import me.confuser.banmanager.common.util.ColorUtils; import me.confuser.banmanager.common.util.Message; import me.confuser.banmanager.velocity.api.events.*; @@ -70,16 +69,6 @@ public void broadcast(String message, String permission) { } } - @Override - public void broadcastJSON(TextComponent message, String permission) { - Component converted = convert(message); - for (Player player : server.getAllPlayers()) { - if (player.hasPermission(permission)) { - player.sendMessage(converted); - } - } - } - @Override public void broadcast(String message, String permission, CommonSender sender) { broadcast(message, permission); diff --git a/velocity/src/main/java/me/confuser/banmanager/velocity/listeners/JoinListener.java b/velocity/src/main/java/me/confuser/banmanager/velocity/listeners/JoinListener.java index e128d6d18..c806feb0c 100644 --- a/velocity/src/main/java/me/confuser/banmanager/velocity/listeners/JoinListener.java +++ b/velocity/src/main/java/me/confuser/banmanager/velocity/listeners/JoinListener.java @@ -56,13 +56,14 @@ public static class BanJoinHandler implements CommonJoinHandler { @Override public void handleDeny(Message message) { - event.setResult(ResultedEvent.ComponentResult.denied(VelocityServer.formatMessage(message.toString()))); + event.setResult(ResultedEvent.ComponentResult.denied(VelocityServer.convert(message.resolveComponent()))); } @Override public void handlePlayerDeny(PlayerData player, Message message) { plugin.getServer().callEvent("PlayerDeniedEvent", player, message); - event.setResult(ResultedEvent.ComponentResult.denied(VelocityServer.formatMessage(message.toString()))); + event.setResult(ResultedEvent.ComponentResult.denied( + VelocityServer.convert(message.resolveComponent(player.getLocale() != null ? player.getLocale() : "en")))); } } @@ -72,7 +73,7 @@ public class LoginHandler implements CommonJoinHandler { @Override public void handleDeny(Message message) { - event.getPlayer().disconnect(VelocityServer.formatMessage(message.toString())); + event.getPlayer().disconnect(VelocityServer.convert(message.resolveComponent())); } @Override