diff --git a/patches/server/Improve-tag-parser-handling.patch b/patches/server/Improve-tag-parser-handling.patch index c53d630f34..51d80c7043 100644 --- a/patches/server/Improve-tag-parser-handling.patch +++ b/patches/server/Improve-tag-parser-handling.patch @@ -109,6 +109,63 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } } +diff --git a/src/main/java/net/minecraft/network/chat/ComponentUtils.java b/src/main/java/net/minecraft/network/chat/ComponentUtils.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/network/chat/ComponentUtils.java ++++ b/src/main/java/net/minecraft/network/chat/ComponentUtils.java +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/network/chat/contents/NbtContents.java ++++ b/src/main/java/net/minecraft/network/chat/contents/NbtContents.java +@@ -0,0 +0,0 @@ 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 { +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/network/chat/contents/SelectorContents.java @@ -122,6 +179,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } return entitySelector; +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/network/chat/contents/TranslatableContents.java diff --git a/patches/server/fix-horse-inventories.patch b/patches/server/fix-horse-inventories.patch index 52d8b5d303..4ae8c83825 100644 --- a/patches/server/fix-horse-inventories.patch +++ b/patches/server/fix-horse-inventories.patch @@ -74,6 +74,39 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + @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);