From 871afcdad4b1c264bf6fa9fd61f2a6c84cb1204b Mon Sep 17 00:00:00 2001 From: Sam Russell Date: Sat, 20 Dec 2025 20:09:01 +0100 Subject: [PATCH 1/4] Make arrow despawn rate override configurable Change #3859 forces all arrows to despawn after 10 seconds to fix MC-125757, but this was marks as works-as-intended. This change allows admins to configure this value (or disable with -1) while keeping the existing behaviour --- .../world/entity/projectile/arrow/AbstractArrow.java.patch | 7 +++++-- .../io/papermc/paper/configuration/WorldConfiguration.java | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch index cee3560183ff..1e8830e1e02b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch @@ -26,11 +26,14 @@ } public void setSoundEvent(SoundEvent soundEvent) { -@@ -207,6 +_,7 @@ +@@ -207,6 +_,10 @@ this.setSharedFlagOnFire(this.getRemainingFireTicks() > 0); } } else { -+ if (this.tickCount > 200) this.tickDespawn(); // Paper - tick life regardless after 10 seconds ++ // Paper start - tick life regardless after X seconds ++ int arrowDespawnOverrideRate = this.level().paperConfig().entities.spawning.arrowDespawnOverrideRate; ++ if (arrowDespawnOverrideRate > 0 && this.tickCount > arrowDespawnOverrideRate) this.tickDespawn(); ++ // Paper end - tick life regardless after X seconds this.inGroundTime = 0; Vec3 vec31 = this.position(); if (this.isInWater()) { diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java b/paper-server/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java index 237abcf06ebf..f289017f4c78 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java @@ -171,6 +171,7 @@ public class Sniffer extends ConfigurationPart { public class Spawning extends ConfigurationPart { public ArrowDespawnRate nonPlayerArrowDespawnRate = ArrowDespawnRate.def(WorldConfiguration.this.spigotConfig); public ArrowDespawnRate creativeArrowDespawnRate = ArrowDespawnRate.def(WorldConfiguration.this.spigotConfig); + public int arrowDespawnOverrideRate = 200; public boolean filterBadTileEntityNbtFromFallingBlocks = true; public List filteredEntityTagNbtPaths = NbtPathSerializer.fromString(List.of("Pos", "Motion", "sleeping_pos")); public boolean disableMobSpawnerSpawnEggTransformation = false; From ae48aac5fdd7714676115465087db7a69abb1e79 Mon Sep 17 00:00:00 2001 From: Sam Russell Date: Tue, 23 Dec 2025 17:08:25 +0100 Subject: [PATCH 2/4] Code review: use IntOr.Disabled for config --- .../entity/projectile/arrow/AbstractArrow.java.patch | 12 ++++++++++-- .../paper/configuration/WorldConfiguration.java | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch index 1e8830e1e02b..870dc42079b8 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch @@ -1,5 +1,13 @@ --- a/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java +++ b/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java +@@ -2,6 +_,7 @@ + + import com.google.common.collect.Lists; + import com.mojang.serialization.Codec; ++import io.papermc.paper.configuration.type.number.IntOr; + import it.unimi.dsi.fastutil.ints.IntOpenHashSet; + import java.util.ArrayList; + import java.util.Collection; @@ -86,7 +_,14 @@ protected AbstractArrow( EntityType type, double x, double y, double z, Level level, ItemStack pickupItemStack, @Nullable ItemStack firedFromWeapon @@ -31,8 +39,8 @@ } } else { + // Paper start - tick life regardless after X seconds -+ int arrowDespawnOverrideRate = this.level().paperConfig().entities.spawning.arrowDespawnOverrideRate; -+ if (arrowDespawnOverrideRate > 0 && this.tickCount > arrowDespawnOverrideRate) this.tickDespawn(); ++ IntOr.Disabled arrowDespawnOverrideRate = this.level().paperConfig().entities.spawning.arrowDespawnOverrideRate; ++ if (arrowDespawnOverrideRate.enabled() && this.tickCount > arrowDespawnOverrideRate.intValue()) this.tickDespawn(); + // Paper end - tick life regardless after X seconds this.inGroundTime = 0; Vec3 vec31 = this.position(); diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java b/paper-server/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java index f289017f4c78..e4db9b68d6dc 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java @@ -171,7 +171,7 @@ public class Sniffer extends ConfigurationPart { public class Spawning extends ConfigurationPart { public ArrowDespawnRate nonPlayerArrowDespawnRate = ArrowDespawnRate.def(WorldConfiguration.this.spigotConfig); public ArrowDespawnRate creativeArrowDespawnRate = ArrowDespawnRate.def(WorldConfiguration.this.spigotConfig); - public int arrowDespawnOverrideRate = 200; + public IntOr.Disabled arrowDespawnOverrideRate = new IntOr.Disabled(OptionalInt.of(200)); public boolean filterBadTileEntityNbtFromFallingBlocks = true; public List filteredEntityTagNbtPaths = NbtPathSerializer.fromString(List.of("Pos", "Motion", "sleeping_pos")); public boolean disableMobSpawnerSpawnEggTransformation = false; From 372809ceca1db00b27f61af62e3733ecfdca257e Mon Sep 17 00:00:00 2001 From: Sam Russell Date: Tue, 23 Dec 2025 17:16:51 +0100 Subject: [PATCH 3/4] Use FQN for IntOr.Disabled --- .../entity/projectile/arrow/AbstractArrow.java.patch | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch index 870dc42079b8..6a77bf1bdaf3 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch @@ -1,13 +1,5 @@ --- a/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java +++ b/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java -@@ -2,6 +_,7 @@ - - import com.google.common.collect.Lists; - import com.mojang.serialization.Codec; -+import io.papermc.paper.configuration.type.number.IntOr; - import it.unimi.dsi.fastutil.ints.IntOpenHashSet; - import java.util.ArrayList; - import java.util.Collection; @@ -86,7 +_,14 @@ protected AbstractArrow( EntityType type, double x, double y, double z, Level level, ItemStack pickupItemStack, @Nullable ItemStack firedFromWeapon @@ -39,7 +31,7 @@ } } else { + // Paper start - tick life regardless after X seconds -+ IntOr.Disabled arrowDespawnOverrideRate = this.level().paperConfig().entities.spawning.arrowDespawnOverrideRate; ++ io.papermc.paper.configuration.type.number.IntOr.Disabled arrowDespawnOverrideRate = this.level().paperConfig().entities.spawning.arrowDespawnOverrideRate; + if (arrowDespawnOverrideRate.enabled() && this.tickCount > arrowDespawnOverrideRate.intValue()) this.tickDespawn(); + // Paper end - tick life regardless after X seconds this.inGroundTime = 0; From ea1092dfc07296d18285a5b675910984cfa7cb67 Mon Sep 17 00:00:00 2001 From: Bjarne Koll Date: Sun, 28 Dec 2025 00:02:31 +0100 Subject: [PATCH 4/4] Rename attempt number 1 --- .../world/entity/projectile/arrow/AbstractArrow.java.patch | 4 ++-- .../io/papermc/paper/configuration/WorldConfiguration.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch index 6a77bf1bdaf3..7eabefe87da8 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch @@ -31,8 +31,8 @@ } } else { + // Paper start - tick life regardless after X seconds -+ io.papermc.paper.configuration.type.number.IntOr.Disabled arrowDespawnOverrideRate = this.level().paperConfig().entities.spawning.arrowDespawnOverrideRate; -+ if (arrowDespawnOverrideRate.enabled() && this.tickCount > arrowDespawnOverrideRate.intValue()) this.tickDespawn(); ++ final io.papermc.paper.configuration.type.number.IntOr.Disabled maxArrowDespawnInvulnerability = this.level().paperConfig().entities.spawning.maxArrowDespawnInvulnerability; ++ if (maxArrowDespawnInvulnerability.enabled() && this.tickCount > maxArrowDespawnInvulnerability.intValue()) this.tickDespawn(); + // Paper end - tick life regardless after X seconds this.inGroundTime = 0; Vec3 vec31 = this.position(); diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java b/paper-server/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java index e4db9b68d6dc..d34e627f8b67 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java @@ -171,7 +171,7 @@ public class Sniffer extends ConfigurationPart { public class Spawning extends ConfigurationPart { public ArrowDespawnRate nonPlayerArrowDespawnRate = ArrowDespawnRate.def(WorldConfiguration.this.spigotConfig); public ArrowDespawnRate creativeArrowDespawnRate = ArrowDespawnRate.def(WorldConfiguration.this.spigotConfig); - public IntOr.Disabled arrowDespawnOverrideRate = new IntOr.Disabled(OptionalInt.of(200)); + public IntOr.Disabled maxArrowDespawnInvulnerability = new IntOr.Disabled(OptionalInt.of(200)); public boolean filterBadTileEntityNbtFromFallingBlocks = true; public List filteredEntityTagNbtPaths = NbtPathSerializer.fromString(List.of("Pos", "Motion", "sleeping_pos")); public boolean disableMobSpawnerSpawnEggTransformation = false;