From f14c4e3fc0cdc209a6c407231695c17012954c46 Mon Sep 17 00:00:00 2001 From: itqop Date: Thu, 31 Oct 2024 17:26:18 +0300 Subject: [PATCH] chore(release): v0.1.9 Added hot-swap profanity filtering modes and custom private messages to replace /w, /tell, /msg commands. --- CHANGELOG.md | 17 ++++ CHANGELOG.ru.md | 18 ++++ README.md | 1 + build.gradle | 35 +++++++ gradle.properties | 2 +- .../itqop/chatit/commands/ChatITCommand.java | 95 +++++++++++++++++++ .../chatit/mixins/MixinMessageCommand.java | 23 +++++ .../java/org/itqop/chatit/utils/Config.java | 46 ++++++++- .../itqop/chatit/utils/ProfanityChecker.java | 39 ++++++-- .../org/itqop/chatit/utils/ProfanityMode.java | 16 ++++ src/main/resources/META-INF/mods.toml | 4 + src/main/resources/chatit.mixins.json | 11 +++ 12 files changed, 295 insertions(+), 12 deletions(-) create mode 100644 src/main/java/org/itqop/chatit/mixins/MixinMessageCommand.java create mode 100644 src/main/java/org/itqop/chatit/utils/ProfanityMode.java create mode 100644 src/main/resources/chatit.mixins.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 96894ca..ad8a8ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/). +## [0.1.9] - 2024-10-31 + +### Added + +- **Config.java**: + - Added hot-swap profanity filtering modes (`off`, `regex`, `api`). + - Implemented the ability to change profanity filtering mode during server runtime using the command `/chatit mode (off|regex|api)`. + +- **ChatITCommand.java**: + - Added custom private messages to replace `/w`, `/tell`, `/msg` commands. + - Updated the logic for sending and formatting private messages. + +### Changed + +- **ProfanityChecker.java**: + - Updated profanity checking logic to accommodate new filtering modes. + ## [0.1.8] - 2024-10-30 ### Changed diff --git a/CHANGELOG.ru.md b/CHANGELOG.ru.md index 31cba49..22da712 100644 --- a/CHANGELOG.ru.md +++ b/CHANGELOG.ru.md @@ -4,6 +4,24 @@ Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.0.0/), и этот проект придерживается [Семантического Версионирования](https://semver.org/lang/ru/). +## [0.1.9] - 2024-10-31 + +### Добавлено + +- **Config.java**: + - Добавлен hot-swap режимов фильтрации мата (`off`, `regex`, `api`). + - Реализована возможность изменения режима фильтрации мата во время работы сервера через команду `/chatit mode (off|regex|api)`. + +- **ChatITCommand.java**: + - Добавлены кастомные личные сообщения на замену команд `/w`, `/tell`, `/msg`. + - Обновлена логика отправки и форматирования приватных сообщений. + +### Изменено + +- **ProfanityChecker.java**: + - Обновлена логика проверки мата с учётом новых режимов фильтрации. + + ## [0.1.8] - 2024-10-30 ### Изменено diff --git a/README.md b/README.md index e69de29..039513b 100644 --- a/README.md +++ b/README.md @@ -0,0 +1 @@ +Readme for usage - https://github.com/itqop/ChatIT \ No newline at end of file diff --git a/build.gradle b/build.gradle index 5c10331..bac5be3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,12 @@ buildscript { repositories { // Эти репозитории предназначены только для Gradle-плагинов, другие репозитории размещайте в блоке ниже + maven { url = 'https://repo.spongepowered.org/repository/maven-public/' } mavenCentral() } dependencies { // После удаления Mixin здесь больше не требуется зависимостей + classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT' } } @@ -14,6 +16,8 @@ plugins { id 'net.minecraftforge.gradle' version '[6.0.16,6.2)' } +apply plugin: 'org.spongepowered.mixin' + group = mod_group_id version = mod_version @@ -117,6 +121,11 @@ minecraft { } } +mixin { + add sourceSets.main, "${mod_id}.refmap.json" + + config "${mod_id}.mixins.json" +} // Включите ресурсы, сгенерированные генераторами данных. sourceSets.main.resources { srcDir 'src/generated/resources' } @@ -153,6 +162,8 @@ dependencies { // Для дополнительной информации: // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html // http://www.gradle.org/docs/current/userguide/dependency_management.html + + annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' } tasks.named('processResources', ProcessResources).configure { @@ -192,3 +203,27 @@ tasks.named('jar', Jar).configure { tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' // Используйте кодировку UTF-8 для компиляции Java } + +// Определите путь к вашей целевой папке +def targetModsDir = "D:/server_sandbox/ForgeCreate/mods" + +// Задача для копирования JAR-файла +tasks.register('copyJarToMods', Copy) { + // Указывает, откуда копировать файл (из build/libs) + from jar.archiveFile + + // Указывает, куда копировать файл + into targetModsDir + + // Фильтр для выбора нужных файлов, если необходимо + //include "${project.name}-${project.version}.jar" + + // Можно добавить переименование файла, если требуется + // rename "${project.name}-${project.version}.jar", "${project.name}.jar" +} + +// Убедитесь, что задача `copyJarToMods` выполняется после сборки JAR +jar.finalizedBy(copyJarToMods) + +// (Опционально) Добавьте зависимость на задачу `copyJarToMods` к задаче `build` +build.dependsOn(copyJarToMods) diff --git a/gradle.properties b/gradle.properties index aeec50c..e8751db 100644 --- a/gradle.properties +++ b/gradle.properties @@ -38,7 +38,7 @@ mod_name=ChatIT # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=All Rights Reserved # The mod version. See https://semver.org/ -mod_version=0.1.8-BETA +mod_version=0.1.9-BETA # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/itqop/chatit/commands/ChatITCommand.java b/src/main/java/org/itqop/chatit/commands/ChatITCommand.java index a1bb821..5bfd3eb 100644 --- a/src/main/java/org/itqop/chatit/commands/ChatITCommand.java +++ b/src/main/java/org/itqop/chatit/commands/ChatITCommand.java @@ -1,14 +1,21 @@ package org.itqop.chatit.commands; import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import net.minecraft.ChatFormatting; import net.minecraft.commands.Commands; import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.commands.arguments.MessageArgument; import net.minecraft.server.level.ServerPlayer; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; import net.minecraftforge.event.RegisterCommandsEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import org.itqop.chatit.utils.PlayerConfigManager; +import org.itqop.chatit.utils.Config; +import org.itqop.chatit.utils.ProfanityMode; @Mod.EventBusSubscriber public class ChatITCommand { @@ -29,6 +36,94 @@ public class ChatITCommand { return 1; }) ) + // Добавление подкоманды mode + .then(Commands.literal("mode") + .requires(source -> source.hasPermission(2)) // Требует уровень разрешения 2 (оператор) + .then(Commands.argument("mode", StringArgumentType.word()) + .executes(context -> { + String modeInput = StringArgumentType.getString(context, "mode").toLowerCase(); + ProfanityMode newMode; + try { + newMode = ProfanityMode.fromString(modeInput); + } catch (IllegalArgumentException e) { + context.getSource().sendFailure(Component.literal("Неверный режим. Используйте: off, regex, api.") + .withStyle(ChatFormatting.RED)); + return 0; + } + + // Установка нового режима в конфигурации + Config.setProfanityMode(newMode); + + // Отправка подтверждающего сообщения + context.getSource().sendSuccess( + () -> Component.literal("Режим проверки мата установлен на: " + newMode.name().toLowerCase() + ".") + .withStyle(ChatFormatting.GREEN), + true + ); + + return 1; + }) + ) + ) + ); + + } + + public static void registerPrivateMessageCommand(CommandDispatcher dispatcher, String commandName) { + dispatcher.register(Commands.literal(commandName) + .then(Commands.argument("target", EntityArgument.player()) + .then(Commands.argument("message", MessageArgument.message()) + .executes(context -> sendPrivateMessage(context.getSource(), + EntityArgument.getPlayer(context, "target"), + MessageArgument.getMessage(context, "message"))) + ) + ) ); } + + /** + * Метод для отправки приватного сообщения от одного игрока к другому. + * + * @param source Источник команды (должен быть игроком). + * @param target Целевой игрок. + * @param message Сообщение. + * @return Статус выполнения команды. + */ + private static int sendPrivateMessage(CommandSourceStack source, ServerPlayer target, Component message) { + // Проверка, что источник команды является игроком + if (!(source.getEntity() instanceof ServerPlayer sender)) { + source.sendFailure(Component.literal("Только игроки могут отправлять личные сообщения.")); + return 0; + } + + // Проверка, что отправитель не отправляет сообщение самому себе + if (sender.getUUID().equals(target.getUUID())) { + sender.sendSystemMessage(Component.literal("Вы не можете отправлять сообщения самому себе.")); + return 0; + } + + MutableComponent pmText = Component.literal("ЛС"); + MutableComponent fromText = Component.literal(" от "); + MutableComponent toText = Component.literal(" для "); + MutableComponent closeBracket = Component.literal(": "); + + MutableComponent messageFormat = message.copy().withStyle(ChatFormatting.YELLOW); + + MutableComponent messageTo = pmText.copy() + .append(toText) + .append(target.getDisplayName().copy().withStyle(ChatFormatting.GREEN)) + .append(closeBracket) + .append(messageFormat); + + MutableComponent messageFrom = pmText.copy() + .append(fromText) + .append(sender.getDisplayName().copy().withStyle(ChatFormatting.GREEN)) + .append(closeBracket) + .append(messageFormat); + + target.sendSystemMessage(messageFrom); + sender.sendSystemMessage(messageTo); + + return 1; + } } diff --git a/src/main/java/org/itqop/chatit/mixins/MixinMessageCommand.java b/src/main/java/org/itqop/chatit/mixins/MixinMessageCommand.java new file mode 100644 index 0000000..56db8dd --- /dev/null +++ b/src/main/java/org/itqop/chatit/mixins/MixinMessageCommand.java @@ -0,0 +1,23 @@ +package org.itqop.chatit.mixins; + +import com.mojang.brigadier.CommandDispatcher; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.server.commands.MsgCommand; +import org.itqop.chatit.commands.ChatITCommand; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(MsgCommand.class) +public abstract class MixinMessageCommand { + + @Inject(method = "register", at = @At("HEAD"), cancellable = true) + private static void onRegister(CommandDispatcher dispatcher, CallbackInfo ci) { + ChatITCommand.registerPrivateMessageCommand(dispatcher, "tell"); + ChatITCommand.registerPrivateMessageCommand(dispatcher, "w"); + ChatITCommand.registerPrivateMessageCommand(dispatcher, "msg"); + + ci.cancel(); + } +} diff --git a/src/main/java/org/itqop/chatit/utils/Config.java b/src/main/java/org/itqop/chatit/utils/Config.java index c579766..3c0fd9c 100644 --- a/src/main/java/org/itqop/chatit/utils/Config.java +++ b/src/main/java/org/itqop/chatit/utils/Config.java @@ -5,11 +5,14 @@ import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.config.ModConfigEvent; import org.itqop.chatit.ChatIT; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @Mod.EventBusSubscriber(modid = ChatIT.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) public class Config { private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder(); + private static final Logger LOGGER = LoggerFactory.getLogger(Config.class); public static ForgeConfigSpec COMMON_CONFIG; @@ -21,6 +24,8 @@ public class Config { public static ForgeConfigSpec.ConfigValue MESSAGE_ADULT; public static ForgeConfigSpec.ConfigValue MESSAGE_LOCAL; + public static ForgeConfigSpec.ConfigValue PROFANITY_MODE; + static { BUILDER.comment("Настройки ChatIT"); @@ -38,7 +43,7 @@ public class Config { PROFANITY_THRESHOLD = BUILDER .comment("Порог для определения мата (0.0 - 1.0)") - .defineInRange("profanity_threshold", 0.5, 0.0, 1.0); // Дефолтное значение 0.5 + .defineInRange("profanity_threshold", 0.75, 0.0, 1.0); // Дефолтное значение 0.5 PROFANITY_REGEX = BUILDER .comment("Регулярное выражение для проверки мата") @@ -52,9 +57,15 @@ public class Config { .comment("Сообщение предупреждения о том, что никого рядом нет") .define("message_local", "Вас никто не услышал, поставьте ! перед сообщением."); + // Определение нового параметра profanity_mode + PROFANITY_MODE = BUILDER + .comment("Режим проверки мата: off, regex, api") + .define("profanity_mode", "regex"); // Дефолтное значение: api + COMMON_CONFIG = BUILDER.build(); } + // Статические переменные для доступа к настройкам public static String hostApi; public static boolean defaultAdult; public static boolean useRegex; @@ -62,6 +73,7 @@ public class Config { public static String profanityRegex; public static String messageAdult; public static String messageLocal; + public static ProfanityMode profanityMode; @SubscribeEvent public static void onLoad(final ModConfigEvent event) { @@ -72,5 +84,37 @@ public class Config { profanityRegex = PROFANITY_REGEX.get(); messageAdult = MESSAGE_ADULT.get(); messageLocal = MESSAGE_LOCAL.get(); + + // Чтение и установка режима проверки мата + String modeString = PROFANITY_MODE.get().toLowerCase(); + try { + profanityMode = ProfanityMode.fromString(modeString); + } catch (IllegalArgumentException e) { + profanityMode = ProfanityMode.REGEX; // Значение по умолчанию + LOGGER.warn("Неверный режим проверки мата в конфигурации: {}. Используется режим API.", modeString); + } + } + + /** + * Метод для установки нового режима проверки мата. + * + * @param mode Новый режим. + */ + public static void setProfanityMode(ProfanityMode mode) { + profanityMode = mode; + PROFANITY_MODE.set(mode.name().toLowerCase()); + + COMMON_CONFIG.save(); + LOGGER.info("Режим проверки мата установлен на: {} и конфигурация сохранена.", mode.name().toLowerCase()); + } + + + /** + * Метод для получения текущего режима проверки мата. + * + * @return Текущий режим. + */ + public static ProfanityMode getProfanityMode() { + return profanityMode; } } diff --git a/src/main/java/org/itqop/chatit/utils/ProfanityChecker.java b/src/main/java/org/itqop/chatit/utils/ProfanityChecker.java index 12eb8f7..eaf6682 100644 --- a/src/main/java/org/itqop/chatit/utils/ProfanityChecker.java +++ b/src/main/java/org/itqop/chatit/utils/ProfanityChecker.java @@ -23,17 +23,34 @@ public class ProfanityChecker { private static Pattern profanityPattern = null; public static CompletableFuture checkMessageAsync(String message) { + return CompletableFuture.supplyAsync(() -> { + try { + ProfanityMode mode = Config.getProfanityMode(); + + return switch (mode) { + case OFF -> 0.0; // Проверка отключена + case REGEX -> containsProfanity(message) ? 1.0 : 0.0; + case API -> checkViaApi(message).get(); + default -> { + LOGGER.warn("Неизвестный режим проверки мата: " + mode); + yield 0.0; + } + }; + } catch (Exception e) { + LOGGER.error("Ошибка при проверке мата: ", e); + return 0.0; + } + }); + } + + private static CompletableFuture checkViaApi(String message) { return CompletableFuture.supplyAsync(() -> { try { String apiUrl = Config.hostApi; - boolean useRegex = Config.useRegex; if (apiUrl == null || apiUrl.isEmpty()) { - if (useRegex) { - return containsProfanity(message) ? 1.0 : 0.0; - } else { - return 0.0; - } + LOGGER.warn("URL API не задан. Возвращается 0.0"); + return 0.0; } String jsonRequest = GSON.toJson(new MessageRequest(message)); @@ -56,16 +73,18 @@ public class ProfanityChecker { return jsonResponse.get("toxicity_score").getAsDouble(); } catch (Exception e) { - LOGGER.error(e.toString()); - if (Config.useRegex) { - return containsProfanity(message) ? 1.0 : 0.0; - } + LOGGER.error("Ошибка при вызове API: ", e); return 0.0; } }); } private static boolean containsProfanity(String message) { + ProfanityMode mode = Config.getProfanityMode(); + if (mode != ProfanityMode.REGEX) { + return false; + } + if (profanityPattern == null || !profanityPattern.pattern().equals(Config.profanityRegex)) { profanityPattern = Pattern.compile(Config.profanityRegex); } diff --git a/src/main/java/org/itqop/chatit/utils/ProfanityMode.java b/src/main/java/org/itqop/chatit/utils/ProfanityMode.java new file mode 100644 index 0000000..13a1bbb --- /dev/null +++ b/src/main/java/org/itqop/chatit/utils/ProfanityMode.java @@ -0,0 +1,16 @@ +package org.itqop.chatit.utils; + +public enum ProfanityMode { + OFF, + REGEX, + API; + + public static ProfanityMode fromString(String mode) { + return switch (mode.toLowerCase()) { + case "off" -> OFF; + case "regex" -> REGEX; + case "api" -> API; + default -> throw new IllegalArgumentException("Неверный режим проверки мата: " + mode); + }; + } +} diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 5f47983..4a2ea9a 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -61,3 +61,7 @@ mandatory = true versionRange = "${minecraft_version_range}" ordering = "NONE" side = "BOTH" + +[[mixins]] +mod = "chatit" +config = "chatit.mixins.json" diff --git a/src/main/resources/chatit.mixins.json b/src/main/resources/chatit.mixins.json new file mode 100644 index 0000000..a778e9d --- /dev/null +++ b/src/main/resources/chatit.mixins.json @@ -0,0 +1,11 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "org.itqop.chatit.mixins", + "refmap": "chatit.refmap.json", + "mixins": [ + "MixinMessageCommand" + ], + "client": [], + "server": [] +}