Переделал настройки цветов: /chatcolor теперь принимает &b формат, добавлена поддержка #RRGGBB в конфигах

This commit is contained in:
loki5512344 2025-12-30 20:35:10 +01:00
parent c6442bc88f
commit ee67dcc12a
4 changed files with 99 additions and 34 deletions

View file

@ -11,12 +11,13 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
public class ChatColorCommand implements CommandExecutor, TabCompleter {
private final LoChat plugin;
private static final Pattern LEGACY_COLOR_PATTERN = Pattern.compile("^&([0-9a-fk-orA-FK-OR])$");
public ChatColorCommand(LoChat plugin) {
this.plugin = plugin;
@ -36,51 +37,51 @@ public class ChatColorCommand implements CommandExecutor, TabCompleter {
if (args.length == 0) {
player.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getInvalidUsage("/chatcolor <цвет>")));
player.sendMessage(ChatFormatter.parse("<gray>Доступные цвета: <red>red</red>, <blue>blue</blue>, <green>green</green>, <yellow>yellow</yellow>, <gold>gold</gold>, <aqua>aqua</aqua>, <light_purple>light_purple</light_purple>, <white>white</white>, <gray>gray</gray>, <dark_gray>dark_gray</dark_gray>"));
player.sendMessage(ChatFormatter.parse("<gray>Используйте Minecraft color codes: &a, &b, &c, &d, &e, &f, &0-&9, &k, &l, &m, &n, &o, &r</gray>"));
player.sendMessage(ChatFormatter.parse("<gray>Пример: /chatcolor &b</gray>"));
return true;
}
String color = args[0].toLowerCase();
String color = args[0];
// Проверяем валидность цвета
// Проверяем валидность цвета (формат &X где X - это цветовой код)
if (!isValidColor(color)) {
player.sendMessage(ChatFormatter.parse("<red>Неверный цвет! Используйте один из доступных цветов.</red>"));
player.sendMessage(ChatFormatter.parse("<red>Неверный формат цвета! Используйте формат &X, например: &b, &a, &c</red>"));
return true;
}
// Сохраняем цвет чата игрока
plugin.getChatColorManager().setChatColor(player.getUniqueId(), color);
player.sendMessage(ChatFormatter.parse("<green>Цвет чата установлен на <" + color + ">" + color + "</color>!"));
// Показываем пример с примененным цветом
String preview = ChatFormatter.convertAllColors(color + "Пример текста");
player.sendMessage(ChatFormatter.parse("<green>Цвет чата установлен! Пример: " + preview));
return true;
}
private boolean isValidColor(String color) {
List<String> validColors = Arrays.asList(
"red", "blue", "green", "yellow", "gold", "aqua",
"light_purple", "white", "gray", "dark_gray", "black",
"dark_red", "dark_green", "dark_blue", "dark_aqua", "dark_purple"
);
return validColors.contains(color);
if (color == null || color.length() != 2) {
return false;
}
if (!color.startsWith("&")) {
return false;
}
char code = color.charAt(1);
return (code >= '0' && code <= '9') ||
(code >= 'a' && code <= 'f') ||
(code >= 'A' && code <= 'F') ||
code == 'k' || code == 'K' ||
code == 'l' || code == 'L' ||
code == 'm' || code == 'M' ||
code == 'n' || code == 'N' ||
code == 'o' || code == 'O' ||
code == 'r' || code == 'R';
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
if (args.length == 1) {
List<String> colors = Arrays.asList(
"red", "blue", "green", "yellow", "gold", "aqua",
"light_purple", "white", "gray", "dark_gray"
);
List<String> completions = new ArrayList<>();
String input = args[0].toLowerCase();
for (String color : colors) {
if (color.startsWith(input)) {
completions.add(color);
}
}
return completions;
}
// Убираем автодополнение, так как теперь пользователь сам вводит цвет
return new ArrayList<>();
}
}

View file

@ -82,12 +82,59 @@ public class ChatColorManager {
/**
* Применяет цвет чата к сообщению
* Поддерживает формат &X (Minecraft color codes)
*/
public String applyChatColor(UUID playerId, String message) {
String color = getChatColor(playerId);
if (color != null) {
// Если цвет в формате &X, конвертируем его в MiniMessage
if (color.startsWith("&") && color.length() == 2) {
String miniMessageColor = convertLegacyColorToMiniMessage(color);
if (!miniMessageColor.isEmpty()) {
// Извлекаем имя тега из <tag> для закрывающего тега
String tagName = miniMessageColor.substring(1, miniMessageColor.length() - 1);
return miniMessageColor + message + "</" + tagName + ">";
}
}
// Если уже в формате MiniMessage, используем как есть
return "<" + color + ">" + message + "</" + color + ">";
}
return message;
}
/**
* Конвертирует &X код в MiniMessage формат
*/
private String convertLegacyColorToMiniMessage(String legacyColor) {
if (legacyColor == null || legacyColor.length() != 2 || !legacyColor.startsWith("&")) {
return "";
}
char code = legacyColor.charAt(1);
return switch (Character.toLowerCase(code)) {
case '0' -> "<black>";
case '1' -> "<dark_blue>";
case '2' -> "<dark_green>";
case '3' -> "<dark_aqua>";
case '4' -> "<dark_red>";
case '5' -> "<dark_purple>";
case '6' -> "<gold>";
case '7' -> "<gray>";
case '8' -> "<dark_gray>";
case '9' -> "<blue>";
case 'a' -> "<green>";
case 'b' -> "<aqua>";
case 'c' -> "<red>";
case 'd' -> "<light_purple>";
case 'e' -> "<yellow>";
case 'f' -> "<white>";
case 'k' -> "<obfuscated>";
case 'l' -> "<bold>";
case 'm' -> "<strikethrough>";
case 'n' -> "<underlined>";
case 'o' -> "<italic>";
case 'r' -> "<reset>";
default -> "";
};
}
}

View file

@ -16,6 +16,7 @@ public class ChatFormatter {
// Паттерны для цветов
private static final Pattern HEX_PATTERN = Pattern.compile("&#([A-Fa-f0-9]{6})");
private static final Pattern HEX_PATTERN_NO_AMPERSAND = Pattern.compile("(?<!&)#([A-Fa-f0-9]{6})");
private static final Pattern LEGACY_COLOR_PATTERN = Pattern.compile("&([0-9a-fk-orA-FK-OR])");
private static final Pattern SECTION_COLOR_PATTERN = Pattern.compile("§([0-9a-fk-orA-FK-OR])");
private static final Pattern SECTION_HEX_PATTERN = Pattern.compile("§x(§[0-9A-Fa-f]){6}");
@ -73,16 +74,28 @@ public class ChatFormatter {
}
/**
* Конвертирует &#RRGGBB в MiniMessage формат <#RRGGBB>
* Конвертирует &#RRGGBB и #RRGGBB в MiniMessage формат <#RRGGBB>
*/
public static String convertHexColors(String message) {
Matcher matcher = HEX_PATTERN.matcher(message);
StringBuilder result = new StringBuilder();
String result = message;
// Конвертируем &#RRGGBB
Matcher matcher = HEX_PATTERN.matcher(result);
StringBuilder sb = new StringBuilder();
while (matcher.find()) {
matcher.appendReplacement(result, "<#" + matcher.group(1) + ">");
matcher.appendReplacement(sb, "<#" + matcher.group(1) + ">");
}
matcher.appendTail(result);
return result.toString();
matcher.appendTail(sb);
result = sb.toString();
// Конвертируем #RRGGBB (без &, но не если это часть &#RRGGBB)
matcher = HEX_PATTERN_NO_AMPERSAND.matcher(result);
sb = new StringBuilder();
while (matcher.find()) {
matcher.appendReplacement(sb, "<#" + matcher.group(1) + ">");
}
matcher.appendTail(sb);
return sb.toString();
}
/**
@ -171,6 +184,7 @@ public class ChatFormatter {
boolean hasColorCodes = LEGACY_COLOR_PATTERN.matcher(result).find()
|| SECTION_COLOR_PATTERN.matcher(result).find()
|| HEX_PATTERN.matcher(result).find()
|| HEX_PATTERN_NO_AMPERSAND.matcher(result).find()
|| MINIMESSAGE_HEX_PATTERN.matcher(result).find();
// Если есть право на цвета И есть цветовые коды - конвертируем
@ -239,6 +253,9 @@ public class ChatFormatter {
// Убираем &#RRGGBB
result = HEX_PATTERN.matcher(result).replaceAll("");
// Убираем #RRGGBB (без &)
result = HEX_PATTERN_NO_AMPERSAND.matcher(result).replaceAll("");
// Убираем &коды
result = stripLegacyColors(result);