Compare commits

..

3 Commits

Author SHA1 Message Date
itqop 779ba9c8b4 Rename class name and fix CHANGELOG dates 2024-10-21 11:31:59 +03:00
itqop 0b4a253dcb Add 0.1.1 version 2024-10-21 11:25:52 +03:00
itqop f7b0004423 Add CHANGELOG 2024-10-21 11:25:14 +03:00
7 changed files with 96 additions and 46 deletions

72
CHANGELOG Normal file
View File

@ -0,0 +1,72 @@
# Журнал изменений (CHANGELOG)
Все заметные изменения в этом проекте будут задокументированы в этом файле.
Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.0.0/), и этот проект придерживается [Семантического Версионирования](https://semver.org/lang/ru/).
## [0.1.2] - 2024-10-21
### Изменено
- **Название мода**:
- Переименован мод с `Chatit` на `ChatIT` для согласованности и улучшения брендинга.
## [0.1.1] - 2024-10-21
### Изменено
- **Исправление метода получения уровня игрока**:
- Использование `receiver.level()` и `sender.level()` теперь обёрнуто в блок `try-with-resources` для корректной работы с ресурсами и устранения ошибок.
- **Форматирование префиксов**:
- Убрано жирное форматирование (`ChatFormatting.BOLD`) из префиксов `[G]`, `[L]` и `[ERROR]`. Теперь буквы `G`, `L` и `ERROR` отображаются без жирного начертания, сохраняя цветовое выделение.
- **Чистый код**:
- Удалены все комментарии из кода для повышения читаемости и поддерживаемости.
## [0.1.0] - 2024-10-21
### Добавлено
- **Локальный и глобальный чат**:
- Сообщения, начинающиеся с `!`, отправляются глобально всем игрокам.
- Сообщения без `!` отправляются локально игрокам в радиусе 50 блоков.
- **Префиксы сообщений**:
- `[G]` для глобальных сообщений, где `G` лаймового цвета.
- `[L]` для локальных сообщений, где `L` жёлтого цвета.
- `[ERROR]` для сообщений об ошибках, где `ERROR` красного цвета.
- **Проверка на маты**:
- Интеграция с внешним API для проверки сообщений на наличие мата.
- Асинхронная проверка сообщений, чтобы избежать блокировки основного потока сервера.
- Добавлена настройка `regex` для использования регулярного выражения при недоступности API.
- **Параметр `adult` для игроков**:
- Команда `/chatit adult` для переключения параметра `adult` у игрока.
- Настройки игроков сохраняются в файл `config/chatit_player_settings.json`.
- Значение `adult` по умолчанию для новых игроков задаётся в конфигурации (`default_adult`).
- **Фильтрация сообщений на основе параметра `adult`**:
- Если у отправителя `adult` выключен и сообщение содержит маты, оно блокируется и отправляется только ему с префиксом `[ERROR]`.
- Игроки с `adult` выключенным не видят сообщения с матами от других игроков.
- Игроки с `adult` включенным могут отправлять и получать сообщения с матами.
- **Конфигурационный файл**:
- Создаётся файл `config/chatit.toml` с настройками:
- `host_api`: URL API для проверки мата.
- `default_adult`: Значение `adult` по умолчанию для новых игроков (true/false).
- `regex`: Использовать регулярное выражение при недоступности API (true/false).
- **Асинхронная обработка**:
- Взаимодействие с API происходит асинхронно с использованием `CompletableFuture`.
- Предотвращает блокировку основного потока сервера при проверке сообщений.
- **Обработка ошибок**:
- При недоступности API и `regex=true` используется регулярное выражение для проверки мата.
- При возникновении ошибок отправляется сообщение об ошибке только отправителю.
- **Форматирование сообщений**:
- Префиксы `[G]`, `[L]`, `[ERROR]` отображаются с корректным форматированием.
- Буквы `G`, `L` и слово `ERROR` окрашены в заданные цвета.
### Изменено
- **Оптимизация кода**:
- Обработка сообщений перенесена в асинхронный поток для улучшения производительности.
- Улучшена структура кода для повышения читаемости и поддерживаемости.
- **Исправления**:
- Устранены предупреждения и ошибки, связанные с устаревшими методами.
- Исправлены проблемы с многопоточностью и доступом к игровым объектам.

View File

@ -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. # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
mod_license=All Rights Reserved mod_license=All Rights Reserved
# The mod version. See https://semver.org/ # The mod version. See https://semver.org/
mod_version=0.1-BETA mod_version=0.1.2-BETA
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # 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. # This should match the base package used for the mod sources.
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html # See https://maven.apache.org/guides/mini/guide-naming-conventions.html

View File

@ -13,25 +13,22 @@ import org.itqop.chatit.utils.Config;
import org.itqop.chatit.utils.PlayerConfigManager; import org.itqop.chatit.utils.PlayerConfigManager;
import org.slf4j.Logger; import org.slf4j.Logger;
@Mod(Chatit.MODID) @Mod(ChatIT.MODID)
public class Chatit { public class ChatIT {
public static final String MODID = "chatit"; public static final String MODID = "chatit";
private static final Logger LOGGER = LogUtils.getLogger(); private static final Logger LOGGER = LogUtils.getLogger();
public Chatit() { public ChatIT() {
// Регистрация обработчиков событий MinecraftForge.EVENT_BUS.register(this);
MinecraftForge.EVENT_BUS.register(this); // Для событий сервера MinecraftForge.EVENT_BUS.register(ChatEventHandler.class);
MinecraftForge.EVENT_BUS.register(ChatEventHandler.class); // Обработчик чата MinecraftForge.EVENT_BUS.register(ChatitCommand.class);
MinecraftForge.EVENT_BUS.register(ChatitCommand.class); // Команда
// Регистрация конфигурации
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, Config.COMMON_CONFIG); ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, Config.COMMON_CONFIG);
} }
@SubscribeEvent @SubscribeEvent
public void onServerStarting(ServerStartingEvent event) { public void onServerStarting(ServerStartingEvent event) {
// Загрузка конфигурации игроков при старте сервера
PlayerConfigManager.loadConfig(); PlayerConfigManager.loadConfig();
LOGGER.info("ChatIT started and configuration loaded."); LOGGER.info("ChatIT started and configuration loaded.");
} }

View File

@ -19,7 +19,7 @@ public class ChatitCommand {
dispatcher.register(Commands.literal("chatit") dispatcher.register(Commands.literal("chatit")
.then(Commands.literal("adult") .then(Commands.literal("adult")
.requires(source -> source.hasPermission(2)) // Уровень разрешения 2 (операторы) .requires(source -> source.hasPermission(2))
.executes(context -> { .executes(context -> {
ServerPlayer player = context.getSource().getPlayerOrException(); ServerPlayer player = context.getSource().getPlayerOrException();
PlayerConfigManager.toggleAdultContent(player); PlayerConfigManager.toggleAdultContent(player);

View File

@ -22,44 +22,38 @@ public class ChatEventHandler {
MinecraftServer server = sender.getServer(); MinecraftServer server = sender.getServer();
String originalMessage = event.getMessage().getString(); String originalMessage = event.getMessage().getString();
// Отменяем стандартную отправку сообщения
event.setCanceled(true); event.setCanceled(true);
// Убеждаемся, что отправитель есть в настройках
PlayerConfigManager.ensurePlayerExists(sender); PlayerConfigManager.ensurePlayerExists(sender);
// Проверка на наличие '!' для глобального сообщения
boolean isGlobal = originalMessage.startsWith("!"); boolean isGlobal = originalMessage.startsWith("!");
String message = isGlobal ? originalMessage.substring(1) : originalMessage; String message = isGlobal ? originalMessage.substring(1) : originalMessage;
// Создаем заготовку сообщения для отправки после проверки
MutableComponent chatComponent = createChatMessage(sender, message, isGlobal); MutableComponent chatComponent = createChatMessage(sender, message, isGlobal);
// Запускаем асинхронную проверку сообщения
CompletableFuture<Double> future = ProfanityChecker.checkMessageAsync(message); CompletableFuture<Double> future = ProfanityChecker.checkMessageAsync(message);
future.thenAccept(profanityScore -> { future.thenAccept(profanityScore -> {
if (server != null) { if (server != null) {
server.execute(() -> { server.execute(() -> {
// Обработка результата проверки
if (profanityScore > 0.5 && !PlayerConfigManager.hasAdultContentEnabled(sender)) { if (profanityScore > 0.5 && !PlayerConfigManager.hasAdultContentEnabled(sender)) {
// Отправляем сообщение только отправителю с префиксом [ERROR]
MutableComponent errorComponent = createErrorMessage(sender, message); MutableComponent errorComponent = createErrorMessage(sender, message);
sender.sendSystemMessage(errorComponent); sender.sendSystemMessage(errorComponent);
} else { } else {
for (ServerPlayer receiver : server.getPlayerList().getPlayers()) { for (ServerPlayer receiver : server.getPlayerList().getPlayers()) {
// Убеждаемся, что получатель есть в настройках
PlayerConfigManager.ensurePlayerExists(receiver); PlayerConfigManager.ensurePlayerExists(receiver);
// Если сообщение содержит маты и у получателя параметр adult OFF
if (profanityScore > 0.5 && !PlayerConfigManager.hasAdultContentEnabled(receiver)) { if (profanityScore > 0.5 && !PlayerConfigManager.hasAdultContentEnabled(receiver)) {
continue; // Пропускаем отправку этому игроку continue;
} }
// Проверяем условия для отправки сообщения try (var senderLevel = sender.level(); var receiverLevel = receiver.level()) {
if (isGlobal || (receiver.level() == sender.level() && receiver.position().distanceTo(sender.position()) <= 50)) { if (isGlobal || (receiverLevel == senderLevel && receiver.position().distanceTo(sender.position()) <= 50)) {
receiver.sendSystemMessage(chatComponent); receiver.sendSystemMessage(chatComponent);
} }
} catch (Exception e) {
e.printStackTrace();
}
} }
} }
}); });
@ -68,7 +62,6 @@ public class ChatEventHandler {
ex.printStackTrace(); ex.printStackTrace();
if (server != null) { if (server != null) {
server.execute(() -> { server.execute(() -> {
// В случае ошибки отправляем сообщение только отправителю с префиксом [ERROR]
MutableComponent errorComponent = createErrorMessage(sender, message); MutableComponent errorComponent = createErrorMessage(sender, message);
sender.sendSystemMessage(errorComponent); sender.sendSystemMessage(errorComponent);
}); });
@ -80,7 +73,7 @@ public class ChatEventHandler {
private static MutableComponent createErrorMessage(ServerPlayer player, String message) { private static MutableComponent createErrorMessage(ServerPlayer player, String message) {
MutableComponent openBracket = Component.literal("["); MutableComponent openBracket = Component.literal("[");
MutableComponent errorText = Component.literal("ERROR") MutableComponent errorText = Component.literal("ERROR")
.withStyle(ChatFormatting.RED, ChatFormatting.BOLD); .withStyle(ChatFormatting.RED);
MutableComponent closeBracket = Component.literal("] "); MutableComponent closeBracket = Component.literal("] ");
MutableComponent prefixComponent = openBracket.append(errorText).append(closeBracket); MutableComponent prefixComponent = openBracket.append(errorText).append(closeBracket);
@ -98,10 +91,10 @@ public class ChatEventHandler {
if (isGlobal) { if (isGlobal) {
letterComponent = Component.literal("G") letterComponent = Component.literal("G")
.withStyle(ChatFormatting.BOLD, ChatFormatting.GREEN); .withStyle(ChatFormatting.GREEN);
} else { } else {
letterComponent = Component.literal("L") letterComponent = Component.literal("L")
.withStyle(ChatFormatting.BOLD, ChatFormatting.YELLOW); .withStyle(ChatFormatting.YELLOW);
} }
MutableComponent prefixComponent = openBracket.append(letterComponent).append(closeBracket); MutableComponent prefixComponent = openBracket.append(letterComponent).append(closeBracket);

View File

@ -4,9 +4,9 @@ import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.config.ModConfigEvent; import net.minecraftforge.fml.event.config.ModConfigEvent;
import org.itqop.chatit.Chatit; import org.itqop.chatit.ChatIT;
@Mod.EventBusSubscriber(modid = Chatit.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) @Mod.EventBusSubscriber(modid = ChatIT.MODID, bus = Mod.EventBusSubscriber.Bus.MOD)
public class Config { public class Config {
private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder(); private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder();

View File

@ -27,21 +27,17 @@ public class ProfanityChecker {
boolean useRegex = Config.useRegex; boolean useRegex = Config.useRegex;
if (apiUrl == null || apiUrl.isEmpty()) { if (apiUrl == null || apiUrl.isEmpty()) {
// Если URL API не задан
if (useRegex) { if (useRegex) {
// Используем регулярное выражение для проверки мата
if (containsProfanity(message)) { if (containsProfanity(message)) {
return 1.0; // Мат найден return 1.0;
} else { } else {
return 0.0; // Мат не найден return 0.0;
} }
} else { } else {
// Если regex=false, возвращаем 0.0 (нет мата)
return 0.0; return 0.0;
} }
} }
// Создаем JSON-запрос
String jsonRequest = GSON.toJson(new MessageRequest(message)); String jsonRequest = GSON.toJson(new MessageRequest(message));
HttpRequest request = HttpRequest.newBuilder() HttpRequest request = HttpRequest.newBuilder()
@ -50,23 +46,18 @@ public class ProfanityChecker {
.POST(HttpRequest.BodyPublishers.ofString(jsonRequest, StandardCharsets.UTF_8)) .POST(HttpRequest.BodyPublishers.ofString(jsonRequest, StandardCharsets.UTF_8))
.build(); .build();
// Отправляем запрос и получаем ответ
HttpResponse<String> response = CLIENT.send(request, HttpResponse.BodyHandlers.ofString()); HttpResponse<String> response = CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
// Парсим ответ
String responseBody = response.body(); String responseBody = response.body();
double result = Double.parseDouble(responseBody);
return result; return Double.parseDouble(responseBody);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
if (Config.useRegex) { if (Config.useRegex) {
// Если произошла ошибка и regex=true, используем регулярное выражение
if (containsProfanity(message)) { if (containsProfanity(message)) {
return 1.0; // Мат найден return 1.0;
} }
} }
// В случае ошибки и regex=false считаем, что мата нет
return 0.0; return 0.0;
} }
}); });
@ -76,12 +67,9 @@ public class ProfanityChecker {
return PROFANITY_PATTERN.matcher(message).find(); return PROFANITY_PATTERN.matcher(message).find();
} }
// Класс для сериализации JSON-запроса
private static class MessageRequest { private static class MessageRequest {
private final String text;
public MessageRequest(String text) { public MessageRequest(String text) {
this.text = text;
} }
} }
} }