Переделал настройки цветов: /chatcolor теперь принимает &b формат, добавлена поддержка #RRGGBB в конфигах
This commit is contained in:
parent
c6442bc88f
commit
ee67dcc12a
4 changed files with 99 additions and 34 deletions
|
|
@ -11,12 +11,13 @@ import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class ChatColorCommand implements CommandExecutor, TabCompleter {
|
public class ChatColorCommand implements CommandExecutor, TabCompleter {
|
||||||
|
|
||||||
private final LoChat plugin;
|
private final LoChat plugin;
|
||||||
|
private static final Pattern LEGACY_COLOR_PATTERN = Pattern.compile("^&([0-9a-fk-orA-FK-OR])$");
|
||||||
|
|
||||||
public ChatColorCommand(LoChat plugin) {
|
public ChatColorCommand(LoChat plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
|
@ -36,51 +37,51 @@ public class ChatColorCommand implements CommandExecutor, TabCompleter {
|
||||||
|
|
||||||
if (args.length == 0) {
|
if (args.length == 0) {
|
||||||
player.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getInvalidUsage("/chatcolor <цвет>")));
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String color = args[0].toLowerCase();
|
String color = args[0];
|
||||||
|
|
||||||
// Проверяем валидность цвета
|
// Проверяем валидность цвета (формат &X где X - это цветовой код)
|
||||||
if (!isValidColor(color)) {
|
if (!isValidColor(color)) {
|
||||||
player.sendMessage(ChatFormatter.parse("<red>Неверный цвет! Используйте один из доступных цветов.</red>"));
|
player.sendMessage(ChatFormatter.parse("<red>Неверный формат цвета! Используйте формат &X, например: &b, &a, &c</red>"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Сохраняем цвет чата игрока
|
// Сохраняем цвет чата игрока
|
||||||
plugin.getChatColorManager().setChatColor(player.getUniqueId(), color);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isValidColor(String color) {
|
private boolean isValidColor(String color) {
|
||||||
List<String> validColors = Arrays.asList(
|
if (color == null || color.length() != 2) {
|
||||||
"red", "blue", "green", "yellow", "gold", "aqua",
|
return false;
|
||||||
"light_purple", "white", "gray", "dark_gray", "black",
|
}
|
||||||
"dark_red", "dark_green", "dark_blue", "dark_aqua", "dark_purple"
|
if (!color.startsWith("&")) {
|
||||||
);
|
return false;
|
||||||
return validColors.contains(color);
|
}
|
||||||
|
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
|
@Override
|
||||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
|
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<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -82,12 +82,59 @@ public class ChatColorManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Применяет цвет чата к сообщению
|
* Применяет цвет чата к сообщению
|
||||||
|
* Поддерживает формат &X (Minecraft color codes)
|
||||||
*/
|
*/
|
||||||
public String applyChatColor(UUID playerId, String message) {
|
public String applyChatColor(UUID playerId, String message) {
|
||||||
String color = getChatColor(playerId);
|
String color = getChatColor(playerId);
|
||||||
if (color != null) {
|
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 "<" + color + ">" + message + "</" + color + ">";
|
||||||
}
|
}
|
||||||
return message;
|
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 -> "";
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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 = 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 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_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}");
|
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) {
|
public static String convertHexColors(String message) {
|
||||||
Matcher matcher = HEX_PATTERN.matcher(message);
|
String result = message;
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
|
// Конвертируем &#RRGGBB
|
||||||
|
Matcher matcher = HEX_PATTERN.matcher(result);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
matcher.appendReplacement(result, "<#" + matcher.group(1) + ">");
|
matcher.appendReplacement(sb, "<#" + matcher.group(1) + ">");
|
||||||
}
|
}
|
||||||
matcher.appendTail(result);
|
matcher.appendTail(sb);
|
||||||
return result.toString();
|
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()
|
boolean hasColorCodes = LEGACY_COLOR_PATTERN.matcher(result).find()
|
||||||
|| SECTION_COLOR_PATTERN.matcher(result).find()
|
|| SECTION_COLOR_PATTERN.matcher(result).find()
|
||||||
|| HEX_PATTERN.matcher(result).find()
|
|| HEX_PATTERN.matcher(result).find()
|
||||||
|
|| HEX_PATTERN_NO_AMPERSAND.matcher(result).find()
|
||||||
|| MINIMESSAGE_HEX_PATTERN.matcher(result).find();
|
|| MINIMESSAGE_HEX_PATTERN.matcher(result).find();
|
||||||
|
|
||||||
// Если есть право на цвета И есть цветовые коды - конвертируем
|
// Если есть право на цвета И есть цветовые коды - конвертируем
|
||||||
|
|
@ -239,6 +253,9 @@ public class ChatFormatter {
|
||||||
// Убираем &#RRGGBB
|
// Убираем &#RRGGBB
|
||||||
result = HEX_PATTERN.matcher(result).replaceAll("");
|
result = HEX_PATTERN.matcher(result).replaceAll("");
|
||||||
|
|
||||||
|
// Убираем #RRGGBB (без &)
|
||||||
|
result = HEX_PATTERN_NO_AMPERSAND.matcher(result).replaceAll("");
|
||||||
|
|
||||||
// Убираем &коды
|
// Убираем &коды
|
||||||
result = stripLegacyColors(result);
|
result = stripLegacyColors(result);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ messages:
|
||||||
|
|
||||||
# Донат
|
# Донат
|
||||||
donate:
|
donate:
|
||||||
- "&#FFD700&l:gem: ДОНАТ :gem:"
|
- "#FFD700&l:gem: ДОНАТ :gem:"
|
||||||
- "&7Поддержи сервер и получи"
|
- "&7Поддержи сервер и получи"
|
||||||
- "&7крутые привилегии!"
|
- "&7крутые привилегии!"
|
||||||
- "&eПодробнее: &a/donate"
|
- "&eПодробнее: &a/donate"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue