ChatPlus/src/main/java/cn/revaria/chatplus/util/TextStyleFormatter.java
2026-01-08 16:58:26 +08:00

93 lines
2.9 KiB
Java

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:
* <p>
* 1. Replaces {@code &} with {@code §}, using {@code &&} to escape literal {@code &}<br>
* 2. Substitutes {@code [item]} with main-hand item hover text and {@code [item=N]} with Nth slot's hover text
* </p>
* 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<Integer> 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<Text> 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("§§", "&");
}
}