From 72c8448e379005a87dad1f39ccc5551ae78e7c96 Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 11 Oct 2026 10:27:24 -0600 Subject: [PATCH 01/10] Hide formatting boundary guards after final dialog text parsing --- .../com/bencodez/simpleapi/dialog/DialogTextFormatter.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/DialogTextFormatter.java b/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/DialogTextFormatter.java index c0ac3e10..0d3ea897 100644 --- a/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/DialogTextFormatter.java +++ b/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/DialogTextFormatter.java @@ -29,6 +29,9 @@ public static String format(Player player, String text, HashMap String formatted = text; - return MessageAPI.colorize(MessageAPI.replacePlaceHolder(formatted, placeholders, true)); + // Keep WORD JOINER guards through placeholder/color parsing, then remove them + // at this final dialog-text sink so unsupported Minecraft glyphs never show. + return MessageAPI.colorize(MessageAPI.replacePlaceHolder(formatted, placeholders, true)) + .replace("\u2060", ""); } } \ No newline at end of file From e554d202af69ef20e9a0391e3c198b4113531d3d Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 11 Oct 2026 10:27:42 -0600 Subject: [PATCH 02/10] Test visible dialog labels and protected formatting boundaries --- .../dialog/DialogTextFormatterTest.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 SimpleAPI/src/test/java/com/bencodez/simpleapi/dialog/DialogTextFormatterTest.java diff --git a/SimpleAPI/src/test/java/com/bencodez/simpleapi/dialog/DialogTextFormatterTest.java b/SimpleAPI/src/test/java/com/bencodez/simpleapi/dialog/DialogTextFormatterTest.java new file mode 100644 index 00000000..a7fb3859 --- /dev/null +++ b/SimpleAPI/src/test/java/com/bencodez/simpleapi/dialog/DialogTextFormatterTest.java @@ -0,0 +1,43 @@ +package com.bencodez.simpleapi.dialog; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + +import java.util.HashMap; + +import org.junit.jupiter.api.Test; + +class DialogTextFormatterTest { + + @Test + void stripsInertMarkersAfterFormattingSiteNames() { + HashMap values = new HashMap<>(); + values.put("site", "\u2060Minecraft Menu\u2060"); + + String result = DialogTextFormatter.format(null, "&7Site: &e%site%", values); + + assertEquals("\u00A77Site: \u00A7eMinecraft Menu", result); + assertFalse(result.contains("\u2060")); + } + + @Test + void boundariesStillBlockColorsFormedAcrossPlaceholderEdges() { + HashMap values = new HashMap<>(); + values.put("site", "\u2060a\u2060"); + + // Without the guards, a trailing & in the trusted template would + // become a Minecraft color code before the message is sent. + assertEquals("&a", DialogTextFormatter.format(null, "&%site%", values)); + assertEquals("\u00A7a", DialogTextFormatter.format(null, "&%site%", + new HashMap<>(java.util.Map.of("site", "a")))); + } + + @Test + void guardedNestedPlaceholderRemainsLiteralText() { + HashMap values = new HashMap<>(); + values.put("site", "\u2060%\u2060player_name%\u2060"); + values.put("player_name", "NotTheSite"); + + assertEquals("%player_name%", DialogTextFormatter.format(null, "%site%", values)); + } +} From 73af37895b72d6abdf253e68d9d9d4f08f4c6c4b Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 11 Oct 2026 10:29:14 -0600 Subject: [PATCH 03/10] Remove inert boundary glyphs from finalized action-bar components --- .../messages/actionbar/ActionBarManager.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/SimpleAPI/src/main/java/com/bencodez/simpleapi/messages/actionbar/ActionBarManager.java b/SimpleAPI/src/main/java/com/bencodez/simpleapi/messages/actionbar/ActionBarManager.java index 83026bc5..dcf29d91 100644 --- a/SimpleAPI/src/main/java/com/bencodez/simpleapi/messages/actionbar/ActionBarManager.java +++ b/SimpleAPI/src/main/java/com/bencodez/simpleapi/messages/actionbar/ActionBarManager.java @@ -297,6 +297,15 @@ protected boolean canReplace(ActionBarEntry current, ActionBarMessage nextMessag */ @SuppressWarnings("deprecation") protected void sendNow(Player player, String message) { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message)); + // Parse legacy styling while the inert boundaries still separate + // untrusted text from formatting tokens. Remove them only from the + // finished components, after parsing can no longer be influenced. + net.md_5.bungee.api.chat.BaseComponent[] rendered = TextComponent.fromLegacyText(message); + for (net.md_5.bungee.api.chat.BaseComponent component : rendered) { + if (component instanceof TextComponent text) { + text.setText(text.getText().replace("\u2060", "")); + } + } + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, rendered); } } \ No newline at end of file From f8c305daa26675ada6b444d75a33f005e83176e5 Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 11 Oct 2026 10:41:28 -0600 Subject: [PATCH 04/10] Keep inert boundaries until UniDialog finishes component parsing --- .../bencodez/simpleapi/dialog/DialogTextFormatter.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/DialogTextFormatter.java b/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/DialogTextFormatter.java index 0d3ea897..be5f95e3 100644 --- a/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/DialogTextFormatter.java +++ b/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/DialogTextFormatter.java @@ -29,9 +29,9 @@ public static String format(Player player, String text, HashMap String formatted = text; - // Keep WORD JOINER guards through placeholder/color parsing, then remove them - // at this final dialog-text sink so unsupported Minecraft glyphs never show. - return MessageAPI.colorize(MessageAPI.replacePlaceHolder(formatted, placeholders, true)) - .replace("\u2060", ""); + // UniDialog deserializes legacy color codes again. Preserve all inert + // boundaries until that last component conversion, then strip them from + // the already-parsed component instead of exposing active color syntax. + return MessageAPI.colorize(MessageAPI.replacePlaceHolder(formatted, placeholders, true)); } } \ No newline at end of file From 26f76b6ee1120df65e3175d4f01787d338bed773 Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 11 Oct 2026 10:42:02 -0600 Subject: [PATCH 05/10] Parse Spigot dialog components before removing inert vote site guards --- .../dialog/SpigotUniDialogPlatform.java | 62 +++++++++++++------ 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/SpigotUniDialogPlatform.java b/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/SpigotUniDialogPlatform.java index 4bafd009..c3b796d5 100644 --- a/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/SpigotUniDialogPlatform.java +++ b/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/SpigotUniDialogPlatform.java @@ -12,6 +12,8 @@ import io.github.projectunified.unidialog.core.payload.DialogPayload; import io.github.projectunified.unidialog.spigot.SpigotDialogManager; import io.github.projectunified.unidialog.spigot.opener.SpigotDialogOpener; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; /** * Spigot implementation using UniDialog's Spigot manager. @@ -69,13 +71,13 @@ public void showNotice(Player player, UniDialogNoticeRequest request) { registerCustomAction(namespace, actionId, request.getCallback()); } - BungeeNoticeDialog dialog = manager.createNoticeDialog().title(request.getTitle()) - .body(builder -> builder.text().text(request.getBody())); + BungeeNoticeDialog dialog = manager.createNoticeDialog().title(renderedText(request.getTitle())) + .body(builder -> builder.text().text(renderedText(request.getBody()))); applyInputs(dialog, request.getInputs()); dialog.action(action -> { - action.label(request.getButtonText()); + action.label(renderedText(request.getButtonText())); action.dynamicCustom(namespace, actionId); }); @@ -97,17 +99,17 @@ public void showConfirmation(Player player, UniDialogConfirmationRequest request } BungeeConfirmationDialog dialog = manager.createConfirmationDialog() - .title(request.getTitle()).body(builder -> builder.text().text(request.getBody())); + .title(renderedText(request.getTitle())).body(builder -> builder.text().text(renderedText(request.getBody()))); applyInputs(dialog, request.getInputs()); dialog.yesAction(action -> { - action.label(request.getYesText()); + action.label(renderedText(request.getYesText())); action.dynamicCustom(namespace, yesActionId); }); dialog.noAction(action -> { - action.label(request.getNoText()); + action.label(renderedText(request.getNoText())); action.dynamicCustom(namespace, noActionId); }); @@ -118,8 +120,8 @@ public void showConfirmation(Player player, UniDialogConfirmationRequest request public void showMultiAction(Player player, UniDialogMultiActionRequest request) { String namespace = resolveNamespace(request.getNamespace()); - BungeeMultiActionDialog dialog = manager.createMultiActionDialog().title(request.getTitle()) - .body(builder -> builder.text().text(request.getBody())).columns(request.getColumns()); + BungeeMultiActionDialog dialog = manager.createMultiActionDialog().title(renderedText(request.getTitle())) + .body(builder -> builder.text().text(renderedText(request.getBody()))).columns(request.getColumns()); applyInputs(dialog, request.getInputs()); @@ -131,10 +133,10 @@ public void showMultiAction(Player player, UniDialogMultiActionRequest request) } dialog.action(action -> { - action.label(button.getText()); + action.label(renderedText(button.getText())); if (button.getTooltip() != null && !button.getTooltip().isEmpty()) { - action.tooltip(button.getTooltip()); + action.tooltip(renderedText(button.getTooltip())); } Integer width = button.getWidth(); @@ -190,13 +192,13 @@ private void applyInput(BungeeNoticeDialog dialog, UniDialog dialog.input(input.getId(), builder -> { if (input.getType() == UniDialogInput.InputType.BOOLEAN) { - builder.booleanInput().label(getInputLabel(input)).initial(input.isInitialBoolean()); + builder.booleanInput().label(renderedText(getInputLabel(input))).initial(input.isInitialBoolean()); } else { String initial = getInputInitial(input); if (initial != null && !initial.isEmpty()) { - builder.textInput().label(getInputLabel(input)).initial(initial); + builder.textInput().label(renderedText(getInputLabel(input))).initial(initial); } else { - builder.textInput().label(getInputLabel(input)); + builder.textInput().label(renderedText(getInputLabel(input))); } } }); @@ -209,13 +211,13 @@ private void applyInput(BungeeConfirmationDialog dialog, Uni dialog.input(input.getId(), builder -> { if (input.getType() == UniDialogInput.InputType.BOOLEAN) { - builder.booleanInput().label(getInputLabel(input)).initial(input.isInitialBoolean()); + builder.booleanInput().label(renderedText(getInputLabel(input))).initial(input.isInitialBoolean()); } else { String initial = getInputInitial(input); if (initial != null && !initial.isEmpty()) { - builder.textInput().label(getInputLabel(input)).initial(initial); + builder.textInput().label(renderedText(getInputLabel(input))).initial(initial); } else { - builder.textInput().label(getInputLabel(input)); + builder.textInput().label(renderedText(getInputLabel(input))); } } }); @@ -228,13 +230,13 @@ private void applyInput(BungeeMultiActionDialog dialog, UniD dialog.input(input.getId(), builder -> { if (input.getType() == UniDialogInput.InputType.BOOLEAN) { - builder.booleanInput().label(getInputLabel(input)).initial(input.isInitialBoolean()); + builder.booleanInput().label(renderedText(getInputLabel(input))).initial(input.isInitialBoolean()); } else { String initial = getInputInitial(input); if (initial != null && !initial.isEmpty()) { - builder.textInput().label(getInputLabel(input)).initial(initial); + builder.textInput().label(renderedText(getInputLabel(input))).initial(initial); } else { - builder.textInput().label(getInputLabel(input)); + builder.textInput().label(renderedText(getInputLabel(input))); } } }); @@ -250,7 +252,27 @@ private String getInputLabel(UniDialogInput input) { return label; } + /** + * UniDialog's Spigot methods deserialize Bungee legacy formatting again. + * Let that final conversion see the inert guards, then drop them from text + * components without reparsing color or click-action syntax. + */ + static TextComponent renderedText(String prepared) { + TextComponent component = TextComponent.fromLegacy(prepared); + stripGuards(component); + return component; + } + + private static void stripGuards(BaseComponent component) { + if (component instanceof TextComponent text) { + text.setText(text.getText().replace("\u2060", "")); + } + if (component.getExtra() != null) { + for (BaseComponent extra : component.getExtra()) stripGuards(extra); + } + } + private String getInputInitial(UniDialogInput input) { - return input.getInitialValue(); + return input.getInitialValue() == null ? null : input.getInitialValue().replace("\u2060", ""); } } From 335c708bb629c837281e05e4a054857d2e7e71bc Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 11 Oct 2026 10:42:18 -0600 Subject: [PATCH 06/10] Strip inert guards after final Paper UniDialog legacy deserialization --- .../dialog/PaperUniDialogPlatform.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/PaperUniDialogPlatform.java b/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/PaperUniDialogPlatform.java index 7809d67b..5b5bb906 100644 --- a/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/PaperUniDialogPlatform.java +++ b/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/PaperUniDialogPlatform.java @@ -12,17 +12,32 @@ import io.github.projectunified.unidialog.paper.dialog.PaperConfirmationDialog; import io.github.projectunified.unidialog.paper.dialog.PaperMultiActionDialog; import io.github.projectunified.unidialog.paper.dialog.PaperNoticeDialog; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextReplacementConfig; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; /** * Paper implementation using UniDialog's Paper manager. */ public class PaperUniDialogPlatform extends AbstractUniDialogPlatform { + private static final TextReplacementConfig HIDE_INERT_GUARDS = TextReplacementConfig.builder() + .matchLiteral("\u2060").replacement("").build(); private final PaperDialogManager manager; public PaperUniDialogPlatform(Plugin plugin, String namespace) { super(plugin, namespace); - this.manager = new PaperDialogManager(plugin, namespace); + this.manager = new PaperDialogManager(plugin, namespace, PaperUniDialogPlatform::renderedText); + } + + /** + * Called by UniDialog at its final component deserialization boundary. + * Deserialize while WORD JOINER guards are present, then remove those + * markers from the component tree, never from another parsable string. + */ + static Component renderedText(String prepared) { + return LegacyComponentSerializer.legacySection().deserialize(prepared) + .replaceText(HIDE_INERT_GUARDS); } @Override @@ -275,6 +290,6 @@ private String getInputLabel(UniDialogInput input) { } private String getInputInitial(UniDialogInput input) { - return input.getInitialValue(); + return input.getInitialValue() == null ? null : input.getInitialValue().replace("\u2060", ""); } } \ No newline at end of file From 64ab17b4c00337bc51449cfc3d9e6eaba4a63c85 Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 11 Oct 2026 10:42:55 -0600 Subject: [PATCH 07/10] Test final UniDialog parsing with protected section-sign and placeholder boundaries --- .../dialog/DialogTextFormatterTest.java | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/SimpleAPI/src/test/java/com/bencodez/simpleapi/dialog/DialogTextFormatterTest.java b/SimpleAPI/src/test/java/com/bencodez/simpleapi/dialog/DialogTextFormatterTest.java index a7fb3859..46f5d1b0 100644 --- a/SimpleAPI/src/test/java/com/bencodez/simpleapi/dialog/DialogTextFormatterTest.java +++ b/SimpleAPI/src/test/java/com/bencodez/simpleapi/dialog/DialogTextFormatterTest.java @@ -2,42 +2,57 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.HashMap; import org.junit.jupiter.api.Test; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; + class DialogTextFormatterTest { @Test - void stripsInertMarkersAfterFormattingSiteNames() { + void removesMarkersOnlyAfterSpigotAndPaperComponentParsing() { HashMap values = new HashMap<>(); values.put("site", "\u2060Minecraft Menu\u2060"); - String result = DialogTextFormatter.format(null, "&7Site: &e%site%", values); - - assertEquals("\u00A77Site: \u00A7eMinecraft Menu", result); - assertFalse(result.contains("\u2060")); + String formatted = DialogTextFormatter.format(null, "&7Site: &e%site%", values); + assertTrue(formatted.contains("\u2060"), "Keep guards through UniDialog's final legacy parser"); + assertEquals("Site: Minecraft Menu", SpigotUniDialogPlatform.renderedText(formatted).toPlainText()); + assertEquals("Site: Minecraft Menu", PlainTextComponentSerializer.plainText() + .serialize(PaperUniDialogPlatform.renderedText(formatted))); } @Test - void boundariesStillBlockColorsFormedAcrossPlaceholderEdges() { + void boundariesProtectBothAmpersandAndSectionSignCodesAcrossSubstitution() { HashMap values = new HashMap<>(); values.put("site", "\u2060a\u2060"); - // Without the guards, a trailing & in the trusted template would - // become a Minecraft color code before the message is sent. - assertEquals("&a", DialogTextFormatter.format(null, "&%site%", values)); - assertEquals("\u00A7a", DialogTextFormatter.format(null, "&%site%", - new HashMap<>(java.util.Map.of("site", "a")))); + // Color code can be formed only if the boundaries are dropped BEFORE + // either parser runs. Verify the finished components still show literal + // text in both legacy serializers, including when a template has §. + String ampersand = DialogTextFormatter.format(null, "&%site%", values); + assertEquals("&a", SpigotUniDialogPlatform.renderedText(ampersand).toPlainText()); + assertEquals("&a", PlainTextComponentSerializer.plainText() + .serialize(PaperUniDialogPlatform.renderedText(ampersand))); + + String section = DialogTextFormatter.format(null, "\u00A7%site%", values); + assertEquals("\u00A7a", SpigotUniDialogPlatform.renderedText(section).toPlainText()); + assertEquals("\u00A7a", PlainTextComponentSerializer.plainText() + .serialize(PaperUniDialogPlatform.renderedText(section))); } @Test - void guardedNestedPlaceholderRemainsLiteralText() { + void nestedPlaceholderNeverResolvesFromGuardedSiteName() { HashMap values = new HashMap<>(); values.put("site", "\u2060%\u2060player_name%\u2060"); values.put("player_name", "NotTheSite"); - assertEquals("%player_name%", DialogTextFormatter.format(null, "%site%", values)); + String formatted = DialogTextFormatter.format(null, "%site%", values); + assertFalse(formatted.contains("NotTheSite")); + assertEquals("%player_name%", SpigotUniDialogPlatform.renderedText(formatted).toPlainText()); + assertEquals("%player_name%", PlainTextComponentSerializer.plainText() + .serialize(PaperUniDialogPlatform.renderedText(formatted))); } } From 35404f70a0b2af249c236750c104fdd485da5039 Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 11 Oct 2026 10:43:43 -0600 Subject: [PATCH 08/10] Use Bungee BaseComponent return type for parsed Spigot dialog text --- .../bencodez/simpleapi/dialog/SpigotUniDialogPlatform.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/SpigotUniDialogPlatform.java b/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/SpigotUniDialogPlatform.java index c3b796d5..36afc096 100644 --- a/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/SpigotUniDialogPlatform.java +++ b/SimpleAPI/src/main/java/com/bencodez/simpleapi/dialog/SpigotUniDialogPlatform.java @@ -257,8 +257,8 @@ private String getInputLabel(UniDialogInput input) { * Let that final conversion see the inert guards, then drop them from text * components without reparsing color or click-action syntax. */ - static TextComponent renderedText(String prepared) { - TextComponent component = TextComponent.fromLegacy(prepared); + static BaseComponent renderedText(String prepared) { + BaseComponent component = TextComponent.fromLegacy(prepared); stripGuards(component); return component; } From 06ab158e577e90999b71bbfcc5946e49a41b6362 Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 11 Oct 2026 10:47:20 -0600 Subject: [PATCH 09/10] Assert incomplete section codes stay inert across both UniDialog parsers --- .../simpleapi/dialog/DialogTextFormatterTest.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/SimpleAPI/src/test/java/com/bencodez/simpleapi/dialog/DialogTextFormatterTest.java b/SimpleAPI/src/test/java/com/bencodez/simpleapi/dialog/DialogTextFormatterTest.java index 46f5d1b0..09de82f4 100644 --- a/SimpleAPI/src/test/java/com/bencodez/simpleapi/dialog/DialogTextFormatterTest.java +++ b/SimpleAPI/src/test/java/com/bencodez/simpleapi/dialog/DialogTextFormatterTest.java @@ -38,9 +38,15 @@ void boundariesProtectBothAmpersandAndSectionSignCodesAcrossSubstitution() { .serialize(PaperUniDialogPlatform.renderedText(ampersand))); String section = DialogTextFormatter.format(null, "\u00A7%site%", values); - assertEquals("\u00A7a", SpigotUniDialogPlatform.renderedText(section).toPlainText()); - assertEquals("\u00A7a", PlainTextComponentSerializer.plainText() - .serialize(PaperUniDialogPlatform.renderedText(section))); + // A legacy parser may drop the isolated invalid § character, but + // the site name must remain text, not turn into a green color token. + var spigot = SpigotUniDialogPlatform.renderedText(section); + var paper = PaperUniDialogPlatform.renderedText(section); + assertTrue(spigot.toPlainText().endsWith("a")); + assertTrue(PlainTextComponentSerializer.plainText().serialize(paper).endsWith("a")); + assertFalse(spigot.toLegacyText().contains("\u00A7a")); + assertFalse(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection() + .serialize(paper).contains("\u00A7a")); } @Test From 15431521e5c73e83e976d2a39dd912ba44efb7f1 Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 11 Oct 2026 10:50:54 -0600 Subject: [PATCH 10/10] Check actual Paper component style rather than lossy legacy reserialization --- .../bencodez/simpleapi/dialog/DialogTextFormatterTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/SimpleAPI/src/test/java/com/bencodez/simpleapi/dialog/DialogTextFormatterTest.java b/SimpleAPI/src/test/java/com/bencodez/simpleapi/dialog/DialogTextFormatterTest.java index 09de82f4..194b09f5 100644 --- a/SimpleAPI/src/test/java/com/bencodez/simpleapi/dialog/DialogTextFormatterTest.java +++ b/SimpleAPI/src/test/java/com/bencodez/simpleapi/dialog/DialogTextFormatterTest.java @@ -45,8 +45,10 @@ void boundariesProtectBothAmpersandAndSectionSignCodesAcrossSubstitution() { assertTrue(spigot.toPlainText().endsWith("a")); assertTrue(PlainTextComponentSerializer.plainText().serialize(paper).endsWith("a")); assertFalse(spigot.toLegacyText().contains("\u00A7a")); - assertFalse(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection() - .serialize(paper).contains("\u00A7a")); + // Re-serializing a literal § followed by 'a' to a legacy String can + // produce an ambiguous §a sequence; check the actual component style. + org.junit.jupiter.api.Assertions.assertNotEquals( + net.kyori.adventure.text.format.NamedTextColor.GREEN, paper.color()); } @Test