diff --git a/patches/server/0950-Improve-tag-parser-handling.patch b/patches/server/0950-Improve-tag-parser-handling.patch index 60b1c1c44a..ba0144b9df 100644 --- a/patches/server/0950-Improve-tag-parser-handling.patch +++ b/patches/server/0950-Improve-tag-parser-handling.patch @@ -109,8 +109,65 @@ index da101bca71f4710812621b98f0a0d8cab180346a..3cd112584accb8e8f050ac99738eed11 + } + } } +diff --git a/src/main/java/net/minecraft/network/chat/ComponentUtils.java b/src/main/java/net/minecraft/network/chat/ComponentUtils.java +index 3365aed2b67ae0e4dd0410f5190ba474f146139b..8b776434a733b91129b089d702b2583b727bf3d2 100644 +--- a/src/main/java/net/minecraft/network/chat/ComponentUtils.java ++++ b/src/main/java/net/minecraft/network/chat/ComponentUtils.java +@@ -33,10 +33,30 @@ public class ComponentUtils { + } + } + ++ @io.papermc.paper.annotation.DoNotUse // Paper - validate separators - right now this method is only used for separator evaluation. Error on build if this changes to re-evaluate. + public static Optional updateForEntity(@Nullable CommandSourceStack source, Optional text, @Nullable Entity sender, int depth) throws CommandSyntaxException { + return text.isPresent() ? Optional.of(updateForEntity(source, text.get(), sender, depth)) : Optional.empty(); + } + ++ // Paper start - validate separator ++ public static Optional updateSeparatorForEntity(@Nullable CommandSourceStack source, Optional text, @Nullable Entity sender, int depth) throws CommandSyntaxException { ++ if (text.isEmpty() || !isValidSelector(text.get())) return Optional.empty(); ++ return Optional.of(updateForEntity(source, text.get(), sender, depth)); ++ } ++ public static boolean isValidSelector(final Component component) { ++ final ComponentContents contents = component.getContents(); ++ ++ if (contents instanceof net.minecraft.network.chat.contents.NbtContents || contents instanceof net.minecraft.network.chat.contents.SelectorContents) return false; ++ if (contents instanceof final net.minecraft.network.chat.contents.TranslatableContents translatableContents) { ++ for (final Object arg : translatableContents.getArgs()) { ++ if (arg instanceof final Component argumentAsComponent && !isValidSelector(argumentAsComponent)) return false; ++ } ++ } ++ ++ return true; ++ } ++ // Paper end - validate separator ++ + public static MutableComponent updateForEntity(@Nullable CommandSourceStack source, Component text, @Nullable Entity sender, int depth) throws CommandSyntaxException { + if (depth > 100) { + return text.copy(); +diff --git a/src/main/java/net/minecraft/network/chat/contents/NbtContents.java b/src/main/java/net/minecraft/network/chat/contents/NbtContents.java +index df26c39a2bb20e2021b50211dce905483a77f4e6..5634122dac8afeecab0cde623e9868d8e865e02a 100644 +--- a/src/main/java/net/minecraft/network/chat/contents/NbtContents.java ++++ b/src/main/java/net/minecraft/network/chat/contents/NbtContents.java +@@ -120,7 +120,7 @@ public class NbtContents implements ComponentContents { + }).map(Tag::getAsString); + if (this.interpreting) { + Component component = DataFixUtils.orElse( +- ComponentUtils.updateForEntity(source, this.separator, sender, depth), ComponentUtils.DEFAULT_NO_STYLE_SEPARATOR ++ ComponentUtils.updateSeparatorForEntity(source, this.separator, sender, depth), ComponentUtils.DEFAULT_NO_STYLE_SEPARATOR // Paper - validate separator + ); + return stream.flatMap(text -> { + try { +@@ -132,7 +132,7 @@ public class NbtContents implements ComponentContents { + } + }).reduce((accumulator, current) -> accumulator.append(component).append(current)).orElseGet(Component::empty); + } else { +- return ComponentUtils.updateForEntity(source, this.separator, sender, depth) ++ return ComponentUtils.updateSeparatorForEntity(source, this.separator, sender, depth) // Paper - validate separator + .map( + text -> stream.map(Component::literal) + .reduce((accumulator, current) -> accumulator.append(text).append(current)) diff --git a/src/main/java/net/minecraft/network/chat/contents/SelectorContents.java b/src/main/java/net/minecraft/network/chat/contents/SelectorContents.java -index 1337853badf8e124aa8439ce33a255bc4164125b..a1869eee2da9b1993b1348ed40ef8fdac092b72a 100644 +index 1337853badf8e124aa8439ce33a255bc4164125b..933388a60eda2af259d4ef761e31c5abb69c31fd 100644 --- a/src/main/java/net/minecraft/network/chat/contents/SelectorContents.java +++ b/src/main/java/net/minecraft/network/chat/contents/SelectorContents.java @@ -50,7 +50,7 @@ public class SelectorContents implements ComponentContents { @@ -122,6 +179,15 @@ index 1337853badf8e124aa8439ce33a255bc4164125b..a1869eee2da9b1993b1348ed40ef8fda } return entitySelector; +@@ -77,7 +77,7 @@ public class SelectorContents implements ComponentContents { + @Override + public MutableComponent resolve(@Nullable CommandSourceStack source, @Nullable Entity sender, int depth) throws CommandSyntaxException { + if (source != null && this.selector != null) { +- Optional optional = ComponentUtils.updateForEntity(source, this.separator, sender, depth); ++ Optional optional = ComponentUtils.updateSeparatorForEntity(source, this.separator, sender, depth); // Paper - validate separator + return ComponentUtils.formatList(this.selector.findEntities(source), optional, Entity::getDisplayName); + } else { + return Component.empty(); diff --git a/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java b/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java index 56e641bc5f6edc657647993ea2efbb7bb9c2f732..4aa6232bf0f72fcde32d257100bd15b1c5192aaa 100644 --- a/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java diff --git a/patches/server/1029-fix-horse-inventories.patch b/patches/server/1029-fix-horse-inventories.patch index ca5b9c08cd..9737a4fa71 100644 --- a/patches/server/1029-fix-horse-inventories.patch +++ b/patches/server/1029-fix-horse-inventories.patch @@ -23,10 +23,10 @@ index 9bcc0931510607b8fbd01233e2b3c346369b214d..467693a60786688b753cebac3b0a8889 // Paper start - Horse API diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAbstractHorse.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAbstractHorse.java -index 4946da593713f4d11d88ac1bb68a089f2f6d5ae0..abef7f23361e6c5d18243dd18439ffd13ac787ae 100644 +index 4946da593713f4d11d88ac1bb68a089f2f6d5ae0..54e81472259dc13dfc7b2af6b211628c39435890 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAbstractHorse.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAbstractHorse.java -@@ -6,17 +6,73 @@ import org.bukkit.inventory.ItemStack; +@@ -6,17 +6,106 @@ import org.bukkit.inventory.ItemStack; public class CraftInventoryAbstractHorse extends CraftInventory implements AbstractHorseInventory { @@ -74,6 +74,39 @@ index 4946da593713f4d11d88ac1bb68a089f2f6d5ae0..abef7f23361e6c5d18243dd18439ffd1 + } + + @Override ++ public boolean isEmpty() { ++ return this.getMainInventory().isEmpty() && this.getArmorInventory().isEmpty(); ++ } ++ ++ @Override ++ public ItemStack[] getContents() { ++ ItemStack[] items = new ItemStack[this.getSize()]; ++ ++ items[net.minecraft.world.entity.animal.horse.AbstractHorse.INV_SLOT_SADDLE] = this.getSaddle(); ++ items[net.minecraft.world.inventory.HorseInventoryMenu.SLOT_BODY_ARMOR] = this.getArmor(); ++ ++ for (int i = net.minecraft.world.inventory.HorseInventoryMenu.SLOT_BODY_ARMOR + 1; i < items.length; i++) { ++ net.minecraft.world.item.ItemStack item = this.getMainInventory().getItem(i - 1); ++ items[i] = item.isEmpty() ? null : CraftItemStack.asCraftMirror(item); ++ } ++ ++ return items; ++ } ++ ++ @Override ++ public void setContents(ItemStack[] items) { ++ com.google.common.base.Preconditions.checkArgument(items.length <= this.getSize(), "Invalid inventory size (%s); expected %s or less", items.length, this.getSize()); ++ ++ this.setSaddle(org.apache.commons.lang3.ArrayUtils.get(items, net.minecraft.world.entity.animal.horse.AbstractHorse.INV_SLOT_SADDLE)); ++ this.setArmor(org.apache.commons.lang3.ArrayUtils.get(items, net.minecraft.world.inventory.HorseInventoryMenu.SLOT_BODY_ARMOR)); ++ ++ for (int i = net.minecraft.world.inventory.HorseInventoryMenu.SLOT_BODY_ARMOR + 1; i < this.getSize(); i++) { ++ net.minecraft.world.item.ItemStack item = i >= items.length ? net.minecraft.world.item.ItemStack.EMPTY : CraftItemStack.asNMSCopy(items[i]); ++ this.getMainInventory().setItem(i - 1, item); ++ } ++ } ++ ++ @Override + public ItemStack getItem(final int index) { + if (index == net.minecraft.world.inventory.HorseInventoryMenu.SLOT_BODY_ARMOR) { + final net.minecraft.world.item.ItemStack item = this.getArmorInventory().getItem(0);