From d7cfa4fa5c428ce17c712771a632d555ec3c7b29 Mon Sep 17 00:00:00 2001 From: Aikar Date: Sun, 31 May 2020 22:10:49 -0400 Subject: [PATCH] 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. --- ...ialization-of-colors-from-components.patch | 98 +++++++++++-------- 1 file changed, 57 insertions(+), 41 deletions(-) diff --git a/Spigot-Server-Patches/0534-Fix-serialization-of-colors-from-components.patch b/Spigot-Server-Patches/0534-Fix-serialization-of-colors-from-components.patch index 0cfae32a7..c3ced2505 100644 --- a/Spigot-Server-Patches/0534-Fix-serialization-of-colors-from-components.patch +++ b/Spigot-Server-Patches/0534-Fix-serialization-of-colors-from-components.patch @@ -1,6 +1,6 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: wea_ondara -Date: Sat, 2 Nov 2019 22:25:40 +0100 +From: Aikar +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 + 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) 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); ++ } +}