feat: add example mine config, &#RRGGBB color support, up to 100 selection points

This commit is contained in:
loki5512344 2026-06-01 11:38:53 +02:00
parent 0f2735f171
commit f2be6d6ece
6 changed files with 445 additions and 28 deletions

View file

@ -17,32 +17,17 @@ public final class RegionConfigLoader {
/**
* Parses region configuration from YAML.
* Supports up to 100 selection points (50 regions).
*/
public RegionConfig parse(YamlConfiguration yaml) {
List<Location> selections = new ArrayList<>();
// Try new format first
for (int i = 1; i <= 10; i++) {
String key = "region.selection." + i;
if (yaml.contains(key)) {
String locStr = yaml.getString(key);
if (locStr != null && !locStr.isBlank()) {
selections.add(parseLocation(locStr));
}
}
}
// Try new format first (region.selection.X)
selections.addAll(parseSelections(yaml, "region.selection.", 100));
// Legacy fallback
// Legacy fallback (selection.X)
if (selections.isEmpty()) {
for (int i = 1; i <= 10; i++) {
String key = "selection." + i;
if (yaml.contains(key)) {
String locStr = yaml.getString(key);
if (locStr != null && !locStr.isBlank()) {
selections.add(parseLocation(locStr));
}
}
}
selections.addAll(parseSelections(yaml, "selection.", 100));
}
if (selections.size() < 2) {
@ -52,6 +37,43 @@ public final class RegionConfigLoader {
return RegionConfig.fromSelections(selections);
}
/**
* Parses selection points from YAML with given prefix.
* Supports indexed format: prefix.1, prefix.2, etc.
*/
private List<Location> parseSelections(YamlConfiguration yaml, String prefix, int maxPoints) {
List<Location> selections = new ArrayList<>();
for (int i = 1; i <= maxPoints; i++) {
String key = prefix + i;
if (yaml.contains(key)) {
String locStr = yaml.getString(key);
if (locStr != null && !locStr.isBlank()) {
try {
selections.add(parseLocation(locStr));
} catch (IllegalArgumentException e) {
// Skip invalid locations but continue parsing
}
}
} else {
// Stop at first missing index (assuming sequential)
// But check at least a few more for gaps
if (i > 20) {
boolean hasMore = false;
for (int j = i + 1; j <= Math.min(i + 5, maxPoints); j++) {
if (yaml.contains(prefix + j)) {
hasMore = true;
break;
}
}
if (!hasMore) break;
}
}
}
return selections;
}
/**
* Saves region configuration to YAML.
*/

View file

@ -1,6 +1,6 @@
package dev.loki.lomines.data.config.ui;
import net.kyori.adventure.text.minimessage.MiniMessage;
import dev.loki.lomines.util.format.ColorUtils;
import net.kyori.adventure.text.Component;
import java.util.Objects;
@ -36,6 +36,7 @@ public record UIConfig(
/**
* Parses the action bar format with placeholders.
* Placeholders: {mine}, {percent}, {time}, {blocks}, {total}
* Supports colors: &#RRGGBB, &a..&f, <color>
*/
public Component formatActionBar(String mineName, double percent, String timeStr, int blocks, int total) {
String parsed = actionBarFormat
@ -45,7 +46,7 @@ public record UIConfig(
.replace("{blocks}", String.valueOf(blocks))
.replace("{total}", String.valueOf(total));
return MiniMessage.miniMessage().deserialize(parsed);
return ColorUtils.format(parsed);
}
/**

View file

@ -5,7 +5,7 @@ import dev.loki.lomines.core.mine.Mine;
import dev.loki.lomines.data.config.ui.HologramConfig;
import dev.loki.lomines.integration.hologram.provider.DecentHologramsProvider;
import dev.loki.lomines.integration.hologram.provider.HolographicDisplaysProvider;
import net.kyori.adventure.text.minimessage.MiniMessage;
import dev.loki.lomines.util.format.ColorUtils;
import org.bukkit.Location;
import java.util.*;
@ -144,7 +144,6 @@ public final class HologramManager {
private List<String> formatLines(List<String> format, Mine mine) {
List<String> result = new ArrayList<>();
MiniMessage miniMessage = MiniMessage.miniMessage();
for (String line : format) {
String formatted = line
@ -153,7 +152,8 @@ public final class HologramManager {
.replace("{bar}", createProgressBar(mine.getPercentFilled()))
.replace("{time}", formatResetTime(mine));
result.add(formatted);
// Convert &#RRGGBB and &codes to legacy for hologram plugins
result.add(ColorUtils.toLegacy(formatted));
}
return result;
@ -163,12 +163,12 @@ public final class HologramManager {
int filled = (int) Math.round(percent / 10.0);
int empty = 10 - filled;
// Use &#RRGGBB format which works with most hologram plugins
StringBuilder bar = new StringBuilder();
bar.append("<green>");
bar.append("&#00FF00"); // Green for filled
bar.append("█".repeat(Math.max(0, filled)));
bar.append("<gray>");
bar.append("&#808080"); // Gray for empty
bar.append("░".repeat(Math.max(0, empty)));
bar.append("</gray></green>");
return bar.toString();
}

View file

@ -0,0 +1,207 @@
package dev.loki.lomines.util.format;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Utility for converting color formats.
* Supports: &#RRGGBB (HEX), &x&R&R&G&G&B&B (Bukkit HEX), MiniMessage
*/
public final class ColorUtils {
private static final Pattern HEX_PATTERN = Pattern.compile("&#([0-9A-Fa-f]{6})");
private static final Pattern LEGACY_HEX_PATTERN = Pattern.compile("&x([&0-9A-Fa-f]){12}");
private static final MiniMessage MINI_MESSAGE = MiniMessage.miniMessage();
private static final LegacyComponentSerializer LEGACY_SERIALIZER = LegacyComponentSerializer.builder()
.hexColors()
.useUnusualXRepeatedCharacterHexFormat()
.build();
private ColorUtils() {
// Utility class
}
/**
* Converts a string with color codes to a Component.
* Supports:
* - &#RRGGBB - HEX colors
* - &x&R&R&G&G&B&B - Legacy Bukkit HEX
* - &a, &b, ... - Legacy colors
* - <color>, <#RRGGBB> - MiniMessage (pass-through)
*/
public static Component format(String text) {
if (text == null || text.isEmpty()) {
return Component.empty();
}
// Check if it's already MiniMessage format
if (text.contains("<") && text.contains(">")) {
try {
return MINI_MESSAGE.deserialize(text);
} catch (Exception e) {
// Fall through to legacy conversion
}
}
// Convert &#RRGGBB to MiniMessage <#RRGGBB>
String miniMessageText = convertHexToMiniMessage(text);
// Convert legacy &x format if present
miniMessageText = convertLegacyHexToMiniMessage(miniMessageText);
// Convert remaining legacy codes (&a, &l, etc.) to MiniMessage
miniMessageText = convertLegacyToMiniMessage(miniMessageText);
try {
return MINI_MESSAGE.deserialize(miniMessageText);
} catch (Exception e) {
// Fallback: use legacy serializer
return LEGACY_SERIALIZER.deserialize(text);
}
}
/**
* Converts &#RRGGBB to <#RRGGBB> for MiniMessage.
*/
private static String convertHexToMiniMessage(String text) {
Matcher matcher = HEX_PATTERN.matcher(text);
StringBuffer result = new StringBuffer();
while (matcher.find()) {
String hex = matcher.group(1);
matcher.appendReplacement(result, "<#" + hex + ">");
}
matcher.appendTail(result);
return result.toString();
}
/**
* Converts &x&R&R&G&G&B&B to <#RRGGBB> for MiniMessage.
*/
private static String convertLegacyHexToMiniMessage(String text) {
if (!text.contains("&x")) {
return text;
}
// Pattern for &x&R&R&G&G&B&B
Pattern bukkitHex = Pattern.compile("&x(&[0-9A-Fa-f])(&[0-9A-Fa-f])(&[0-9A-Fa-f])(&[0-9A-Fa-f])(&[0-9A-Fa-f])(&[0-9A-Fa-f])");
Matcher matcher = bukkitHex.matcher(text);
StringBuffer result = new StringBuffer();
while (matcher.find()) {
String r1 = matcher.group(1).substring(1);
String r2 = matcher.group(2).substring(1);
String g1 = matcher.group(3).substring(1);
String g2 = matcher.group(4).substring(1);
String b1 = matcher.group(5).substring(1);
String b2 = matcher.group(6).substring(1);
String hex = r1 + r2 + g1 + g2 + b1 + b2;
matcher.appendReplacement(result, "<#" + hex + ">");
}
matcher.appendTail(result);
return result.toString();
}
/**
* Converts legacy & codes to MiniMessage tags.
*/
private static String convertLegacyToMiniMessage(String text) {
return text
.replace("&0", "<black>")
.replace("&1", "<dark_blue>")
.replace("&2", "<dark_green>")
.replace("&3", "<dark_aqua>")
.replace("&4", "<dark_red>")
.replace("&5", "<dark_purple>")
.replace("&6", "<gold>")
.replace("&7", "<gray>")
.replace("&8", "<dark_gray>")
.replace("&9", "<blue>")
.replace("&a", "<green>")
.replace("&b", "<aqua>")
.replace("&c", "<red>")
.replace("&d", "<light_purple>")
.replace("&e", "<yellow>")
.replace("&f", "<white>")
.replace("&k", "<obfuscated>")
.replace("&l", "<bold>")
.replace("&m", "<strikethrough>")
.replace("&n", "<underlined>")
.replace("&o", "<italic>")
.replace("&r", "<reset>");
}
/**
* Strips all color codes from text.
*/
public static String stripColors(String text) {
if (text == null || text.isEmpty()) {
return "";
}
return text.replaceAll("&#[0-9A-Fa-f]{6}", "")
.replaceAll("&[0-9A-Fa-fk-orK-OR]", "")
.replaceAll("<[^>]+>", "");
}
/**
* Converts to legacy color format (&a, &c, &x&R&R&G&G&B&B).
* Useful for plugins that don't support MiniMessage.
*/
public static String toLegacy(String text) {
if (text == null || text.isEmpty()) {
return "";
}
String result = text;
// Convert MiniMessage <#RRGGBB> to &x&R&R&G&G&B&B
Pattern hexTag = Pattern.compile("<#([0-9A-Fa-f]{6})>");
Matcher hexMatcher = hexTag.matcher(result);
StringBuffer sb = new StringBuffer();
while (hexMatcher.find()) {
String hex = hexMatcher.group(1);
StringBuilder legacy = new StringBuilder("&x");
for (char c : hex.toCharArray()) {
legacy.append("&").append(c);
}
hexMatcher.appendReplacement(sb, legacy.toString());
}
hexMatcher.appendTail(sb);
result = sb.toString();
// Convert MiniMessage named colors to legacy
result = result
.replace("<black>", "&0")
.replace("<dark_blue>", "&1")
.replace("<dark_green>", "&2")
.replace("<dark_aqua>", "&3")
.replace("<dark_red>", "&4")
.replace("<dark_purple>", "&5")
.replace("<gold>", "&6")
.replace("<gray>", "&7")
.replace("<dark_gray>", "&8")
.replace("<blue>", "&9")
.replace("<green>", "&a")
.replace("<aqua>", "&b")
.replace("<red>", "&c")
.replace("<light_purple>", "&d")
.replace("<yellow>", "&e")
.replace("<white>", "&f")
.replace("<obfuscated>", "&k")
.replace("<bold>", "&l")
.replace("<strikethrough>", "&m")
.replace("<underlined>", "&n")
.replace("<italic>", "&o")
.replace("<reset>", "&r");
// &#RRGGBB is already in a good format for most plugins
return result;
}
}