chore(release): v0.2
Added the `/r` command for quick replies, implemented logging for private and global messages, and enabled clickable nicknames and links in chat.
This commit is contained in:
parent
f14c4e3fc0
commit
8fc7b9a5f9
19
CHANGELOG.md
19
CHANGELOG.md
|
@ -4,6 +4,25 @@ 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/).
|
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.2] - 2024-11-10
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **ChatITCommand.java**:
|
||||||
|
- **`/r` Command**:
|
||||||
|
- Introduced the `/r` command for quick replies to the last received private message.
|
||||||
|
- Allows players to send responses without specifying the recipient's name.
|
||||||
|
|
||||||
|
- **Utils.java**:
|
||||||
|
- **Message Logging**:
|
||||||
|
- Implemented logging for private and global messages into separate files: `logs/private_messages.log` and `logs/global_messages.log`.
|
||||||
|
- Each message is logged with timestamp, sender's IP address, player names, and message content.
|
||||||
|
|
||||||
|
- **Clickable Nicknames and Links in Chat**:
|
||||||
|
- Added clickable player nicknames in chat. Clicking on a player's nickname suggests sending a private message to them.
|
||||||
|
- Enabled clickable URLs in chat messages. Valid URLs are automatically converted into clickable links that open in the player's browser upon clicking.
|
||||||
|
- Implemented URL validation before converting them into clickable components.
|
||||||
|
|
||||||
## [0.1.9] - 2024-10-31
|
## [0.1.9] - 2024-10-31
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -4,6 +4,26 @@
|
||||||
|
|
||||||
Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.0.0/), и этот проект придерживается [Семантического Версионирования](https://semver.org/lang/ru/).
|
Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.0.0/), и этот проект придерживается [Семантического Версионирования](https://semver.org/lang/ru/).
|
||||||
|
|
||||||
|
## [0.2] - 2024-11-10
|
||||||
|
|
||||||
|
### Добавлено
|
||||||
|
|
||||||
|
- **ChatITCommand.java**:
|
||||||
|
- **Команда `/r`**:
|
||||||
|
- Добавлена команда `/r` для быстрого ответа на последнее полученное приватное сообщение.
|
||||||
|
- Позволяет игрокам быстро отправлять ответы без необходимости указывать имя получателя.
|
||||||
|
|
||||||
|
- **Utils.java**:
|
||||||
|
- **Логирование сообщений**:
|
||||||
|
- Реализовано логирование приватных и глобальных сообщений в отдельные файлы `logs/private_messages.log` и `logs/global_messages.log`.
|
||||||
|
- Каждое сообщение логируется с указанием времени, IP-адреса отправителя, имен игроков и содержания сообщения.
|
||||||
|
|
||||||
|
- **Кликабельность ников и ссылок в чате**:
|
||||||
|
- Добавлена возможность кликабельности ников игроков в чате. При клике на ник игрока предлагается отправить приватное сообщение.
|
||||||
|
- Внедрена кликабельность ссылок в сообщениях чата. Валидные URL автоматически преобразуются в кликабельные ссылки, которые открываются в браузере игрока при клике.
|
||||||
|
- Реализована проверка валидности ссылок перед их преобразованием в кликабельные компоненты.
|
||||||
|
|
||||||
|
|
||||||
## [0.1.9] - 2024-10-31
|
## [0.1.9] - 2024-10-31
|
||||||
|
|
||||||
### Добавлено
|
### Добавлено
|
||||||
|
|
|
@ -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.9-BETA
|
mod_version=0.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
|
||||||
|
|
|
@ -10,16 +10,27 @@ import net.minecraft.commands.arguments.MessageArgument;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.network.chat.MutableComponent;
|
import net.minecraft.network.chat.MutableComponent;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraftforge.event.RegisterCommandsEvent;
|
import net.minecraftforge.event.RegisterCommandsEvent;
|
||||||
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.event.entity.player.PlayerEvent.PlayerLoggedOutEvent;
|
||||||
|
|
||||||
import org.itqop.chatit.utils.PlayerConfigManager;
|
import org.itqop.chatit.utils.PlayerConfigManager;
|
||||||
import org.itqop.chatit.utils.Config;
|
import org.itqop.chatit.utils.Config;
|
||||||
import org.itqop.chatit.utils.ProfanityMode;
|
import org.itqop.chatit.utils.ProfanityMode;
|
||||||
|
import static org.itqop.chatit.utils.Utils.logPrivateMessage;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
@Mod.EventBusSubscriber
|
@Mod.EventBusSubscriber
|
||||||
public class ChatITCommand {
|
public class ChatITCommand {
|
||||||
|
|
||||||
|
private static final Map<UUID, UUID> lastSenders = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onRegisterCommands(RegisterCommandsEvent event) {
|
public static void onRegisterCommands(RegisterCommandsEvent event) {
|
||||||
CommandDispatcher<CommandSourceStack> dispatcher = event.getDispatcher();
|
CommandDispatcher<CommandSourceStack> dispatcher = event.getDispatcher();
|
||||||
|
@ -36,7 +47,6 @@ public class ChatITCommand {
|
||||||
return 1;
|
return 1;
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
// Добавление подкоманды mode
|
|
||||||
.then(Commands.literal("mode")
|
.then(Commands.literal("mode")
|
||||||
.requires(source -> source.hasPermission(2)) // Требует уровень разрешения 2 (оператор)
|
.requires(source -> source.hasPermission(2)) // Требует уровень разрешения 2 (оператор)
|
||||||
.then(Commands.argument("mode", StringArgumentType.word())
|
.then(Commands.argument("mode", StringArgumentType.word())
|
||||||
|
@ -67,6 +77,31 @@ public class ChatITCommand {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Регистрация команды /r
|
||||||
|
dispatcher.register(Commands.literal("r")
|
||||||
|
.then(Commands.argument("message", MessageArgument.message())
|
||||||
|
.executes(context -> {
|
||||||
|
ServerPlayer sender = context.getSource().getPlayerOrException();
|
||||||
|
UUID lastSenderUUID = lastSenders.get(sender.getUUID());
|
||||||
|
if (lastSenderUUID == null) {
|
||||||
|
context.getSource().sendFailure(Component.literal("Нет игрока для ответа.")
|
||||||
|
.withStyle(ChatFormatting.RED));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerPlayer target = context.getSource().getServer().getPlayerList().getPlayer(lastSenderUUID);
|
||||||
|
if (target == null) {
|
||||||
|
context.getSource().sendFailure(Component.literal("Последний отправитель недоступен.")
|
||||||
|
.withStyle(ChatFormatting.RED));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Component message = MessageArgument.getMessage(context, "message");
|
||||||
|
|
||||||
|
return sendPrivateMessage(context.getSource(), target, message);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void registerPrivateMessageCommand(CommandDispatcher<CommandSourceStack> dispatcher, String commandName) {
|
public static void registerPrivateMessageCommand(CommandDispatcher<CommandSourceStack> dispatcher, String commandName) {
|
||||||
|
@ -90,15 +125,15 @@ public class ChatITCommand {
|
||||||
* @return Статус выполнения команды.
|
* @return Статус выполнения команды.
|
||||||
*/
|
*/
|
||||||
private static int sendPrivateMessage(CommandSourceStack source, ServerPlayer target, Component message) {
|
private static int sendPrivateMessage(CommandSourceStack source, ServerPlayer target, Component message) {
|
||||||
// Проверка, что источник команды является игроком
|
|
||||||
if (!(source.getEntity() instanceof ServerPlayer sender)) {
|
if (!(source.getEntity() instanceof ServerPlayer sender)) {
|
||||||
source.sendFailure(Component.literal("Только игроки могут отправлять личные сообщения."));
|
source.sendFailure(Component.literal("Только игроки могут отправлять личные сообщения.")
|
||||||
|
.withStyle(ChatFormatting.RED));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Проверка, что отправитель не отправляет сообщение самому себе
|
|
||||||
if (sender.getUUID().equals(target.getUUID())) {
|
if (sender.getUUID().equals(target.getUUID())) {
|
||||||
sender.sendSystemMessage(Component.literal("Вы не можете отправлять сообщения самому себе."));
|
sender.sendSystemMessage(Component.literal("Вы не можете отправлять сообщения самому себе.")
|
||||||
|
.withStyle(ChatFormatting.RED));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +159,26 @@ public class ChatITCommand {
|
||||||
target.sendSystemMessage(messageFrom);
|
target.sendSystemMessage(messageFrom);
|
||||||
sender.sendSystemMessage(messageTo);
|
sender.sendSystemMessage(messageTo);
|
||||||
|
|
||||||
|
lastSenders.put(target.getUUID(), sender.getUUID());
|
||||||
|
|
||||||
|
logPrivateMessage(sender, target, message);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Слушатель события отключения игрока для очистки хэшмапы.
|
||||||
|
*
|
||||||
|
* @param event Событие отключения игрока.
|
||||||
|
*/
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void onPlayerLogout(PlayerLoggedOutEvent event) {
|
||||||
|
Player player = event.getEntity();
|
||||||
|
UUID playerUUID = player.getUUID();
|
||||||
|
|
||||||
|
lastSenders.values().removeIf(senderUUID -> senderUUID.equals(playerUUID));
|
||||||
|
|
||||||
|
lastSenders.remove(playerUUID);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.itqop.chatit.handlers;
|
package org.itqop.chatit.handlers;
|
||||||
|
|
||||||
|
import net.minecraft.network.chat.ClickEvent;
|
||||||
|
import net.minecraft.network.chat.HoverEvent;
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
import net.minecraftforge.event.ServerChatEvent;
|
import net.minecraftforge.event.ServerChatEvent;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
|
@ -15,16 +17,27 @@ import org.slf4j.Logger;
|
||||||
import com.mojang.logging.LogUtils;
|
import com.mojang.logging.LogUtils;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static org.itqop.chatit.utils.Utils.isValidUrl;
|
||||||
|
import static org.itqop.chatit.utils.Utils.logGlobalMessage;
|
||||||
|
|
||||||
@Mod.EventBusSubscriber
|
@Mod.EventBusSubscriber
|
||||||
public class ChatEventHandler {
|
public class ChatEventHandler {
|
||||||
|
|
||||||
private static final Logger LOGGER = LogUtils.getLogger();
|
private static final Logger LOGGER = LogUtils.getLogger();
|
||||||
|
|
||||||
|
private static final Pattern URL_PATTERN = Pattern.compile(
|
||||||
|
"(https?://\\S+)", Pattern.CASE_INSENSITIVE
|
||||||
|
);
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onServerChat(ServerChatEvent event) {
|
public static void onServerChat(ServerChatEvent event) {
|
||||||
ServerPlayer sender = event.getPlayer();
|
MutableComponent errorComponent = createErrorMessage(Config.messageLocal);
|
||||||
|
MutableComponent adultComponent = createAdultMessage();
|
||||||
|
|
||||||
|
ServerPlayer sender = event.getPlayer();
|
||||||
MinecraftServer server = sender.getServer();
|
MinecraftServer server = sender.getServer();
|
||||||
String originalMessage = event.getMessage().getString();
|
String originalMessage = event.getMessage().getString();
|
||||||
|
|
||||||
|
@ -37,6 +50,8 @@ public class ChatEventHandler {
|
||||||
|
|
||||||
MutableComponent chatComponent = createChatMessage(sender, message, isGlobal);
|
MutableComponent chatComponent = createChatMessage(sender, message, isGlobal);
|
||||||
|
|
||||||
|
logGlobalMessage(chatComponent);
|
||||||
|
|
||||||
CompletableFuture<Double> future = ProfanityChecker.checkMessageAsync(message);
|
CompletableFuture<Double> future = ProfanityChecker.checkMessageAsync(message);
|
||||||
|
|
||||||
future.thenAccept(profanityScore -> {
|
future.thenAccept(profanityScore -> {
|
||||||
|
@ -45,7 +60,6 @@ public class ChatEventHandler {
|
||||||
double threshold = Config.profanityThreshold;
|
double threshold = Config.profanityThreshold;
|
||||||
|
|
||||||
if (profanityScore > threshold && !PlayerConfigManager.hasAdultContentEnabled(sender)) {
|
if (profanityScore > threshold && !PlayerConfigManager.hasAdultContentEnabled(sender)) {
|
||||||
MutableComponent adultComponent = createAdultMessage();
|
|
||||||
sender.sendSystemMessage(adultComponent);
|
sender.sendSystemMessage(adultComponent);
|
||||||
} else {
|
} else {
|
||||||
boolean localMessageSent = false;
|
boolean localMessageSent = false;
|
||||||
|
@ -73,7 +87,6 @@ public class ChatEventHandler {
|
||||||
|
|
||||||
if (!isGlobal) {
|
if (!isGlobal) {
|
||||||
if (!localMessageSent) {
|
if (!localMessageSent) {
|
||||||
MutableComponent errorComponent = createErrorMessage(Config.messageLocal);
|
|
||||||
sender.sendSystemMessage(errorComponent);
|
sender.sendSystemMessage(errorComponent);
|
||||||
} else {
|
} else {
|
||||||
sender.sendSystemMessage(chatComponent);
|
sender.sendSystemMessage(chatComponent);
|
||||||
|
@ -86,8 +99,8 @@ public class ChatEventHandler {
|
||||||
LOGGER.error(ex.toString());
|
LOGGER.error(ex.toString());
|
||||||
if (server != null) {
|
if (server != null) {
|
||||||
server.execute(() -> {
|
server.execute(() -> {
|
||||||
MutableComponent errorComponent = createErrorMessage(message);
|
MutableComponent errorCustomComponent = createErrorMessage(message);
|
||||||
sender.sendSystemMessage(errorComponent);
|
sender.sendSystemMessage(errorCustomComponent);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -120,6 +133,14 @@ public class ChatEventHandler {
|
||||||
return prefixComponent.append(errorMessage);
|
return prefixComponent.append(errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Метод для создания сообщения чата с кликабельными ссылками.
|
||||||
|
*
|
||||||
|
* @param player Игрок, отправляющий сообщение.
|
||||||
|
* @param message Текст сообщения.
|
||||||
|
* @param isGlobal Флаг, указывающий на глобальное или локальное сообщение.
|
||||||
|
* @return Кликабельное сообщение чата.
|
||||||
|
*/
|
||||||
private static MutableComponent createChatMessage(ServerPlayer player, String message, boolean isGlobal) {
|
private static MutableComponent createChatMessage(ServerPlayer player, String message, boolean isGlobal) {
|
||||||
MutableComponent openBracket = Component.literal("[");
|
MutableComponent openBracket = Component.literal("[");
|
||||||
MutableComponent letterComponent;
|
MutableComponent letterComponent;
|
||||||
|
@ -135,10 +156,47 @@ public class ChatEventHandler {
|
||||||
|
|
||||||
MutableComponent prefixComponent = openBracket.append(letterComponent).append(closeBracket);
|
MutableComponent prefixComponent = openBracket.append(letterComponent).append(closeBracket);
|
||||||
|
|
||||||
Component playerName = Component.literal(player.getName().getString());
|
MutableComponent playerName = Component.literal(player.getName().getString())
|
||||||
Component separatorComponent = Component.literal(": ");
|
.withStyle(style -> style
|
||||||
Component messageComponent = Component.literal(message).withStyle(ChatFormatting.YELLOW);
|
.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/msg " + player.getName().getString() + " "))
|
||||||
|
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal("Нажмите, чтобы ответить")))
|
||||||
|
.withColor(ChatFormatting.WHITE)
|
||||||
|
);
|
||||||
|
|
||||||
return prefixComponent.append(playerName).append(separatorComponent).append(messageComponent);
|
Component separatorComponent = Component.literal(": ");
|
||||||
|
|
||||||
|
MutableComponent messageComponent = Component.empty();
|
||||||
|
Matcher matcher = URL_PATTERN.matcher(message);
|
||||||
|
int lastEnd = 0;
|
||||||
|
|
||||||
|
while (matcher.find()) {
|
||||||
|
if (matcher.start() > lastEnd) {
|
||||||
|
String textBeforeUrl = message.substring(lastEnd, matcher.start());
|
||||||
|
messageComponent.append(Component.literal(textBeforeUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
String url = matcher.group(1);
|
||||||
|
if (isValidUrl(url)) {
|
||||||
|
MutableComponent clickableLink = Component.literal(url)
|
||||||
|
.withStyle(style -> style
|
||||||
|
.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url))
|
||||||
|
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal("Нажмите, чтобы открыть ссылку")))
|
||||||
|
.withColor(ChatFormatting.BLUE)
|
||||||
|
.withUnderlined(true)
|
||||||
|
);
|
||||||
|
messageComponent.append(clickableLink);
|
||||||
|
} else {
|
||||||
|
messageComponent.append(Component.literal(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
lastEnd = matcher.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastEnd < message.length()) {
|
||||||
|
String remainingText = message.substring(lastEnd);
|
||||||
|
messageComponent.append(Component.literal(remainingText));
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefixComponent.append(playerName).append(separatorComponent).append(messageComponent.withStyle(ChatFormatting.YELLOW));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
package org.itqop.chatit.utils;
|
||||||
|
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.chat.MutableComponent;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
|
||||||
|
public class Utils {
|
||||||
|
|
||||||
|
private static final DateTimeFormatter LOG_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
private static final String PRIVATE_MESSAGES_LOG = "logs/private_messages.log";
|
||||||
|
private static final String GLOBAL_MESSAGES_LOG = "logs/global_messages.log";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Метод для получения IP-адреса игрока.
|
||||||
|
*
|
||||||
|
* @param player Игрок, чей IP требуется получить.
|
||||||
|
* @return IP-адрес игрока в строковом формате.
|
||||||
|
*/
|
||||||
|
private static String getPlayerIp(ServerPlayer player) {
|
||||||
|
ServerGamePacketListenerImpl connection = player.connection;
|
||||||
|
|
||||||
|
InetSocketAddress address = (InetSocketAddress) connection.connection.getRemoteAddress();
|
||||||
|
|
||||||
|
InetAddress inetAddress = address.getAddress();
|
||||||
|
if (inetAddress == null) {
|
||||||
|
return "Unknown IP";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inetAddress instanceof Inet4Address) {
|
||||||
|
return inetAddress.getHostAddress();
|
||||||
|
} else if (inetAddress instanceof Inet6Address) {
|
||||||
|
String ip = inetAddress.getHostAddress();
|
||||||
|
int percentIndex = ip.indexOf('%');
|
||||||
|
if (percentIndex != -1) {
|
||||||
|
ip = ip.substring(0, percentIndex);
|
||||||
|
}
|
||||||
|
return ip;
|
||||||
|
} else {
|
||||||
|
return inetAddress.getHostAddress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Метод для логирования приватных сообщений в файл.
|
||||||
|
*
|
||||||
|
* @param sender Игрок, отправляющий сообщение.
|
||||||
|
* @param target Целевой игрок.
|
||||||
|
* @param message Текст сообщения.
|
||||||
|
*/
|
||||||
|
public static void logPrivateMessage(ServerPlayer sender, ServerPlayer target, Component message) {
|
||||||
|
String time = LocalDateTime.now().format(LOG_TIME_FORMAT);
|
||||||
|
String senderIp = getPlayerIp(sender);
|
||||||
|
String senderName = sender.getName().getString();
|
||||||
|
String targetName = target.getName().getString();
|
||||||
|
String messageText = message.getString();
|
||||||
|
String logEntry = String.format("[%s] [%s] - %s -> %s: %s%n", time, senderIp, senderName, targetName, messageText);
|
||||||
|
|
||||||
|
try (BufferedWriter writer = new BufferedWriter(new FileWriter(PRIVATE_MESSAGES_LOG, true))) {
|
||||||
|
writer.write(logEntry);
|
||||||
|
} catch (IOException e) {
|
||||||
|
//LOGGER.error("Не удалось записать приватное сообщение в лог.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Метод для логирования глобальных сообщений в файл.
|
||||||
|
*
|
||||||
|
* @param message Глобальное сообщение в формате MutableComponent.
|
||||||
|
*/
|
||||||
|
public static void logGlobalMessage(MutableComponent message) {
|
||||||
|
String time = LocalDateTime.now().format(LOG_TIME_FORMAT);
|
||||||
|
String messageText = message.getString();
|
||||||
|
String logEntry = String.format("[%s] %s%n", time, messageText);
|
||||||
|
|
||||||
|
try (BufferedWriter writer = new BufferedWriter(new FileWriter(GLOBAL_MESSAGES_LOG, true))) {
|
||||||
|
writer.write(logEntry);
|
||||||
|
} catch (IOException e) {
|
||||||
|
//LOGGER.error("Не удалось записать глобальное сообщение в лог.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Метод для проверки валидности URL.
|
||||||
|
* В будущем сюда можно добавить дополнительные проверки, например, DGA.
|
||||||
|
*
|
||||||
|
* @param url Строка с URL для проверки.
|
||||||
|
* @return true, если URL валиден, иначе false.
|
||||||
|
*/
|
||||||
|
public static boolean isValidUrl(String url) {
|
||||||
|
try {
|
||||||
|
new URL(url).toURI(); // Проверяем синтаксис URL
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue