Improve legacy format serialization more

This should now complete legacy serialization to avoid ever
changing the output content.

This removes the concept of "Default Color" from the method as
that entire concept was flawed and broke the intent of chat components.

Going to actually PR this patch to Spigot soon.

This now puts us back at a point where any data saved pre Spigot
breaking things will still save back the exact same way as before,

but new component -> legacy will now be fixed to not insert undesirable
default colors (such as black) into the legacy string, and instead use
the proper reset code.

This means you can now safety get the text from a book and
put it in chat or an entity display name without worry about black
color codes or other undesired color codes leaking into the new
context where that color doesn't make sense.
This commit is contained in:
Aikar 2020-05-31 22:10:49 -04:00
parent d6eda567ff
commit d7cfa4fa5c
No known key found for this signature in database
GPG key ID: 401ADFC9891FAAFE

View file

@ -1,6 +1,6 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wea_ondara <wea_ondara@alpenblock.net>
Date: Sat, 2 Nov 2019 22:25:40 +0100
From: Aikar <aikar@aikar.co>
Date: Sun, 31 May 2020 21:55:52 -0400
Subject: [PATCH] Fix serialization of colors from components
This patch fixes the serialization of display names, item lores and
@ -13,8 +13,11 @@ saving an ItemStack in a Yaml config).
Spigot has now made the issue worse and expanded the scope to more places.
Original work by (but impl pretty much fully changed):
Co-Authored-By: wea_ondara <wea_ondara@alpenblock.net>
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java
index 2e162b9ea31c8bf81cfa5282566b37fc29537f51..e2fbbfdd5b678f632ddbd68ec33a7cd9adfd4955 100644
index 2e162b9ea31c8bf81cfa5282566b37fc29537f51..7edb88d515e3dab0d81b8f7a545ab614b4b51489 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java
@@ -67,7 +67,7 @@ public final class CraftChatMessage {
@ -26,35 +29,43 @@ index 2e162b9ea31c8bf81cfa5282566b37fc29537f51..e2fbbfdd5b678f632ddbd68ec33a7cd9
} else if (format.isFormat()) {
switch (format) {
case BOLD:
@@ -172,9 +172,26 @@ public final class CraftChatMessage {
@@ -94,7 +94,11 @@ public final class CraftChatMessage {
break;
case 2:
if (keepNewlines) {
- currentChatComponent.addSibling(new ChatComponentText("\n"));
+ // Paper start - retain formatting for new lines
+ ChatComponentText ichatbasecomponent = new ChatComponentText("\n");
+ ichatbasecomponent.setChatModifier(modifier.clone());
+ currentChatComponent.addSibling(ichatbasecomponent);
+ // Paper end
} else {
currentChatComponent = null;
}
@@ -172,9 +176,21 @@ public final class CraftChatMessage {
if (component == null) return "";
StringBuilder out = new StringBuilder();
+ // Paper start - fix deletion of color codes at the beginning of result string
+ boolean first = true;
+ boolean hadColor = false;
for (IChatBaseComponent c : (Iterable<IChatBaseComponent>) component) {
ChatModifier modi = c.getChatModifier();
- out.append(modi.getColor() == null ? defaultColor : modi.getColor());
+ EnumChatFormat color = modi.getColor();
+ if (first) {
+ if (!c.getText().isEmpty() || color != null) {
+ if (color != null) {
+ out.append(color);
+ }
+ if (!c.getText().isEmpty() || color != null) {
+ first = false;
+ }
+ } else if (!c.getText().isEmpty() || color != null) {
+ if (color != null) {
+ out.append(color);
+ } else if (defaultColor != null) {
+ out.append(defaultColor);
+ hadColor = true;
+ } else if (hadColor) {
+ out.append(ChatColor.RESET);
+ hadColor = false;
+ }
+ }
+ // Paper end
if (modi.isBold()) {
out.append(EnumChatFormat.BOLD);
}
@@ -192,7 +209,7 @@ public final class CraftChatMessage {
@@ -192,7 +208,7 @@ public final class CraftChatMessage {
}
out.append(c.getText());
}
@ -65,15 +76,13 @@ index 2e162b9ea31c8bf81cfa5282566b37fc29537f51..e2fbbfdd5b678f632ddbd68ec33a7cd9
public static IChatBaseComponent fixComponent(IChatBaseComponent component) {
diff --git a/src/test/java/org/bukkit/craftbukkit/CraftChatMessageTest.java b/src/test/java/org/bukkit/craftbukkit/CraftChatMessageTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a3b3ef168415ec8813afaa9f0c1657b078f8bf4
index 0000000000000000000000000000000000000000..759049174d2113837aa06faea82ddcc683b4d9c6
--- /dev/null
+++ b/src/test/java/org/bukkit/craftbukkit/CraftChatMessageTest.java
@@ -0,0 +1,56 @@
@@ -0,0 +1,61 @@
+package org.bukkit.craftbukkit;
+
+import net.minecraft.server.EnumChatFormat;
+import net.minecraft.server.IChatBaseComponent;
+import org.bukkit.ChatColor;
+import org.bukkit.craftbukkit.util.CraftChatMessage;
+import org.bukkit.support.AbstractTestingBase;
+import org.junit.Test;
@ -83,21 +92,25 @@ index 0000000000000000000000000000000000000000..4a3b3ef168415ec8813afaa9f0c1657b
+public class CraftChatMessageTest extends AbstractTestingBase {
+ @Test
+ public void testSimpleStrings() {
+ testString("&fFoo", EnumChatFormat.WHITE);
+ testString("Foo", EnumChatFormat.WHITE);
+ testString("Foo&bBar", EnumChatFormat.WHITE);
+ testString("Foo&bBar", EnumChatFormat.AQUA);
+ testString("&fFoo&bBar", EnumChatFormat.WHITE);
+ testString("&rFoo", EnumChatFormat.WHITE);
+ testString("§fFoo");
+ testString("Foo");
+ testString("Foo§bBar");
+ testString("Foo§bBar");
+ testString("§fFoo§bBar");
+ testString("§fFoo§bBar§rBaz");
+ testString("§rFoo");
+ testString("Test§0\n§0\n§5Test");
+ }
+
+ @Test
+ public void testComponents() {
+ testComponent("Foo&bBar&fBaz", EnumChatFormat.WHITE, create("Foo", "&bBar", "Baz"));
+ testComponent("&fFoo&bBar&fBaz", EnumChatFormat.WHITE, create("", "&fFoo", "&bBar", "Baz"));
+ testComponent("Foo&bBar&fBaz", EnumChatFormat.WHITE, create("", "Foo", "&bBar", "Baz"));
+ testComponent("&fFoo&bBar&fBaz", EnumChatFormat.WHITE, create("&fFoo", "&bBar", "Baz"));
+ testComponent("F&foo&bBar&fBaz", EnumChatFormat.WHITE, create("F&foo", "&bBar", "Baz"));
+ testComponent("Foo§bBar§rBaz", create("Foo", "§bBar", "Baz"));
+ testComponent("§fFoo§bBar§rBaz", create("", "§fFoo", "§bBar", "Baz"));
+ testComponent("§fFoo§bBar§rBaz", create("", "§fFoo", "§bBar", "", "Baz"));
+ testComponent("§fFoo§bBar§rBaz", create("§fFoo", "§bBar", "Baz"));
+ testComponent("Foo§bBar§rBaz", create("", "Foo", "§bBar", "Baz"));
+ testComponent("§fFoo§bBar§rBaz", create("§fFoo", "§bBar", "Baz"));
+ testComponent("F§foo§bBar§rBaz", create("F§foo", "§bBar", "Baz"));
+ }
+
+ private IChatBaseComponent create(String txt, String ...rest) {
@ -110,18 +123,21 @@ index 0000000000000000000000000000000000000000..4a3b3ef168415ec8813afaa9f0c1657b
+ }
+
+ private IChatBaseComponent toComp(String txt) {
+ return CraftChatMessage.fromString(ChatColor.translateAlternateColorCodes('&', txt))[0];
+ return CraftChatMessage.fromString(txt, true)[0];
+ }
+
+ private void testString(String expected, EnumChatFormat defColor) {
+ expected = ChatColor.translateAlternateColorCodes('&', expected);
+ IChatBaseComponent cmp = CraftChatMessage.fromStringOrNull(expected);
+ testComponent(expected, defColor, cmp);
+ }
+
+ private void testComponent(String expected, EnumChatFormat defColor, IChatBaseComponent components) {
+ expected = ChatColor.translateAlternateColorCodes('&', expected);
+ String actual = CraftChatMessage.fromComponent(components, defColor);
+ private void testString(String expected) {
+ IChatBaseComponent cmp = toComp(expected);
+ String actual = CraftChatMessage.fromComponent(cmp);
+ assertEquals(expected, actual);
+ }
+
+ private void testComponent(String expected, IChatBaseComponent components) {
+ String actual = CraftChatMessage.fromComponent(components);
+ assertEquals(expected, actual);
+
+ IChatBaseComponent expectedCmp = toComp(expected);
+ String actualExpectedCmp = CraftChatMessage.fromComponent(expectedCmp);
+ assertEquals(expected, actualExpectedCmp);
+ }
+}