feat: 支持配置 MiniMessage 文本
This commit is contained in:
217
docs/superpowers/plans/2026-06-14-minimessage-config.md
Normal file
217
docs/superpowers/plans/2026-06-14-minimessage-config.md
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
# MiniMessage Config Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** Let player-visible configuration text support MiniMessage while keeping existing legacy `&` and `#RRGGBB` formatting compatible.
|
||||||
|
|
||||||
|
**Architecture:** Keep `ColorUtil` as the single text-formatting boundary. Add Adventure text serializers there, return legacy `String` values to preserve current command, quest, reward, and API signatures.
|
||||||
|
|
||||||
|
**Tech Stack:** Java 21, Maven, Paper API Adventure classes, JUnit 5 for utility tests.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
- Modify `pom.xml`: add test dependencies for JUnit 5 and Surefire so Maven can run unit tests.
|
||||||
|
- Create `src/test/java/com/io/yaohun/questengine/util/ColorUtilTest.java`: focused tests for legacy compatibility and MiniMessage parsing.
|
||||||
|
- Modify `src/main/java/com/io/yaohun/questengine/util/ColorUtil.java`: implement MiniMessage parsing while retaining legacy output.
|
||||||
|
|
||||||
|
### Task 1: Add ColorUtil Regression Tests
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `pom.xml`
|
||||||
|
- Create: `src/test/java/com/io/yaohun/questengine/util/ColorUtilTest.java`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Add JUnit test dependencies**
|
||||||
|
|
||||||
|
Add these dependencies under `<dependencies>` in `pom.xml`:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter</artifactId>
|
||||||
|
<version>5.10.3</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
Add this plugin under `<plugins>` in `pom.xml`:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>3.2.5</version>
|
||||||
|
</plugin>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Write failing tests**
|
||||||
|
|
||||||
|
Create `src/test/java/com/io/yaohun/questengine/util/ColorUtilTest.java`:
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.io.yaohun.questengine.util;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
class ColorUtilTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void colorKeepsLegacyAmpersandFormatting() {
|
||||||
|
assertEquals("§a任务 §f完成", ColorUtil.color("&a任务 &f完成"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void colorKeepsLegacyHexFormatting() {
|
||||||
|
assertEquals("§x§1§2§3§4§5§6任务", ColorUtil.color("#123456任务"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void colorSupportsMiniMessageNamedColors() {
|
||||||
|
assertEquals("§a任务", ColorUtil.color("<green>任务</green>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void colorSupportsMiniMessageDecorations() {
|
||||||
|
assertEquals("§l加粗", ColorUtil.color("<bold>加粗</bold>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void colorParsesEveryListEntry() {
|
||||||
|
assertEquals(
|
||||||
|
List.of("§a领取", "§c完成"),
|
||||||
|
ColorUtil.color(List.of("<green>领取</green>", "&c完成"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Run tests to verify RED**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mvn -q -Dtest=ColorUtilTest test
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: tests compile, legacy tests pass, MiniMessage tests fail because tags are not parsed yet.
|
||||||
|
|
||||||
|
### Task 2: Implement MiniMessage Support
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `src/main/java/com/io/yaohun/questengine/util/ColorUtil.java`
|
||||||
|
- Test: `src/test/java/com/io/yaohun/questengine/util/ColorUtilTest.java`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Replace ColorUtil implementation**
|
||||||
|
|
||||||
|
Update `ColorUtil.java` to:
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.io.yaohun.questengine.util;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class ColorUtil {
|
||||||
|
|
||||||
|
private static final Pattern HEX_PATTERN = Pattern.compile("#[a-fA-F0-9]{6}");
|
||||||
|
private static final MiniMessage MINI_MESSAGE = MiniMessage.miniMessage();
|
||||||
|
private static final LegacyComponentSerializer LEGACY_SERIALIZER = LegacyComponentSerializer.legacySection();
|
||||||
|
|
||||||
|
public static String color(String text) {
|
||||||
|
if (text == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String legacyText = translateLegacyColors(text);
|
||||||
|
Component component = MINI_MESSAGE.deserialize(legacyText);
|
||||||
|
return LEGACY_SERIALIZER.serialize(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> color(List<String> list) {
|
||||||
|
return list.stream().map(ColorUtil::color).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String translateLegacyColors(String text) {
|
||||||
|
Matcher matcher = HEX_PATTERN.matcher(text);
|
||||||
|
while (matcher.find()) {
|
||||||
|
String hexCode = text.substring(matcher.start(), matcher.end());
|
||||||
|
String replaceSharp = hexCode.replace('#', 'x');
|
||||||
|
char[] ch = replaceSharp.toCharArray();
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for (char c : ch) {
|
||||||
|
builder.append("&").append(c);
|
||||||
|
}
|
||||||
|
text = text.replace(hexCode, builder.toString());
|
||||||
|
matcher = HEX_PATTERN.matcher(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Run focused tests to verify GREEN**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mvn -q -Dtest=ColorUtilTest test
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: all `ColorUtilTest` tests pass.
|
||||||
|
|
||||||
|
### Task 3: Verify Plugin Build
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Verify: full project
|
||||||
|
|
||||||
|
- [ ] **Step 1: Run full test suite**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mvn test
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: build succeeds and `ColorUtilTest` passes.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Run compile**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mvn compile
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: production code compiles.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Review changed files**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git diff --check
|
||||||
|
git status --short
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: no whitespace errors; only planned files are modified or added.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Commit implementation**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add pom.xml src/main/java/com/io/yaohun/questengine/util/ColorUtil.java src/test/java/com/io/yaohun/questengine/util/ColorUtilTest.java docs/superpowers/plans/2026-06-14-minimessage-config.md
|
||||||
|
git commit -m "feat: 支持配置 MiniMessage 文本"
|
||||||
|
```
|
||||||
11
pom.xml
11
pom.xml
@@ -85,6 +85,12 @@
|
|||||||
<version>3.6.52</version>
|
<version>3.6.52</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter</artifactId>
|
||||||
|
<version>5.10.3</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@@ -124,6 +130,11 @@
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>3.2.5</version>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package com.io.yaohun.questengine.util;
|
package com.io.yaohun.questengine.util;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -10,11 +13,28 @@ import java.util.stream.Collectors;
|
|||||||
public class ColorUtil {
|
public class ColorUtil {
|
||||||
|
|
||||||
private static final Pattern HEX_PATTERN = Pattern.compile("#[a-fA-F0-9]{6}");
|
private static final Pattern HEX_PATTERN = Pattern.compile("#[a-fA-F0-9]{6}");
|
||||||
|
private static final MiniMessage MINI_MESSAGE = MiniMessage.miniMessage();
|
||||||
|
private static final LegacyComponentSerializer LEGACY_SERIALIZER = LegacyComponentSerializer.legacySection();
|
||||||
|
|
||||||
public static String color(String text) {
|
public static String color(String text) {
|
||||||
if (text == null) {
|
if (text == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
if (text.indexOf('§') >= 0) {
|
||||||
|
Component component = LEGACY_SERIALIZER.deserialize(text);
|
||||||
|
return LEGACY_SERIALIZER.serialize(component);
|
||||||
|
}
|
||||||
|
String hexText = translateHexColors(text);
|
||||||
|
Component component = MINI_MESSAGE.deserialize(hexText);
|
||||||
|
String serialized = LEGACY_SERIALIZER.serialize(component);
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', serialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> color(List<String> list) {
|
||||||
|
return list.stream().map(ColorUtil::color).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String translateHexColors(String text) {
|
||||||
Matcher matcher = HEX_PATTERN.matcher(text);
|
Matcher matcher = HEX_PATTERN.matcher(text);
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
String hexCode = text.substring(matcher.start(), matcher.end());
|
String hexCode = text.substring(matcher.start(), matcher.end());
|
||||||
@@ -28,10 +48,6 @@ public class ColorUtil {
|
|||||||
matcher = HEX_PATTERN.matcher(text);
|
matcher = HEX_PATTERN.matcher(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ChatColor.translateAlternateColorCodes('&', text);
|
return text;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public static List<String> color(List<String> list) {
|
|
||||||
return list.stream().map(ColorUtil::color).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.io.yaohun.questengine.util;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
class ColorUtilTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void colorKeepsLegacyAmpersandFormatting() {
|
||||||
|
assertEquals("§a任务 §f完成", ColorUtil.color("&a任务 &f完成"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void colorKeepsLegacyHexFormatting() {
|
||||||
|
assertEquals("§x§1§2§3§4§5§6任务", ColorUtil.color("#123456任务"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void colorSupportsMiniMessageNamedColors() {
|
||||||
|
assertEquals("§a任务", ColorUtil.color("<green>任务</green>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void colorSupportsMiniMessageDecorations() {
|
||||||
|
assertEquals("§l加粗", ColorUtil.color("<bold>加粗</bold>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void colorSupportsMixedMiniMessageAndLegacyFormatting() {
|
||||||
|
assertEquals("§a领取§r §c奖励", ColorUtil.color("<green>领取</green> &c奖励"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void colorCanBeCalledOnAlreadyColoredText() {
|
||||||
|
assertEquals("§a任务", ColorUtil.color(ColorUtil.color("<green>任务</green>")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void colorLeavesUnknownMiniMessageTagsVisible() {
|
||||||
|
assertEquals("<quest>任务</quest>", ColorUtil.color("<quest>任务</quest>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void colorParsesEveryListEntry() {
|
||||||
|
assertEquals(
|
||||||
|
List.of("§a领取", "§c完成"),
|
||||||
|
ColorUtil.color(List.of("<green>领取</green>", "&c完成"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user