package cn.revaria.chatplus.util; #if MC_VER <= MC_1_20 import net.minecraft.text.LiteralTextContent; #else import net.minecraft.text.PlainTextContent.Literal; #endif import net.minecraft.item.ItemStack; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; public class TextStyleFormatter { public static int MAIN_HAND = -1; // Must be smaller than or equal to 0 /** * Processes text styling with two key functions: *

* 1. Replaces {@code &} with {@code §}, using {@code &&} to escape literal {@code &}
* 2. Substitutes {@code [item]} with main-hand item hover text and {@code [item=N]} with Nth slot's hover text *

* Recursively processes nested text components. * * @param sourceText Original text to process (supports nested text components) * @param sourcePlayer Player used for item stack references * @return Processed text with styling and item hover elements */ public static MutableText applyStyle(Text sourceText, ServerPlayerEntity sourcePlayer) { MutableText sourceMutableText = sourceText.copy(); MutableText finalText = Text.empty().setStyle(sourceMutableText.getStyle()); if (sourceText.getContent() instanceof #if MC_VER <= MC_1_20 LiteralTextContent #else Literal #endif plainTextContent) { String changedMessage = plainTextContent.string() .replace('&', '§') .replace("§§", "&"); String regex = "\\[item(?:=([1-9]))?\\]"; String[] messages = changedMessage.split(regex, -1); Deque itemDeque = new ArrayDeque<>(); Matcher matcher = Pattern.compile(regex).matcher(changedMessage); while (matcher.find()) { String digit = matcher.group(1); if (digit == null) { itemDeque.addLast(MAIN_HAND); } else { itemDeque.addLast(Integer.parseInt(digit)); } } for (String message : messages) { finalText.append(Text.literal(message)); if (!itemDeque.isEmpty()) { ItemStack itemStack; if (itemDeque.getFirst() == MAIN_HAND) { itemStack = sourcePlayer.getMainHandStack(); } else { itemStack = sourcePlayer.getInventory().getStack(itemDeque.getFirst() - 1); } finalText.append(itemStack.toHoverableText()); itemDeque.removeFirst(); } } } List sourceTexts = sourceMutableText.getSiblings(); for (Text text : sourceTexts) { finalText.append(applyStyle(text, sourcePlayer)); } return finalText; } /** * Simple style application that only replaces color codes. * Used for anvil renaming where [item] tags are not appropriate. * * @param text The text to format * @return Formatted text with § color codes */ public static String applySimpleStyle(String text) { if (text == null) return null; return text.replace('&', '§').replace("§§", "&"); } }