aboutsummaryrefslogtreecommitdiffhomepage
path: root/removed-patches-1-20-5
diff options
context:
space:
mode:
authorJake Potrebic <[email protected]>2024-04-23 22:43:09 -0700
committerJake Potrebic <[email protected]>2024-04-23 22:43:09 -0700
commit1d7d7e92f213694ddf1155d03a7541671683f4cb (patch)
tree049b15b20e5405669f75f4fa13fd7c54d68a18e3 /removed-patches-1-20-5
parent309ebc13fcbae181ec3b3aa0f670ff3e6ada863e (diff)
downloadPaper-1d7d7e92f213694ddf1155d03a7541671683f4cb.tar.gz
Paper-1d7d7e92f213694ddf1155d03a7541671683f4cb.zip
301
Diffstat (limited to 'removed-patches-1-20-5')
-rw-r--r--removed-patches-1-20-5/0259-Add-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch397
-rw-r--r--removed-patches-1-20-5/0284-Handle-Large-Packets-disconnecting-client.patch134
-rw-r--r--removed-patches-1-20-5/0310-Configurable-Keep-Spawn-Loaded-range-per-world.patch220
3 files changed, 751 insertions, 0 deletions
diff --git a/removed-patches-1-20-5/0259-Add-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch b/removed-patches-1-20-5/0259-Add-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch
new file mode 100644
index 0000000000..f179b48bd7
--- /dev/null
+++ b/removed-patches-1-20-5/0259-Add-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch
@@ -0,0 +1,397 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Mark Vainomaa <[email protected]>
+Date: Wed, 12 Sep 2018 18:53:55 +0300
+Subject: [PATCH] Add API for CanPlaceOn and CanDestroy NBT values
+
+
+diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
+index 1920cf7ad846f57cd278cb9a72dce03f3d014fbb..7cf1153ae532a9d53ee85b05f77ed74b94cf5fbc 100644
+--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
+@@ -85,6 +85,12 @@ import org.bukkit.persistence.PersistentDataContainer;
+ import static org.spigotmc.ValidateUtils.*;
+ // Spigot end
+
++// Paper start
++import com.destroystokyo.paper.Namespaced;
++import com.destroystokyo.paper.NamespacedTag;
++import java.util.Collections;
++// Paper end
++
+ /**
+ * Children must include the following:
+ *
+@@ -273,6 +279,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ @Specific(Specific.To.NBT)
+ static final ItemMetaKey BLOCK_DATA = new ItemMetaKey("BlockStateTag");
+ static final ItemMetaKey BUKKIT_CUSTOM_TAG = new ItemMetaKey("PublicBukkitValues");
++ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values
++ static final ItemMetaKey CAN_DESTROY = new ItemMetaKey("CanDestroy");
++ static final ItemMetaKey CAN_PLACE_ON = new ItemMetaKey("CanPlaceOn");
++ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values
+
+ // We store the raw original JSON representation of all text data. See SPIGOT-5063, SPIGOT-5656, SPIGOT-5304
+ private String displayName;
+@@ -286,6 +296,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ private int hideFlag;
+ private boolean unbreakable;
+ private int damage;
++ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values
++ private Set<Namespaced> placeableKeys = Sets.newHashSet();
++ private Set<Namespaced> destroyableKeys = Sets.newHashSet();
++ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values
+
+ private static final Set<String> HANDLED_TAGS = Sets.newHashSet();
+ private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
+@@ -323,6 +337,15 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ this.hideFlag = meta.hideFlag;
+ this.unbreakable = meta.unbreakable;
+ this.damage = meta.damage;
++ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values
++ if (meta.hasPlaceableKeys()) {
++ this.placeableKeys = new java.util.HashSet<>(meta.placeableKeys);
++ }
++
++ if (meta.hasDestroyableKeys()) {
++ this.destroyableKeys = new java.util.HashSet<>(meta.destroyableKeys);
++ }
++ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values
+ this.unhandledTags.putAll(meta.unhandledTags);
+ this.persistentDataContainer.putAll(meta.persistentDataContainer.getRaw());
+
+@@ -386,6 +409,31 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ this.persistentDataContainer.put(key, compound.get(key).copy());
+ }
+ }
++ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values
++ if (tag.contains(CAN_DESTROY.NBT)) {
++ ListTag list = tag.getList(CAN_DESTROY.NBT, CraftMagicNumbers.NBT.TAG_STRING);
++ for (int i = 0; i < list.size(); i++) {
++ Namespaced namespaced = this.blockKeyFromString(list.getString(i));
++ if (namespaced == null) {
++ continue;
++ }
++
++ this.destroyableKeys.add(namespaced);
++ }
++ }
++
++ if (tag.contains(CAN_PLACE_ON.NBT)) {
++ ListTag list = tag.getList(CAN_PLACE_ON.NBT, CraftMagicNumbers.NBT.TAG_STRING);
++ for (int i = 0; i < list.size(); i++) {
++ Namespaced namespaced = this.blockKeyFromString(list.getString(i));
++ if (namespaced == null) {
++ continue;
++ }
++
++ this.placeableKeys.add(namespaced);
++ }
++ }
++ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values
+
+ Set<String> keys = tag.getAllKeys();
+ for (String key : keys) {
+@@ -524,6 +572,34 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ this.setDamage(damage);
+ }
+
++ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values
++ Iterable<?> canPlaceOnSerialized = SerializableMeta.getObject(Iterable.class, map, CAN_PLACE_ON.BUKKIT, true);
++ if (canPlaceOnSerialized != null) {
++ for (Object canPlaceOnElement : canPlaceOnSerialized) {
++ String canPlaceOnRaw = (String) canPlaceOnElement;
++ Namespaced value = this.blockKeyFromString(canPlaceOnRaw);
++ if (value == null) {
++ continue;
++ }
++
++ this.placeableKeys.add(value);
++ }
++ }
++
++ Iterable<?> canDestroySerialized = SerializableMeta.getObject(Iterable.class, map, CAN_DESTROY.BUKKIT, true);
++ if (canDestroySerialized != null) {
++ for (Object canDestroyElement : canDestroySerialized) {
++ String canDestroyRaw = (String) canDestroyElement;
++ Namespaced value = this.blockKeyFromString(canDestroyRaw);
++ if (value == null) {
++ continue;
++ }
++
++ this.destroyableKeys.add(value);
++ }
++ }
++ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values
++
+ String internal = SerializableMeta.getString(map, "internal", true);
+ if (internal != null) {
+ ByteArrayInputStream buf = new ByteArrayInputStream(Base64.getDecoder().decode(internal));
+@@ -652,6 +728,23 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ if (this.hasDamage()) {
+ itemTag.putInt(CraftMetaItem.DAMAGE.NBT, this.damage);
+ }
++ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values
++ if (hasPlaceableKeys()) {
++ List<String> items = this.placeableKeys.stream()
++ .map(this::serializeNamespaced)
++ .collect(java.util.stream.Collectors.toList());
++
++ itemTag.put(CAN_PLACE_ON.NBT, createNonComponentStringList(items));
++ }
++
++ if (hasDestroyableKeys()) {
++ List<String> items = this.destroyableKeys.stream()
++ .map(this::serializeNamespaced)
++ .collect(java.util.stream.Collectors.toList());
++
++ itemTag.put(CAN_DESTROY.NBT, createNonComponentStringList(items));
++ }
++ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values
+
+ for (Map.Entry<String, Tag> e : this.unhandledTags.entrySet()) {
+ itemTag.put(e.getKey(), e.getValue());
+@@ -668,6 +761,21 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ }
+ }
+
++ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values
++ static ListTag createNonComponentStringList(List<String> list) {
++ if (list == null || list.isEmpty()) {
++ return null;
++ }
++
++ ListTag tagList = new ListTag();
++ for (String value : list) {
++ tagList.add(StringTag.valueOf(value)); // Paper - NBTTagString.of(String str)
++ }
++
++ return tagList;
++ }
++ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values
++
+ ListTag createStringList(List<String> list) {
+ if (list == null) {
+ return null;
+@@ -751,7 +859,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+
+ @Overridden
+ boolean isEmpty() {
+- return !(this.hasDisplayName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isUnbreakable() || this.hasDamage() || this.hasAttributeModifiers());
++ return !(this.hasDisplayName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isUnbreakable() || this.hasDamage() || this.hasAttributeModifiers() || this.hasPlaceableKeys() || this.hasDestroyableKeys()); // Paper - Implement an API for CanPlaceOn and CanDestroy NBT values
+ }
+
+ // Paper start
+@@ -1223,7 +1331,11 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ && (this.hideFlag == that.hideFlag)
+ && (this.isUnbreakable() == that.isUnbreakable())
+ && (this.hasDamage() ? that.hasDamage() && this.damage == that.damage : !that.hasDamage())
+- && (this.version == that.version);
++ && (this.version == that.version)
++ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
++ && (this.hasPlaceableKeys() ? that.hasPlaceableKeys() && this.placeableKeys.equals(that.placeableKeys) : !that.hasPlaceableKeys())
++ && (this.hasDestroyableKeys() ? that.hasDestroyableKeys() && this.destroyableKeys.equals(that.destroyableKeys) : !that.hasDestroyableKeys());
++ // Paper end
+ }
+
+ /**
+@@ -1258,6 +1370,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ hash = 61 * hash + (this.hasDamage() ? this.damage : 0);
+ hash = 61 * hash + (this.hasAttributeModifiers() ? this.attributeModifiers.hashCode() : 0);
+ hash = 61 * hash + this.version;
++ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
++ hash = 61 * hash + (this.hasPlaceableKeys() ? this.placeableKeys.hashCode() : 0);
++ hash = 61 * hash + (this.hasDestroyableKeys() ? this.destroyableKeys.hashCode() : 0);
++ // Paper end
+ return hash;
+ }
+
+@@ -1282,6 +1398,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ clone.unbreakable = this.unbreakable;
+ clone.damage = this.damage;
+ clone.version = this.version;
++ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
++ if (this.placeableKeys != null) {
++ clone.placeableKeys = Sets.newHashSet(this.placeableKeys);
++ }
++ if (this.destroyableKeys != null) {
++ clone.destroyableKeys = Sets.newHashSet(this.destroyableKeys);
++ }
++ // Paper end
+ return clone;
+ } catch (CloneNotSupportedException e) {
+ throw new Error(e);
+@@ -1339,6 +1463,23 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ builder.put(CraftMetaItem.DAMAGE.BUKKIT, this.damage);
+ }
+
++ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
++ if (this.hasPlaceableKeys()) {
++ List<String> cerealPlaceable = this.placeableKeys.stream()
++ .map(this::serializeNamespaced)
++ .collect(java.util.stream.Collectors.toList());
++
++ builder.put(CAN_PLACE_ON.BUKKIT, cerealPlaceable);
++ }
++
++ if (this.hasDestroyableKeys()) {
++ List<String> cerealDestroyable = this.destroyableKeys.stream()
++ .map(this::serializeNamespaced)
++ .collect(java.util.stream.Collectors.toList());
++
++ builder.put(CAN_DESTROY.BUKKIT, cerealDestroyable);
++ }
++ // Paper end
+ final Map<String, Tag> internalTags = new HashMap<String, Tag>(this.unhandledTags);
+ this.serializeInternal(internalTags);
+ if (!internalTags.isEmpty()) {
+@@ -1516,6 +1657,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ CraftMetaArmorStand.SHOW_ARMS.NBT,
+ CraftMetaArmorStand.SMALL.NBT,
+ CraftMetaArmorStand.MARKER.NBT,
++ CAN_DESTROY.NBT,
++ CAN_PLACE_ON.NBT,
+ // Paper end
+ CraftMetaCompass.LODESTONE_DIMENSION.NBT,
+ CraftMetaCompass.LODESTONE_POS.NBT,
+@@ -1545,4 +1688,141 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ }
+ // Paper end
+
++ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
++ @Override
++ @SuppressWarnings("deprecation")
++ public Set<Material> getCanDestroy() {
++ return !hasDestroyableKeys() ? Collections.emptySet() : legacyGetMatsFromKeys(this.destroyableKeys);
++ }
++
++ @Override
++ @SuppressWarnings("deprecation")
++ public void setCanDestroy(Set<Material> canDestroy) {
++ Preconditions.checkArgument(canDestroy != null, "Cannot replace with null set!");
++ legacyClearAndReplaceKeys(this.destroyableKeys, canDestroy);
++ }
++
++ @Override
++ @SuppressWarnings("deprecation")
++ public Set<Material> getCanPlaceOn() {
++ return !hasPlaceableKeys() ? Collections.emptySet() : legacyGetMatsFromKeys(this.placeableKeys);
++ }
++
++ @Override
++ @SuppressWarnings("deprecation")
++ public void setCanPlaceOn(Set<Material> canPlaceOn) {
++ Preconditions.checkArgument(canPlaceOn != null, "Cannot replace with null set!");
++ legacyClearAndReplaceKeys(this.placeableKeys, canPlaceOn);
++ }
++
++ @Override
++ public Set<Namespaced> getDestroyableKeys() {
++ return !hasDestroyableKeys() ? Collections.emptySet() : Sets.newHashSet(this.destroyableKeys);
++ }
++
++ @Override
++ public void setDestroyableKeys(Collection<Namespaced> canDestroy) {
++ Preconditions.checkArgument(canDestroy != null, "Cannot replace with null collection!");
++ Preconditions.checkArgument(ofAcceptableType(canDestroy), "Can only use NamespacedKey or NamespacedTag objects!");
++ this.destroyableKeys.clear();
++ this.destroyableKeys.addAll(canDestroy);
++ }
++
++ @Override
++ public Set<Namespaced> getPlaceableKeys() {
++ return !hasPlaceableKeys() ? Collections.emptySet() : Sets.newHashSet(this.placeableKeys);
++ }
++
++ @Override
++ public void setPlaceableKeys(Collection<Namespaced> canPlaceOn) {
++ Preconditions.checkArgument(canPlaceOn != null, "Cannot replace with null collection!");
++ Preconditions.checkArgument(ofAcceptableType(canPlaceOn), "Can only use NamespacedKey or NamespacedTag objects!");
++ this.placeableKeys.clear();
++ this.placeableKeys.addAll(canPlaceOn);
++ }
++
++ @Override
++ public boolean hasPlaceableKeys() {
++ return this.placeableKeys != null && !this.placeableKeys.isEmpty();
++ }
++
++ @Override
++ public boolean hasDestroyableKeys() {
++ return this.destroyableKeys != null && !this.destroyableKeys.isEmpty();
++ }
++
++ @Deprecated
++ private void legacyClearAndReplaceKeys(Collection<Namespaced> toUpdate, Collection<Material> beingSet) {
++ if (beingSet.stream().anyMatch(Material::isLegacy)) {
++ throw new IllegalArgumentException("Set must not contain any legacy materials!");
++ }
++
++ toUpdate.clear();
++ toUpdate.addAll(beingSet.stream().map(Material::getKey).collect(java.util.stream.Collectors.toSet()));
++ }
++
++ @Deprecated
++ private Set<Material> legacyGetMatsFromKeys(Collection<Namespaced> names) {
++ Set<Material> mats = Sets.newHashSet();
++ for (Namespaced key : names) {
++ if (!(key instanceof org.bukkit.NamespacedKey)) {
++ continue;
++ }
++
++ Material material = Material.matchMaterial(key.toString(), false);
++ if (material != null) {
++ mats.add(material);
++ }
++ }
++
++ return mats;
++ }
++
++ private @Nullable Namespaced blockKeyFromString(String raw) {
++ boolean isTag = !raw.isEmpty() && raw.codePointAt(0) == '#';
++ com.mojang.datafixers.util.Either<net.minecraft.commands.arguments.blocks.BlockStateParser.BlockResult, net.minecraft.commands.arguments.blocks.BlockStateParser.TagResult> result;
++ try {
++ result = net.minecraft.commands.arguments.blocks.BlockStateParser.parseForTesting(net.minecraft.core.registries.BuiltInRegistries.BLOCK.asLookup(), raw, false);
++ } catch (com.mojang.brigadier.exceptions.CommandSyntaxException e) {
++ return null;
++ }
++
++ net.minecraft.resources.ResourceLocation key = null;
++ if (isTag && result.right().isPresent() && result.right().get().tag() instanceof net.minecraft.core.HolderSet.Named<net.minecraft.world.level.block.Block> namedSet) {
++ key = namedSet.key().location();
++ } else if (result.left().isPresent()) {
++ key = net.minecraft.core.registries.BuiltInRegistries.BLOCK.getKey(result.left().get().blockState().getBlock());
++ }
++
++ if (key == null) {
++ return null;
++ }
++
++ try {
++ if (isTag) {
++ return new NamespacedTag(key.getNamespace(), key.getPath());
++
++ }
++ return CraftNamespacedKey.fromMinecraft(key);
++ } catch (IllegalArgumentException ignored) {
++ return null;
++ }
++ }
++
++ private @Nonnull String serializeNamespaced(Namespaced resource) {
++ return resource.toString();
++ }
++
++ // not a fan of this
++ private boolean ofAcceptableType(Collection<Namespaced> namespacedResources) {
++
++ for (Namespaced resource : namespacedResources) {
++ if (!(resource instanceof org.bukkit.NamespacedKey || resource instanceof com.destroystokyo.paper.NamespacedTag)) {
++ return false;
++ }
++ }
++
++ return true;
++ }
++ // Paper end
+ }
diff --git a/removed-patches-1-20-5/0284-Handle-Large-Packets-disconnecting-client.patch b/removed-patches-1-20-5/0284-Handle-Large-Packets-disconnecting-client.patch
new file mode 100644
index 0000000000..de32fb8f39
--- /dev/null
+++ b/removed-patches-1-20-5/0284-Handle-Large-Packets-disconnecting-client.patch
@@ -0,0 +1,134 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Aikar <[email protected]>
+Date: Tue, 27 Nov 2018 21:18:06 -0500
+Subject: [PATCH] Handle Large Packets disconnecting client
+
+If a players inventory is too big to send in a single packet,
+split the inventory set into multiple packets instead.
+
+diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
+index 02b3f5c67b47a098f7fe15ddba0df6cb586a9ae5..157f055df00faf3a7870df8109e84fdb12f55964 100644
+--- a/src/main/java/net/minecraft/network/Connection.java
++++ b/src/main/java/net/minecraft/network/Connection.java
+@@ -156,6 +156,22 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
+ }
+
+ public void exceptionCaught(ChannelHandlerContext channelhandlercontext, Throwable throwable) {
++ // Paper start - Handle large packets disconnecting client
++ if (throwable instanceof io.netty.handler.codec.EncoderException && throwable.getCause() instanceof PacketEncoder.PacketTooLargeException packetTooLargeException) {
++ final Packet<?> packet = packetTooLargeException.getPacket();
++ final io.netty.util.Attribute<ConnectionProtocol.CodecData<?>> codecDataAttribute = channelhandlercontext.channel().attr(packetTooLargeException.codecKey);
++ if (packet.packetTooLarge(this)) {
++ ProtocolSwapHandler.swapProtocolIfNeeded(codecDataAttribute, packet);
++ return;
++ } else if (packet.isSkippable()) {
++ Connection.LOGGER.debug("Skipping packet due to errors", throwable.getCause());
++ ProtocolSwapHandler.swapProtocolIfNeeded(codecDataAttribute, packet);
++ return;
++ } else {
++ throwable = throwable.getCause();
++ }
++ }
++ // Paper end - Handle large packets disconnecting client
+ if (throwable instanceof SkipPacketException) {
+ Connection.LOGGER.debug("Skipping packet due to errors", throwable.getCause());
+ } else {
+diff --git a/src/main/java/net/minecraft/network/PacketEncoder.java b/src/main/java/net/minecraft/network/PacketEncoder.java
+index 0d80fcee1831af59b06c4d00dc713bd4dad947fc..061eada043325142d33a0cec02e9e484d14a7fca 100644
+--- a/src/main/java/net/minecraft/network/PacketEncoder.java
++++ b/src/main/java/net/minecraft/network/PacketEncoder.java
+@@ -41,7 +41,7 @@ public class PacketEncoder extends MessageToByteEncoder<Packet<?>> {
+ int j = friendlyByteBuf.writerIndex();
+ packet.write(friendlyByteBuf);
+ int k = friendlyByteBuf.writerIndex() - j;
+- if (k > 8388608) {
++ if (false && k > 8388608) { // Paper - Handle large packets disconnecting client; disable
+ throw new IllegalArgumentException("Packet too big (is " + k + ", should be less than 8388608): " + packet);
+ }
+
+@@ -54,9 +54,34 @@ public class PacketEncoder extends MessageToByteEncoder<Packet<?>> {
+
+ throw var13;
+ } finally {
++ // Paper start - Handle large packets disconnecting client
++ int packetLength = friendlyByteBuf.readableBytes();
++ if (packetLength > MAX_PACKET_SIZE) {
++ throw new PacketTooLargeException(packet, this.codecKey, packetLength);
++ }
++ // Paper end - Handle large packets disconnecting client
+ ProtocolSwapHandler.swapProtocolIfNeeded(attribute, packet);
+ }
+ }
+ }
+ }
++
++ // Paper start
++ private static int MAX_PACKET_SIZE = 8388608;
++
++ public static class PacketTooLargeException extends RuntimeException {
++ private final Packet<?> packet;
++ public final AttributeKey<ConnectionProtocol.CodecData<?>> codecKey;
++
++ PacketTooLargeException(Packet<?> packet, AttributeKey<ConnectionProtocol.CodecData<?>> codecKey, int packetLength) {
++ super("PacketTooLarge - " + packet.getClass().getSimpleName() + " is " + packetLength + ". Max is " + MAX_PACKET_SIZE);
++ this.packet = packet;
++ this.codecKey = codecKey;
++ }
++
++ public Packet<?> getPacket() {
++ return this.packet;
++ }
++ }
++ // Paper end
+ }
+diff --git a/src/main/java/net/minecraft/network/protocol/Packet.java b/src/main/java/net/minecraft/network/protocol/Packet.java
+index 700418bb0c9fbed3f161611881b1e222248ca4eb..cc658a61065d5c0021a4b88fa58b40211b94f8ec 100644
+--- a/src/main/java/net/minecraft/network/protocol/Packet.java
++++ b/src/main/java/net/minecraft/network/protocol/Packet.java
+@@ -10,6 +10,12 @@ public interface Packet<T extends PacketListener> {
+
+ void handle(T listener);
+
++ // Paper start
++ default boolean packetTooLarge(net.minecraft.network.Connection manager) {
++ return false;
++ }
++ // Paper end
++
+ default boolean isSkippable() {
+ return false;
+ }
+diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java
+index 6206d4d71dfe95b454b22f5b3055623638e145c0..6765175c98d52e5cbc191e88e0d545a05606dfd4 100644
+--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java
++++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java
+@@ -31,6 +31,16 @@ public class ClientboundContainerSetContentPacket implements Packet<ClientGamePa
+ this.carriedItem = buf.readItem();
+ }
+
++ // Paper start
++ @Override
++ public boolean packetTooLarge(net.minecraft.network.Connection manager) {
++ for (int i = 0 ; i < this.items.size() ; i++) {
++ manager.send(new ClientboundContainerSetSlotPacket(this.containerId, this.stateId, i, this.items.get(i)));
++ }
++ return true;
++ }
++ // Paper end
++
+ @Override
+ public void write(FriendlyByteBuf buf) {
+ buf.writeByte(this.containerId);
+diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
+index dc657312889da4fc3222a6981223a01406b77deb..a44a82d2d5ed4d675dc1a184d5b6b935fda575dd 100644
+--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
++++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
+@@ -49,7 +49,7 @@ public class ClientboundLevelChunkPacketData {
+ throw new RuntimeException("Can't read heightmap in packet for [" + x + ", " + z + "]");
+ } else {
+ int i = buf.readVarInt();
+- if (i > 2097152) {
++ if (i > 2097152) { // Paper - diff on change - if this changes, update PacketEncoder
+ throw new RuntimeException("Chunk Packet trying to allocate too much memory on read.");
+ } else {
+ this.buffer = new byte[i];
diff --git a/removed-patches-1-20-5/0310-Configurable-Keep-Spawn-Loaded-range-per-world.patch b/removed-patches-1-20-5/0310-Configurable-Keep-Spawn-Loaded-range-per-world.patch
new file mode 100644
index 0000000000..4d9cba2dd0
--- /dev/null
+++ b/removed-patches-1-20-5/0310-Configurable-Keep-Spawn-Loaded-range-per-world.patch
@@ -0,0 +1,220 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Aikar <[email protected]>
+Date: Sat, 13 Sep 2014 23:14:43 -0400
+Subject: [PATCH] Configurable Keep Spawn Loaded range per world
+
+This lets you disable it for some worlds and lower it for others.
+
+diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
+index 176378ddbf21d758694e8e624cc6c555c78e0fab..6342b7a3c4ccad528f026384da64e973e630f030 100644
+--- a/src/main/java/net/minecraft/server/MinecraftServer.java
++++ b/src/main/java/net/minecraft/server/MinecraftServer.java
+@@ -768,30 +768,33 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
+
+ // CraftBukkit start
+ public void prepareLevels(ChunkProgressListener worldloadlistener, ServerLevel worldserver) {
++ ServerChunkCache chunkproviderserver = worldserver.getChunkSource(); // Paper - Configurable Keep Spawn Loaded range per world
+ // WorldServer worldserver = this.overworld();
+ this.forceTicks = true;
+ // CraftBukkit end
++ if (worldserver.getWorld().getKeepSpawnInMemory()) { // Paper - Configurable Keep Spawn Loaded range per world
+
+ MinecraftServer.LOGGER.info("Preparing start region for dimension {}", worldserver.dimension().location());
+ BlockPos blockposition = worldserver.getSharedSpawnPos();
+
+ worldloadlistener.updateSpawnPos(new ChunkPos(blockposition));
+- ServerChunkCache chunkproviderserver = worldserver.getChunkSource();
++ //ChunkProviderServer chunkproviderserver = worldserver.getChunkProvider(); // Paper - Configurable Keep Spawn Loaded range per world; move up
+
+ this.nextTickTimeNanos = Util.getNanos();
+- // CraftBukkit start
+- if (worldserver.getWorld().getKeepSpawnInMemory()) {
+- chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(blockposition), 11, Unit.INSTANCE);
++ // Paper start - Configurable Keep Spawn Loaded range per world
++ int radiusBlocks = worldserver.paperConfig().spawn.keepSpawnLoadedRange * 16;
++ int radiusChunks = radiusBlocks / 16 + ((radiusBlocks & 15) != 0 ? 1 : 0);
++ int totalChunks = ((radiusChunks) * 2 + 1);
++ totalChunks *= totalChunks;
++ worldloadlistener.setChunkRadius(radiusBlocks / 16);
+
+- while (chunkproviderserver.getTickingGenerated() != 441) {
+- // this.nextTickTimeNanos = SystemUtils.getNanos() + MinecraftServer.PREPARE_LEVELS_DEFAULT_DELAY_NANOS;
+- this.executeModerately();
+- }
+- }
++ worldserver.addTicketsForSpawn(radiusBlocks, blockposition);
++ // Paper end - Configurable Keep Spawn Loaded range per world
+
+ // this.nextTickTimeNanos = SystemUtils.getNanos() + MinecraftServer.PREPARE_LEVELS_DEFAULT_DELAY_NANOS;
+ this.executeModerately();
+ // Iterator iterator = this.levels.values().iterator();
++ } // Paper - Configurable Keep Spawn Loaded range per world
+
+ if (true) {
+ ServerLevel worldserver1 = worldserver;
+@@ -814,7 +817,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
+ // this.nextTickTimeNanos = SystemUtils.getNanos() + MinecraftServer.PREPARE_LEVELS_DEFAULT_DELAY_NANOS;
+ this.executeModerately();
+ // CraftBukkit end
+- worldloadlistener.stop();
++ if (worldserver.getWorld().getKeepSpawnInMemory()) worldloadlistener.stop(); // Paper - Configurable Keep Spawn Loaded range per world
+ // CraftBukkit start
+ // this.updateMobSpawningFlags();
+ worldserver.setSpawnSettings(this.isSpawningMonsters(), this.isSpawningAnimals());
+diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
+index 57f129651778d6c20c695bf7b3a8b4d40c402a20..20de3be232ccc7ec7bbc3c6aee9acf66fd396af1 100644
+--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
+@@ -1640,12 +1640,84 @@ public class ServerLevel extends Level implements WorldGenLevel {
+ return ((MapIndex) this.getServer().overworld().getDataStorage().computeIfAbsent(MapIndex.factory(), "idcounts")).getFreeAuxValueForMap();
+ }
+
++ // Paper start - Configurable Keep Spawn Loaded range per world
++ public void addTicketsForSpawn(int radiusInBlocks, BlockPos spawn) {
++ // In order to respect vanilla behavior, which is ensuring everything but the spawn border can tick, we add tickets
++ // with level 31 for the non-border spawn chunks
++ ServerChunkCache chunkproviderserver = this.getChunkSource();
++ int tickRadius = radiusInBlocks - 16;
++
++ // add ticking chunks
++ for (int x = -tickRadius; x <= tickRadius; x += 16) {
++ for (int z = -tickRadius; z <= tickRadius; z += 16) {
++ // radius of 2 will have the current chunk be level 31
++ chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(spawn.offset(x, 0, z)), 2, Unit.INSTANCE);
++ }
++ }
++
++ // add border chunks
++
++ // add border along x axis (including corner chunks)
++ for (int x = -radiusInBlocks; x <= radiusInBlocks; x += 16) {
++ // top
++ chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(spawn.offset(x, 0, radiusInBlocks)), 1, Unit.INSTANCE); // level 32
++ // bottom
++ chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(spawn.offset(x, 0, -radiusInBlocks)), 1, Unit.INSTANCE); // level 32
++ }
++
++ // add border along z axis (excluding corner chunks)
++ for (int z = -radiusInBlocks + 16; z < radiusInBlocks; z += 16) {
++ // right
++ chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(spawn.offset(radiusInBlocks, 0, z)), 1, Unit.INSTANCE); // level 32
++ // left
++ chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(spawn.offset(-radiusInBlocks, 0, z)), 1, Unit.INSTANCE); // level 32
++ }
++ }
++ public void removeTicketsForSpawn(int radiusInBlocks, BlockPos spawn) {
++ // In order to respect vanilla behavior, which is ensuring everything but the spawn border can tick, we added tickets
++ // with level 31 for the non-border spawn chunks
++ ServerChunkCache chunkproviderserver = this.getChunkSource();
++ int tickRadius = radiusInBlocks - 16;
++
++ // remove ticking chunks
++ for (int x = -tickRadius; x <= tickRadius; x += 16) {
++ for (int z = -tickRadius; z <= tickRadius; z += 16) {
++ // radius of 2 will have the current chunk be level 31
++ chunkproviderserver.removeRegionTicket(TicketType.START, new ChunkPos(spawn.offset(x, 0, z)), 2, Unit.INSTANCE);
++ }
++ }
++
++ // remove border chunks
++
++ // remove border along x axis (including corner chunks)
++ for (int x = -radiusInBlocks; x <= radiusInBlocks; x += 16) {
++ // top
++ chunkproviderserver.removeRegionTicket(TicketType.START, new ChunkPos(spawn.offset(x, 0, radiusInBlocks)), 1, Unit.INSTANCE); // level 32
++ // bottom
++ chunkproviderserver.removeRegionTicket(TicketType.START, new ChunkPos(spawn.offset(x, 0, -radiusInBlocks)), 1, Unit.INSTANCE); // level 32
++ }
++
++ // remove border along z axis (excluding corner chunks)
++ for (int z = -radiusInBlocks + 16; z < radiusInBlocks; z += 16) {
++ // right
++ chunkproviderserver.removeRegionTicket(TicketType.START, new ChunkPos(spawn.offset(radiusInBlocks, 0, z)), 1, Unit.INSTANCE); // level 32
++ // left
++ chunkproviderserver.removeRegionTicket(TicketType.START, new ChunkPos(spawn.offset(-radiusInBlocks, 0, z)), 1, Unit.INSTANCE); // level 32
++ }
++ }
++ // Paper end - Configurable Keep Spawn Loaded range per world
++
+ public void setDefaultSpawnPos(BlockPos pos, float angle) {
+- ChunkPos chunkcoordintpair = new ChunkPos(new BlockPos(this.levelData.getXSpawn(), 0, this.levelData.getZSpawn()));
++ // Paper start - Configurable Keep Spawn Loaded range per world
++ BlockPos prevSpawn = this.getSharedSpawnPos();
++ //ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(new BlockPosition(this.worldData.a(), 0, this.worldData.c()));
+
+ this.levelData.setSpawn(pos, angle);
+- this.getChunkSource().removeRegionTicket(TicketType.START, chunkcoordintpair, 11, Unit.INSTANCE);
+- this.getChunkSource().addRegionTicket(TicketType.START, new ChunkPos(pos), 11, Unit.INSTANCE);
++ if (this.keepSpawnInMemory) {
++ // if this keepSpawnInMemory is false a plugin has already removed our tickets, do not re-add
++ this.removeTicketsForSpawn(this.paperConfig().spawn.keepSpawnLoadedRange * 16, prevSpawn);
++ this.addTicketsForSpawn(this.paperConfig().spawn.keepSpawnLoadedRange * 16, pos);
++ }
+ this.getServer().getPlayerList().broadcastAll(new ClientboundSetDefaultSpawnPositionPacket(pos, angle));
+ }
+
+diff --git a/src/main/java/net/minecraft/server/level/progress/ChunkProgressListener.java b/src/main/java/net/minecraft/server/level/progress/ChunkProgressListener.java
+index 1b565b2809c2d367e21971c5154f35c9763995e6..4792eaa30464f4c4ca7f2d6cf20f734beed81f23 100644
+--- a/src/main/java/net/minecraft/server/level/progress/ChunkProgressListener.java
++++ b/src/main/java/net/minecraft/server/level/progress/ChunkProgressListener.java
+@@ -12,4 +12,6 @@ public interface ChunkProgressListener {
+ void start();
+
+ void stop();
++
++ void setChunkRadius(int radius); // Paper - Configurable Keep Spawn Loaded range per world
+ }
+diff --git a/src/main/java/net/minecraft/server/level/progress/LoggerChunkProgressListener.java b/src/main/java/net/minecraft/server/level/progress/LoggerChunkProgressListener.java
+index c9667df492e5681bf933a7f8878b0fdb324afed3..09d0c702132d4cc52ce36712aed11d30efe89f54 100644
+--- a/src/main/java/net/minecraft/server/level/progress/LoggerChunkProgressListener.java
++++ b/src/main/java/net/minecraft/server/level/progress/LoggerChunkProgressListener.java
+@@ -11,12 +11,19 @@ import org.slf4j.Logger;
+
+ public class LoggerChunkProgressListener implements ChunkProgressListener {
+ private static final Logger LOGGER = LogUtils.getLogger();
+- private final int maxCount;
++ private int maxCount; // Paper - remove final
+ private int count;
+ private long startTime;
+ private long nextTickTime = Long.MAX_VALUE;
+
+ public LoggerChunkProgressListener(int radius) {
++ // Paper start - Configurable Keep Spawn Loaded range per world
++ this.setChunkRadius(radius); // Move to method
++ }
++
++ @Override
++ public void setChunkRadius(int radius) {
++ // Paper end - Configurable Keep Spawn Loaded range per world
+ int i = radius * 2 + 1;
+ this.maxCount = i * i;
+ }
+diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+index 4001a8c13ceed6037174bb81fd06d9758fa0336c..b39721208f8b66c1478e89553a592070cf90fb97 100644
+--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+@@ -1411,15 +1411,21 @@ public class CraftWorld extends CraftRegionAccessor implements World {
+
+ @Override
+ public void setKeepSpawnInMemory(boolean keepLoaded) {
++ // Paper start - Configurable spawn radius
++ if (keepLoaded == this.world.keepSpawnInMemory) {
++ // do nothing, nothing has changed
++ return;
++ }
+ this.world.keepSpawnInMemory = keepLoaded;
+ // Grab the worlds spawn chunk
+ BlockPos chunkcoordinates = this.world.getSharedSpawnPos();
+ if (keepLoaded) {
+- this.world.getChunkSource().addRegionTicket(TicketType.START, new ChunkPos(chunkcoordinates), 11, Unit.INSTANCE);
++ this.world.addTicketsForSpawn(this.world.paperConfig().spawn.keepSpawnLoadedRange * 16, chunkcoordinates);
+ } else {
+- // TODO: doesn't work well if spawn changed....
+- this.world.getChunkSource().removeRegionTicket(TicketType.START, new ChunkPos(chunkcoordinates), 11, Unit.INSTANCE);
++ // TODO: doesn't work well if spawn changed.... // Paper - resolved
++ this.world.removeTicketsForSpawn(this.world.paperConfig().spawn.keepSpawnLoadedRange * 16, chunkcoordinates);
+ }
++ // Paper end
+ }
+
+ @Override