Fix GUI colors and TAB placeholder format - applyGradient uses &#RRGGBB for GUI (LegacyComponentSerializer) - Added applyGradientTabFormat for TAB plugin (§x§R§R§G§G§B§B) - PlaceholderAPIHook now uses TAB format for %lochat_full% - Updated tests to match new formats
This commit is contained in:
parent
036382b71a
commit
29ae373554
5 changed files with 127 additions and 26 deletions
|
|
@ -116,8 +116,25 @@ public class GradientModule {
|
|||
/**
|
||||
* Получает отформатированное имя игрока с градиентом и LuckPerms префиксом
|
||||
* Градиент применяется на всю строку целиком (префикс + ник)
|
||||
* Использует формат &#RRGGBB
|
||||
*/
|
||||
public String getFormattedName(Player player) {
|
||||
return getFormattedName(player, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает отформатированное имя для TAB плагина
|
||||
* Использует формат §x§R§R§G§G§B§B
|
||||
*/
|
||||
public String getFormattedNameForTab(Player player) {
|
||||
return getFormattedName(player, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает отформатированное имя игрока с градиентом и LuckPerms префиксом
|
||||
* @param useTabFormat true для §x§... формата (TAB), false для &#RRGGBB
|
||||
*/
|
||||
private String getFormattedName(Player player, boolean useTabFormat) {
|
||||
if (!enabled) return player.getName();
|
||||
|
||||
GradientPlayerData data = dataManager.getPlayerData(player.getUniqueId());
|
||||
|
|
@ -142,7 +159,7 @@ public class GradientModule {
|
|||
} else {
|
||||
// LP префикс со своими цветами, ник отдельно
|
||||
String nick = data.hasColors() && data.isColorEnabled()
|
||||
? GradientUtil.applyGradient(player.getName(), data.getColors(), config.isUseLegacyRgbFormat())
|
||||
? applyGradientWithFormat(player.getName(), data.getColors(), useTabFormat)
|
||||
: player.getName();
|
||||
return lpPrefix + nick;
|
||||
}
|
||||
|
|
@ -153,12 +170,25 @@ public class GradientModule {
|
|||
|
||||
// Применяем единый градиент на всю строку
|
||||
if (data.hasColors() && data.isColorEnabled()) {
|
||||
return GradientUtil.applyGradient(fullText.toString(), data.getColors(), config.isUseLegacyRgbFormat());
|
||||
return applyGradientWithFormat(fullText.toString(), data.getColors(), useTabFormat);
|
||||
}
|
||||
|
||||
return fullText.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Применяет градиент с нужным форматом
|
||||
*/
|
||||
private String applyGradientWithFormat(String text, java.util.List<String> colors, boolean useTabFormat) {
|
||||
if (useTabFormat) {
|
||||
// Формат §x§R§R§G§G§B§B для TAB
|
||||
return GradientUtil.applyGradientTabFormat(text, colors);
|
||||
} else {
|
||||
// Формат &#RRGGBB для GUI и чата
|
||||
return GradientUtil.applyGradient(text, colors, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Убирает цветовые коды из строки
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -68,8 +68,8 @@ public class GradientConfirmGUI implements InventoryHolder {
|
|||
skullMeta.setOwningPlayer(player);
|
||||
|
||||
String preview = buildPreview();
|
||||
// Preview уже в MiniMessage формате, просто парсим
|
||||
Component previewComponent = ChatFormatter.parse(preview);
|
||||
// Для GUI используем LegacyComponentSerializer с поддержкой HEX
|
||||
Component previewComponent = SERIALIZER.deserialize(preview);
|
||||
skullMeta.displayName(previewComponent.decoration(TextDecoration.ITALIC, false));
|
||||
|
||||
List<Component> lore = new ArrayList<>();
|
||||
|
|
@ -126,22 +126,22 @@ public class GradientConfirmGUI implements InventoryHolder {
|
|||
}
|
||||
}
|
||||
|
||||
// Для GUI всегда используем MiniMessage формат (false) для правильного отображения градиента
|
||||
boolean useLegacyForPreview = false;
|
||||
// Для GUI используем legacy формат &#RRGGBB который LegacyComponentSerializer понимает
|
||||
boolean useLegacyForPreview = true;
|
||||
|
||||
// Если нет кастомного префикса - используем LuckPerms префикс
|
||||
if ((prefixToUse == null || prefixToUse.isEmpty()) && module.getLuckPermsHook().isEnabled()) {
|
||||
String lpPrefix = module.getLuckPermsHook().getActivePrefix(player);
|
||||
if (lpPrefix != null && !lpPrefix.isEmpty()) {
|
||||
// Для превью показываем LP префикс
|
||||
// Конвертируем LP префикс в legacy формат
|
||||
lpPrefix = convertToLegacy(lpPrefix);
|
||||
|
||||
// Если градиент на LP префикс включен - применяем градиент на всю строку
|
||||
if (colorsToUse != null && !colorsToUse.isEmpty() && module.getConfig().isGradientOnLuckPermsPrefix()) {
|
||||
// Убираем цвета из LP префикса и применяем градиент на всё
|
||||
String cleanLpPrefix = stripColors(lpPrefix);
|
||||
String fullText = cleanLpPrefix + nick;
|
||||
return GradientUtil.applyGradient(fullText, colorsToUse, useLegacyForPreview);
|
||||
} else {
|
||||
// LP префикс со своими цветами + градиентный ник
|
||||
if (colorsToUse != null && !colorsToUse.isEmpty()) {
|
||||
return lpPrefix + GradientUtil.applyGradient(nick, colorsToUse, useLegacyForPreview);
|
||||
}
|
||||
|
|
@ -161,6 +161,15 @@ public class GradientConfirmGUI implements InventoryHolder {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Конвертирует MiniMessage теги в legacy формат
|
||||
*/
|
||||
private String convertToLegacy(String text) {
|
||||
if (text == null) return "";
|
||||
// Конвертируем <#RRGGBB> в &#RRGGBB
|
||||
return text.replaceAll("<#([A-Fa-f0-9]{6})>", "&#$1");
|
||||
}
|
||||
|
||||
/**
|
||||
* Убирает цветовые коды из строки
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -98,15 +98,57 @@ public final class GradientUtil {
|
|||
private static String formatHex(String hex, boolean useLegacyFormat) {
|
||||
hex = hex.replace("#", "").toLowerCase();
|
||||
if (useLegacyFormat) {
|
||||
// Формат §x§R§R§G§G§B§B для TAB и других плагинов
|
||||
// Формат &#RRGGBB для LegacyComponentSerializer
|
||||
return "&#" + hex;
|
||||
} else {
|
||||
return "<#" + hex + ">";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Конвертирует HEX в формат §x§R§R§G§G§B§B для TAB плагина
|
||||
*/
|
||||
private static String formatHexForTab(String hex) {
|
||||
hex = hex.replace("#", "").toLowerCase();
|
||||
StringBuilder sb = new StringBuilder("§x");
|
||||
for (char c : hex.toCharArray()) {
|
||||
sb.append("§").append(c);
|
||||
}
|
||||
return sb.toString();
|
||||
} else {
|
||||
return "<#" + hex + ">";
|
||||
}
|
||||
|
||||
/**
|
||||
* Применяет градиент в формате §x§R§R§G§G§B§B для TAB плагина
|
||||
*/
|
||||
public static String applyGradientTabFormat(String text, List<String> hexColors) {
|
||||
if (text == null || text.isEmpty() || hexColors == null || hexColors.isEmpty()) {
|
||||
return text;
|
||||
}
|
||||
|
||||
char[] chars = text.toCharArray();
|
||||
int length = chars.length;
|
||||
if (length == 0) return text;
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
if (hexColors.size() == 1) {
|
||||
String colorCode = formatHexForTab(hexColors.get(0));
|
||||
result.append(colorCode).append(text);
|
||||
} else {
|
||||
Color[] colors = hexColors.stream()
|
||||
.map(GradientUtil::parseHex)
|
||||
.toArray(Color[]::new);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
double ratio = length > 1 ? (double) i / (length - 1) : 0.0;
|
||||
Color interpolated = interpolateMultiColor(colors, ratio);
|
||||
String hex = String.format("#%02x%02x%02x",
|
||||
interpolated.getRed(), interpolated.getGreen(), interpolated.getBlue());
|
||||
result.append(formatHexForTab(hex)).append(chars[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static String buildDisplayName(String prefix, String nick, List<String> colors,
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ public class PlaceholderAPIHook extends PlaceholderExpansion {
|
|||
}
|
||||
|
||||
// Gradient placeholders (совместимость с LoPreff)
|
||||
// Используем TAB формат §x§R§R§G§G§B§B для совместимости с TAB плагином
|
||||
case "gradient_full", "full" -> {
|
||||
Player onlinePlayer = player.getPlayer();
|
||||
if (onlinePlayer == null) yield player.getName() != null ? player.getName() : "";
|
||||
|
|
@ -78,7 +79,8 @@ public class PlaceholderAPIHook extends PlaceholderExpansion {
|
|||
yield player.getName() != null ? player.getName() : "";
|
||||
}
|
||||
|
||||
yield gradient.getFormattedName(onlinePlayer);
|
||||
// Используем TAB формат для плейсхолдеров
|
||||
yield gradient.getFormattedNameForTab(onlinePlayer);
|
||||
}
|
||||
case "gradient_name", "name" -> {
|
||||
Player onlinePlayer = player.getPlayer();
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ class GradientUtilTest {
|
|||
void applyGradient_singleColor_legacy() {
|
||||
String result = GradientUtil.applyGradient("Hi", List.of("#FF0000"), true);
|
||||
assertNotNull(result);
|
||||
// Формат §x§f§f§0§0§0§0
|
||||
assertTrue(result.contains("§x§f§f§0§0§0§0"));
|
||||
// Формат &#RRGGBB для LegacyComponentSerializer
|
||||
assertTrue(result.contains("&#ff0000"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -50,9 +50,9 @@ class GradientUtilTest {
|
|||
void applyGradient_twoColors() {
|
||||
String result = GradientUtil.applyGradient("AB", List.of("#FF0000", "#0000FF"), true);
|
||||
assertNotNull(result);
|
||||
// Первый символ должен быть красным, последний синим
|
||||
assertTrue(result.contains("§x§f§f§0§0§0§0")); // красный
|
||||
assertTrue(result.contains("§x§0§0§0§0§f§f")); // синий
|
||||
// Первый символ должен быть красным, последний синим (формат &#RRGGBB)
|
||||
assertTrue(result.contains("&#ff0000")); // красный
|
||||
assertTrue(result.contains("�ff")); // синий
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -105,23 +105,24 @@ class GradientUtilTest {
|
|||
void buildDisplayName_noPrefix_withColors() {
|
||||
String result = GradientUtil.buildDisplayName(null, "AB", List.of("#FF0000", "#0000FF"), true, true, "[{prefix}] ", true);
|
||||
assertNotNull(result);
|
||||
assertTrue(result.contains("§x"));
|
||||
// Формат &#RRGGBB
|
||||
assertTrue(result.contains("&#"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildDisplayName_withPrefix_withColors_continuous() {
|
||||
String result = GradientUtil.buildDisplayName("V", "AB", List.of("#FF0000", "#0000FF"), true, true, "[{prefix}] ", true);
|
||||
assertNotNull(result);
|
||||
// Единый градиент на всё
|
||||
assertTrue(result.contains("§x"));
|
||||
// Единый градиент на всё (формат &#RRGGBB)
|
||||
assertTrue(result.contains("&#"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildDisplayName_withPrefix_withColors_separate() {
|
||||
String result = GradientUtil.buildDisplayName("V", "AB", List.of("#FF0000", "#0000FF"), true, false, "[{prefix}] ", true);
|
||||
assertNotNull(result);
|
||||
// Отдельные градиенты
|
||||
assertTrue(result.contains("§x"));
|
||||
// Отдельные градиенты (формат &#RRGGBB)
|
||||
assertTrue(result.contains("&#"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -131,4 +132,21 @@ class GradientUtilTest {
|
|||
// Префикс без градиента
|
||||
assertTrue(result.startsWith("[VIP] "));
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyGradientTabFormat_singleColor() {
|
||||
String result = GradientUtil.applyGradientTabFormat("Hi", List.of("#FF0000"));
|
||||
assertNotNull(result);
|
||||
// Формат §x§f§f§0§0§0§0 для TAB
|
||||
assertTrue(result.contains("§x§f§f§0§0§0§0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyGradientTabFormat_twoColors() {
|
||||
String result = GradientUtil.applyGradientTabFormat("AB", List.of("#FF0000", "#0000FF"));
|
||||
assertNotNull(result);
|
||||
// Первый символ красный, последний синий
|
||||
assertTrue(result.contains("§x§f§f§0§0§0§0")); // красный
|
||||
assertTrue(result.contains("§x§0§0§0§0§f§f")); // синий
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue