diff --git a/src/main/java/com/mcprotector/chat/FactionTextFormatter.java b/src/main/java/com/mcprotector/chat/FactionTextFormatter.java index 997c124..007ad62 100644 --- a/src/main/java/com/mcprotector/chat/FactionTextFormatter.java +++ b/src/main/java/com/mcprotector/chat/FactionTextFormatter.java @@ -2,13 +2,12 @@ import com.mcprotector.config.FactionConfig; import com.mcprotector.data.Faction; -import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; +import net.minecraft.network.chat.TextColor; import net.minecraft.server.level.ServerPlayer; -import java.util.HashMap; -import java.util.Map; - public final class FactionTextFormatter { private FactionTextFormatter() { } @@ -19,33 +18,59 @@ public static Component formatChat(FactionChatMode mode, ServerPlayer sender, Fa case ALLY -> FactionConfig.SERVER.allyChatFormat.get(); case PUBLIC -> FactionConfig.SERVER.publicChatFormat.get(); }; - return Component.literal(applyFormat(format, sender, faction, message)); + return applyFormat(format, sender, faction, message); } public static Component formatTabList(ServerPlayer player, Faction faction) { String format = FactionConfig.SERVER.tabListFormat.get(); - return Component.literal(applyFormat(format, player, faction, "")); + return applyFormat(format, player, faction, ""); } - private static String applyFormat(String format, ServerPlayer sender, Faction faction, String message) { - Map replacements = new HashMap<>(); - String factionColor = faction != null ? faction.getLegacyColorCode() : ChatFormatting.WHITE.toString(); + private static Component applyFormat(String format, ServerPlayer sender, Faction faction, String message) { String factionName = faction != null ? faction.getName() : "NoFaction"; - replacements.put("{faction}", factionColor + factionName + ChatFormatting.RESET); - replacements.put("{player}", sender.getName().getString()); - replacements.put("{message}", ChatFormatting.RESET + message); - replacements.put("{faction_color}", factionColor); - replacements.put("{reset}", ChatFormatting.RESET.toString()); - String role = faction != null ? faction.getRole(sender.getUUID()) : null; - replacements.put("{role}", role != null ? faction.getRoleDisplayName(role) : "Wanderer"); - String result = format; - if (faction != null) { - String coloredBracket = factionColor + "[" + factionName + "]" + ChatFormatting.RESET; - result = result.replace("[{faction}]", coloredBracket); - } - for (Map.Entry entry : replacements.entrySet()) { - result = result.replace(entry.getKey(), entry.getValue()); + String role = faction != null && faction.getRole(sender.getUUID()) != null + ? faction.getRoleDisplayName(faction.getRole(sender.getUUID())) + : "Wanderer"; + String playerName = sender.getName().getString(); + int factionRgb = faction != null ? faction.getColorRgb() : 0xFFFFFF; + Style currentStyle = Style.EMPTY; + MutableComponent result = Component.empty(); + + int index = 0; + while (index < format.length()) { + int start = format.indexOf('{', index); + if (start < 0) { + appendLiteral(result, format.substring(index), currentStyle); + break; + } + if (start > index) { + appendLiteral(result, format.substring(index, start), currentStyle); + } + int end = format.indexOf('}', start); + if (end < 0) { + appendLiteral(result, format.substring(start), currentStyle); + break; + } + String token = format.substring(start, end + 1); + switch (token) { + case "{faction_color}" -> currentStyle = currentStyle.withColor(TextColor.fromRgb(factionRgb)); + case "{reset}" -> currentStyle = Style.EMPTY; + case "{faction}" -> appendLiteral(result, factionName, currentStyle); + case "{player}" -> appendLiteral(result, playerName, currentStyle); + case "{message}" -> appendLiteral(result, message, currentStyle); + case "{role}" -> appendLiteral(result, role, currentStyle); + default -> appendLiteral(result, token, currentStyle); + } + index = end + 1; } + return result; } + + private static void appendLiteral(MutableComponent target, String text, Style style) { + if (text == null || text.isEmpty()) { + return; + } + target.append(Component.literal(text).withStyle(style)); + } } diff --git a/src/main/java/com/mcprotector/client/ClientColorHelper.java b/src/main/java/com/mcprotector/client/ClientColorHelper.java new file mode 100644 index 0000000..320437a --- /dev/null +++ b/src/main/java/com/mcprotector/client/ClientColorHelper.java @@ -0,0 +1,33 @@ +package com.mcprotector.client; + +public final class ClientColorHelper { + private ClientColorHelper() { + } + + /** + * Converts a standard ARGB color value to the color ordering used by client GUI draw calls. + */ + public static int toGuiColor(int argb) { + int alpha = (argb >>> 24) & 0xFF; + int red = (argb >>> 16) & 0xFF; + int green = (argb >>> 8) & 0xFF; + int blue = argb & 0xFF; + return (alpha << 24) | (blue << 16) | (green << 8) | red; + } + + public static float red(int argb) { + return (toGuiColor(argb) & 0xFF) / 255.0f; + } + + public static float green(int argb) { + return ((toGuiColor(argb) >>> 8) & 0xFF) / 255.0f; + } + + public static float blue(int argb) { + return ((toGuiColor(argb) >>> 16) & 0xFF) / 255.0f; + } + + public static float alpha(int argb) { + return ((argb >>> 24) & 0xFF) / 255.0f; + } +} diff --git a/src/main/java/com/mcprotector/client/FactionClaimBorderRenderer.java b/src/main/java/com/mcprotector/client/FactionClaimBorderRenderer.java index 28461d1..f91cfb8 100644 --- a/src/main/java/com/mcprotector/client/FactionClaimBorderRenderer.java +++ b/src/main/java/com/mcprotector/client/FactionClaimBorderRenderer.java @@ -67,10 +67,10 @@ public static void render(RenderLevelStageEvent event) { continue; } int color = resolveClaimColor(entry.getValue()); - float red = ((color >> 16) & 0xFF) / 255.0f; - float green = ((color >> 8) & 0xFF) / 255.0f; - float blue = (color & 0xFF) / 255.0f; - float alpha = (((color >> 24) & 0xFF) / 255.0f) * BORDER_ALPHA; + float red = ClientColorHelper.red(color); + float green = ClientColorHelper.green(color); + float blue = ClientColorHelper.blue(color); + float alpha = ClientColorHelper.alpha(color) * BORDER_ALPHA; double minX = chunkPos.getMinBlockX(); double maxX = chunkPos.getMaxBlockX() + 1.0; double minZ = chunkPos.getMinBlockZ(); @@ -104,10 +104,10 @@ public static void render(RenderLevelStageEvent event) { continue; } int color = resolveClaimColor(entry.getValue()); - float red = ((color >> 16) & 0xFF) / 255.0f; - float green = ((color >> 8) & 0xFF) / 255.0f; - float blue = (color & 0xFF) / 255.0f; - float alpha = (((color >> 24) & 0xFF) / 255.0f) * BORDER_ALPHA; + float red = ClientColorHelper.red(color); + float green = ClientColorHelper.green(color); + float blue = ClientColorHelper.blue(color); + float alpha = ClientColorHelper.alpha(color) * BORDER_ALPHA; double minX = chunkPos.getMinBlockX(); double maxX = chunkPos.getMaxBlockX() + 1.0; double minZ = chunkPos.getMinBlockZ(); diff --git a/src/main/java/com/mcprotector/client/gui/FactionMainScreen.java b/src/main/java/com/mcprotector/client/gui/FactionMainScreen.java index fa9faac..d6b5786 100644 --- a/src/main/java/com/mcprotector/client/gui/FactionMainScreen.java +++ b/src/main/java/com/mcprotector/client/gui/FactionMainScreen.java @@ -7,6 +7,7 @@ import com.mcprotector.network.FactionActionPacket; import com.mcprotector.network.FactionClaimSelectionPacket; import com.mcprotector.network.FactionStatePacket; +import com.mcprotector.client.ClientColorHelper; import com.mcprotector.client.ClientNetworkSender; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; @@ -1101,7 +1102,7 @@ private void renderFactionList(GuiGraphics guiGraphics, label += " - " + faction.relation(); } int color = 0xFF000000 | faction.color(); - guiGraphics.drawString(this.font, label, getPanelLeft(), y, color); + guiGraphics.drawString(this.font, label, getPanelLeft(), y, ClientColorHelper.toGuiColor(color)); y += lineHeight; } renderScrollIndicator(guiGraphics, factions.size(), visibleLines, factionListScrollOffset, listStart, listBottom); diff --git a/src/main/java/com/mcprotector/client/gui/FactionMapRenderer.java b/src/main/java/com/mcprotector/client/gui/FactionMapRenderer.java index 5d68d3e..0e03015 100644 --- a/src/main/java/com/mcprotector/client/gui/FactionMapRenderer.java +++ b/src/main/java/com/mcprotector/client/gui/FactionMapRenderer.java @@ -1,5 +1,6 @@ package com.mcprotector.client.gui; +import com.mcprotector.client.ClientColorHelper; import com.mcprotector.client.FactionMapClientData; import com.mcprotector.client.map.MapBackgroundProvider; import com.mcprotector.client.map.MapBackgroundProviders; @@ -77,11 +78,12 @@ public static void renderMapGrid(GuiGraphics guiGraphics, FactionMapClientData.M if (mapSnapshot.backgroundState() != null && mapSnapshot.backgroundState().enabled()) { color = withAlpha(color, 0xA0); } - guiGraphics.fill(x, y, x + region.cellSize(), y + region.cellSize(), color); + int guiColor = ClientColorHelper.toGuiColor(color); + guiGraphics.fill(x, y, x + region.cellSize(), y + region.cellSize(), guiColor); int halfCell = Math.max(1, region.cellSize() / 2); guiGraphics.fill(x, y, x + halfCell, y + halfCell, 0x18FFFFFF); guiGraphics.fill(x + halfCell, y + halfCell, x + region.cellSize(), y + region.cellSize(), 0x18000000); - int gridColor = shadeColor(color, 0.75f); + int gridColor = shadeColor(guiColor, 0.75f); guiGraphics.renderOutline(x, y, region.cellSize(), region.cellSize(), gridColor); } } diff --git a/src/main/java/com/mcprotector/command/FactionCommands.java b/src/main/java/com/mcprotector/command/FactionCommands.java index 6eb9324..8353aa4 100644 --- a/src/main/java/com/mcprotector/command/FactionCommands.java +++ b/src/main/java/com/mcprotector/command/FactionCommands.java @@ -1034,16 +1034,14 @@ private static int setColor(CommandSourceStack source, String colorName) throws return 0; } String normalized = FactionConfig.normalizeColorInput(colorName); - ChatFormatting named = ChatFormatting.getByName(normalized); - boolean validNamed = named != null && named.isColor(); boolean validHex = FactionConfig.isHexColor(normalized); - if (!validNamed && !validHex) { - source.sendFailure(Component.literal("Unknown color. Use a vanilla color name or hex format (#RRGGBB).")); + if (!validHex) { + source.sendFailure(Component.literal("Unknown color. Use hex format only (#RRGGBB).")); return 0; } - faction.get().setColorName(normalized); + faction.get().setColorName("#" + (normalized.startsWith("#") ? normalized.substring(1) : normalized)); FactionData.get(source.getLevel()).setDirty(); - source.sendSuccess(() -> Component.literal("Faction color updated to " + normalized), true); + source.sendSuccess(() -> Component.literal("Faction color updated to " + faction.get().getColorName()), true); return 1; } diff --git a/src/main/java/com/mcprotector/config/FactionConfig.java b/src/main/java/com/mcprotector/config/FactionConfig.java index 180c0d7..fc00b11 100644 --- a/src/main/java/com/mcprotector/config/FactionConfig.java +++ b/src/main/java/com/mcprotector/config/FactionConfig.java @@ -140,13 +140,27 @@ public static int parseHexColor(String colorName) { } public static int resolveRgbColor(String colorName) { + String normalized = normalizeFactionHexColor(colorName); + if (!isHexColor(normalized)) { + return 0xFFFFFF; + } + return parseHexColor(normalized); + } + + public static String normalizeFactionHexColor(String colorName) { String normalized = normalizeColorInput(colorName); + if (normalized.isEmpty()) { + return "#ffffff"; + } if (isHexColor(normalized)) { - return parseHexColor(normalized); + String hex = normalized.startsWith("#") ? normalized.substring(1) : normalized; + return "#" + hex; + } + ChatFormatting formatting = ChatFormatting.getByName(normalized); + if (formatting != null && formatting.isColor() && formatting.getColor() != null) { + return String.format("#%06x", formatting.getColor()); } - ChatFormatting formatting = parseColor(normalized); - Integer rgb = formatting.getColor(); - return rgb == null ? 0xFFFFFF : rgb; + return "#ffffff"; } public static String toLegacyHexCode(String colorName) { @@ -240,8 +254,8 @@ public static final class Server { private Server(ModConfigSpec.Builder builder) { builder.push("factions"); defaultFactionColor = builder - .comment("Default faction chat color name (e.g. red, gold, blue).") - .define("defaultFactionColor", "gold"); + .comment("Default faction color in hex format (#RRGGBB).") + .define("defaultFactionColor", "#ffd700"); defaultMotd = builder .comment("Default message of the day for new factions.") .define("defaultMotd", "Welcome to the faction!"); diff --git a/src/main/java/com/mcprotector/data/Faction.java b/src/main/java/com/mcprotector/data/Faction.java index e1a0777..6f8e3c2 100644 --- a/src/main/java/com/mcprotector/data/Faction.java +++ b/src/main/java/com/mcprotector/data/Faction.java @@ -213,7 +213,7 @@ public String getLegacyColorCode() { } public void setColorName(String colorName) { - this.colorName = colorName; + this.colorName = FactionConfig.normalizeFactionHexColor(colorName); } public String getMotd() { @@ -267,7 +267,7 @@ public boolean removeRule(String rule) { } private void applyDefaults() { - colorName = FactionConfig.getDefaultColorName(); + colorName = FactionConfig.normalizeFactionHexColor(FactionConfig.getDefaultColorName()); motd = FactionConfig.getDefaultMotd(); description = FactionConfig.getDefaultDescription(); bannerColor = FactionConfig.getDefaultBannerColor(); diff --git a/src/main/java/com/mcprotector/network/FactionClaimMapPacket.java b/src/main/java/com/mcprotector/network/FactionClaimMapPacket.java index 640e73c..87bb5ec 100644 --- a/src/main/java/com/mcprotector/network/FactionClaimMapPacket.java +++ b/src/main/java/com/mcprotector/network/FactionClaimMapPacket.java @@ -222,12 +222,12 @@ private static int resolveClaimColor(boolean safeZone, boolean personal, String if (personal) { return PERSONAL_CLAIM_COLOR; } - return switch (relation) { + return resolveFactionColor(faction).orElseGet(() -> switch (relation) { case "OWN" -> 0xFF4CAF50; case "ALLY" -> 0xFF4FC3F7; case "WAR" -> 0xFFEF5350; - default -> resolveFactionColor(faction).orElse(0xFF8D8D8D); - }; + default -> 0xFF8D8D8D; + }); } private static Optional resolveFactionColor(Optional faction) {