diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..89d1b5c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,37 @@ +name: Build & Release + +on: + push: + tags: + - 'v*' + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Java 21 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '21' + + - name: Build with Gradle + run: chmod +x gradlew && ./gradlew shadowJar + + - name: Get version from tag + id: version + run: echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + name: "PixelChatGuardian v${{ steps.version.outputs.VERSION }}" + generate_release_notes: true + files: build/libs/PixelChatGuardian-*.jar diff --git a/build.gradle b/build.gradle index 9b91763..faeb5b0 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ plugins { // Project metadata group = 'de.pixelmindmc' -version = '1.2.0' +version = '1.3.0' description = 'AI-powered chat moderation featuring smart filtering, anti-spam and rich chat formatting including emojis and colors' // Dependency versions diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/src/main/java/de/pixelmindmc/pixelchat/constants/LangConstants.java b/src/main/java/de/pixelmindmc/pixelchat/constants/LangConstants.java index e64364b..5b7485f 100644 --- a/src/main/java/de/pixelmindmc/pixelchat/constants/LangConstants.java +++ b/src/main/java/de/pixelmindmc/pixelchat/constants/LangConstants.java @@ -72,6 +72,7 @@ public static final class ChatGuard { public static final String CLEARED_STRIKES_ON_SERVER_RESTART = "chatguard.cleared-strikes-on-server-restart"; public static final String MESSAGE_BLOCKED = "chatguard.player.message-blocked"; public static final String MESSAGE_CENSORED = "chatguard.player.message-censored"; + public static final String MESSAGE_SILENCED = "chatguard.player.message-silenced"; public static final String PLAYER_KICK = "chatguard.player.kick"; public static final String PLAYER_TEMP_BAN = "chatguard.player.ban-temporary"; public static final String PLAYER_PERM_BAN = "chatguard.player.ban-permanent"; diff --git a/src/main/java/de/pixelmindmc/pixelchat/integration/CarbonChatIntegration.java b/src/main/java/de/pixelmindmc/pixelchat/integration/CarbonChatIntegration.java index eb5fc7c..6dbfb65 100644 --- a/src/main/java/de/pixelmindmc/pixelchat/integration/CarbonChatIntegration.java +++ b/src/main/java/de/pixelmindmc/pixelchat/integration/CarbonChatIntegration.java @@ -83,12 +83,24 @@ private void checkIfMessageShouldBeBlocked(@NotNull CarbonChatEvent event, @NotN // Check if classification matches any enabled blocking rules if (ChatGuardHelper.messageMatchesEnabledRule(plugin, classification)) { - boolean blockOrCensor = plugin.getConfigHelper().getString(ConfigConstants.ChatGuard.MESSAGE_HANDLING).equals("BLOCK"); - if (blockOrCensor) event.cancelled(true); - else event.message(Component.text("*".repeat(message.length()))); + String messageHandling = plugin.getConfigHelper().getString(ConfigConstants.ChatGuard.MESSAGE_HANDLING); + + switch (messageHandling) { + case "BLOCK" -> event.cancelled(true); + case "SILENT" -> { + // Cancel the event so no other players see the message + event.cancelled(true); + // Send the original message back to the author, creating the illusion of successful delivery + Player senderPlayer = Bukkit.getPlayer(event.sender().uuid()); + if (senderPlayer != null) + senderPlayer.sendMessage("<" + senderPlayer.getDisplayName() + "> " + message); + } + default -> // CENSOR + event.message(Component.text("*".repeat(message.length()))); + } Player player = Bukkit.getPlayer(event.sender().uuid()); - if (player != null) ChatGuardHelper.notifyAndStrikePlayer(plugin, player, message, classification, blockOrCensor); + if (player != null) ChatGuardHelper.notifyAndStrikePlayer(plugin, player, message, classification, messageHandling); } } } \ No newline at end of file diff --git a/src/main/java/de/pixelmindmc/pixelchat/listener/AsyncPlayerChatListener.java b/src/main/java/de/pixelmindmc/pixelchat/listener/AsyncPlayerChatListener.java index 19f2784..ea78a1d 100644 --- a/src/main/java/de/pixelmindmc/pixelchat/listener/AsyncPlayerChatListener.java +++ b/src/main/java/de/pixelmindmc/pixelchat/listener/AsyncPlayerChatListener.java @@ -117,12 +117,12 @@ private void onAsyncPlayerChat(@NotNull AsyncPlayerChatEvent event) { } /** - * Checks whether a message should be blocked or censored and takes appropriate actions + * Checks whether a message should be blocked, censored, or silently moderated and takes appropriate actions * * @param event The message event * @param message The message to check * @param player The player that sent the message - * @return {@code true} if the message has been blocked, {@code false} if it has been allowed through + * @return {@code true} if the message has been blocked or silently moderated, {@code false} if it has been allowed through */ private boolean checkIfMessageShouldBeBlocked(@NotNull AsyncPlayerChatEvent event, @NotNull String message, @NotNull Player player) { // Debug logger message @@ -138,13 +138,24 @@ private boolean checkIfMessageShouldBeBlocked(@NotNull AsyncPlayerChatEvent even // Check if classification matches any enabled blocking rules if (ChatGuardHelper.messageMatchesEnabledRule(plugin, classification)) { - boolean blockOrCensor = plugin.getConfigHelper().getString(ConfigConstants.ChatGuard.MESSAGE_HANDLING).equals("BLOCK"); - if (blockOrCensor) event.setCancelled(true); - else event.setMessage("*".repeat(message.length())); + String messageHandling = plugin.getConfigHelper().getString(ConfigConstants.ChatGuard.MESSAGE_HANDLING); + + switch (messageHandling) { + case "BLOCK" -> event.setCancelled(true); + case "SILENT" -> { + // Cancel the event so no other players see the message + event.setCancelled(true); + // Send the message back to the author using the chat format, creating the illusion of successful delivery + String fakeMessage = String.format(event.getFormat(), player.getDisplayName(), message); + player.sendMessage(fakeMessage); + } + default -> // CENSOR + event.setMessage("*".repeat(message.length())); + } - ChatGuardHelper.notifyAndStrikePlayer(plugin, player, message, classification, blockOrCensor); + ChatGuardHelper.notifyAndStrikePlayer(plugin, player, message, classification, messageHandling); - return true; // Message has been blocked or censored + return true; // Message has been blocked, censored, or silently moderated } return false; } diff --git a/src/main/java/de/pixelmindmc/pixelchat/utils/ChatGuardHelper.java b/src/main/java/de/pixelmindmc/pixelchat/utils/ChatGuardHelper.java index 922c460..d3ae402 100644 --- a/src/main/java/de/pixelmindmc/pixelchat/utils/ChatGuardHelper.java +++ b/src/main/java/de/pixelmindmc/pixelchat/utils/ChatGuardHelper.java @@ -32,12 +32,12 @@ private ChatGuardHelper() { /** * Notifies the player of their message being blocked, logs the block itself, and also applies the strike system * - * @param player The player that sent the message - * @param userMessage The message that the user sent - * @param classification The classification of the message - * @param blockOrCensor Whether the message should be blocked ({@code true}) or censored ({@code false}) + * @param player The player that sent the message + * @param userMessage The message that the user sent + * @param classification The classification of the message + * @param messageHandling The message handling mode: "BLOCK", "CENSOR", or "SILENT" */ - public static void notifyAndStrikePlayer(@NotNull PixelChat plugin, @NotNull Player player, @NotNull String userMessage, @NotNull MessageClassification classification, boolean blockOrCensor) { + public static void notifyAndStrikePlayer(@NotNull PixelChat plugin, @NotNull Player player, @NotNull String userMessage, @NotNull MessageClassification classification, @NotNull String messageHandling) { // Debug logger message plugin.getLoggingHelper().debug("Notify player"); @@ -47,13 +47,17 @@ public static void notifyAndStrikePlayer(@NotNull PixelChat plugin, @NotNull Pla chatGuardPrefix = plugin.getConfigHelper().getString(ConfigConstants.ChatGuard.CustomPrefix.FORMAT) + ChatColor.RESET + " "; } else chatGuardPrefix = LangConstants.PLUGIN_PREFIX; - if (plugin.getConfigHelper().getBoolean(ConfigConstants.ChatGuard.NOTIFY_USER)) player.sendMessage(chatGuardPrefix + - plugin.getConfigHelperLanguage() - .getString(blockOrCensor ? LangConstants.ChatGuard.MESSAGE_BLOCKED : LangConstants.ChatGuard.MESSAGE_CENSORED) + - " " + ChatColor.RED + classification.reason()); + if (plugin.getConfigHelper().getBoolean(ConfigConstants.ChatGuard.NOTIFY_USER) && !messageHandling.equals("SILENT")) { + String langKey = messageHandling.equals("BLOCK") ? LangConstants.ChatGuard.MESSAGE_BLOCKED : LangConstants.ChatGuard.MESSAGE_CENSORED; + player.sendMessage(chatGuardPrefix + plugin.getConfigHelperLanguage().getString(langKey) + " " + ChatColor.RED + classification.reason()); + } - plugin.getLoggingHelper() - .info("Message by " + player.getName() + (blockOrCensor ? " has been blocked: " : " has been censored: ") + userMessage); + String action = switch (messageHandling) { + case "BLOCK" -> "blocked"; + case "SILENT" -> "silently moderated"; + default -> "censored"; + }; + plugin.getLoggingHelper().info("Message by " + player.getName() + " has been " + action + ": " + userMessage); if (!classification.isOffensiveLanguage()) return; diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index df4cd3d..a9da894 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -150,7 +150,8 @@ chatguard: # Message handling configuration # Default: CENSOR - # Options: Censor, BLOCK + # Options: CENSOR, BLOCK, SILENT + # SILENT: The message is only visible to the sender, creating the illusion of successful delivery message-handling: CENSOR # Notify user when message is blocked/censored diff --git a/src/main/resources/locale/locale_custom.yml b/src/main/resources/locale/locale_custom.yml index 4df5e06..690dfaf 100644 --- a/src/main/resources/locale/locale_custom.yml +++ b/src/main/resources/locale/locale_custom.yml @@ -59,6 +59,7 @@ chatguard: player: message-blocked: "" message-censored: "" + message-silenced: "" kick: "" ban-temporary: "" ban-permanent: "" \ No newline at end of file diff --git a/src/main/resources/locale/locale_de.yml b/src/main/resources/locale/locale_de.yml index c8484d8..7eac9c3 100644 --- a/src/main/resources/locale/locale_de.yml +++ b/src/main/resources/locale/locale_de.yml @@ -57,6 +57,7 @@ chatguard: player: message-blocked: "Deine Nachricht wurde blockiert. Grund:" message-censored: "Deine Nachricht wurde zensiert. Grund:" + message-silenced: "Deine Nachricht wurde still moderiert und ist nur für dich sichtbar. Grund:" kick: "Du wurdest vom Server gekickt. Grund:" ban-temporary: "Du wurdest vorübergehend vom Server gebannt. Grund:" ban-permanent: "Du wurdest dauerhaft vom Server gebannt. Grund:" \ No newline at end of file diff --git a/src/main/resources/locale/locale_en.yml b/src/main/resources/locale/locale_en.yml index 02bfe95..c777f81 100644 --- a/src/main/resources/locale/locale_en.yml +++ b/src/main/resources/locale/locale_en.yml @@ -57,6 +57,7 @@ chatguard: player: message-blocked: "Your message was blocked. Reason:" message-censored: "Your message was censored. Reason:" + message-silenced: "Your message was silently moderated and only visible to you. Reason:" kick: "You have been kicked from the server. Reason:" ban-temporary: "You have been temporarily banned from the server. Reason:" ban-permanent: "You have been permanently banned from the server. Reason:" \ No newline at end of file diff --git a/src/main/resources/locale/locale_es.yml b/src/main/resources/locale/locale_es.yml index fa2fce8..d0a1be8 100644 --- a/src/main/resources/locale/locale_es.yml +++ b/src/main/resources/locale/locale_es.yml @@ -57,6 +57,7 @@ chatguard: player: message-blocked: "Tu mensaje fue bloqueado. Razón:" message-censored: "Tu mensaje fue censurado. Razón:" + message-silenced: "Tu mensaje fue moderado silenciosamente y solo es visible para ti. Razón:" kick: "Has sido expulsado del servidor. Razón:" ban-temporary: "Has sido baneado temporalmente del servidor. Razón:" ban-permanent: "Has sido baneado permanentemente del servidor. Razón:" \ No newline at end of file diff --git a/src/main/resources/locale/locale_fr.yml b/src/main/resources/locale/locale_fr.yml index fceb2d7..901e461 100644 --- a/src/main/resources/locale/locale_fr.yml +++ b/src/main/resources/locale/locale_fr.yml @@ -57,6 +57,7 @@ chatguard: player: message-blocked: "Votre message a été bloqué. Raison :" message-censored: "Votre message a été censuré. Raison :" + message-silenced: "Votre message a été modéré silencieusement et n'est visible que par vous. Raison :" kick: "Vous avez été expulsé du serveur. Raison :" ban-temporary: "Vous avez été banni temporairement du serveur. Raison :" ban-permanent: "Vous avez été banni définitivement du serveur. Raison :" \ No newline at end of file diff --git a/src/main/resources/locale/locale_nl.yml b/src/main/resources/locale/locale_nl.yml index 9c62ba9..e008b5e 100644 --- a/src/main/resources/locale/locale_nl.yml +++ b/src/main/resources/locale/locale_nl.yml @@ -57,6 +57,7 @@ chatguard: player: message-blocked: "Je bericht is geblokkeerd. Reden:" message-censored: "Je bericht is gecensureerd. Reden:" + message-silenced: "Je bericht is stil gemodereerd en alleen zichtbaar voor jou. Reden:" kick: "Je bent van de server gekickt. Reden:" ban-temporary: "Je bent tijdelijk van de server verbannen. Reden:" ban-permanent: "Je bent permanent van de server verbannen. Reden:" \ No newline at end of file diff --git a/src/main/resources/locale/locale_zh-cn.yml b/src/main/resources/locale/locale_zh-cn.yml index 8b52abe..95afb0f 100644 --- a/src/main/resources/locale/locale_zh-cn.yml +++ b/src/main/resources/locale/locale_zh-cn.yml @@ -57,6 +57,7 @@ chatguard: player: message-blocked: "您的消息已被屏蔽。原因:" message-censored: "您的消息已被过滤。原因:" + message-silenced: "您的消息已被静默审核,仅您自己可见。原因:" kick: "您已被踢出服务器。原因:" ban-temporary: "您已被暂时封禁。原因:" ban-permanent: "您已被永久封禁。原因:" \ No newline at end of file diff --git a/src/main/resources/locale/locale_zh-tw.yml b/src/main/resources/locale/locale_zh-tw.yml index 0343858..770cc79 100644 --- a/src/main/resources/locale/locale_zh-tw.yml +++ b/src/main/resources/locale/locale_zh-tw.yml @@ -57,6 +57,7 @@ chatguard: player: message-blocked: "您的訊息已被封鎖。原因:" message-censored: "您的訊息已被過濾。原因:" + message-silenced: "您的訊息已被靜默審核,僅您自己可見。原因:" kick: "您已被踢出伺服器。原因:" ban-temporary: "您已被暫時封鎖。原因:" ban-permanent: "您已被永久封鎖。原因:" \ No newline at end of file