From f1c64357143b7ae1a4e061124c96b1647af1f410 Mon Sep 17 00:00:00 2001 From: Tamion <70228790+notTamion@users.noreply.github.com> Date: Sun, 13 Apr 2025 10:03:08 +0200 Subject: [PATCH] 1.21.5 --- .../patches/features/0004-Anti-Xray.patch | 8 +- .../0015-Moonrise-optimisation-patches.patch | 24 ++-- ...nate-Current-redstone-implementation.patch | 4 +- .../minecraft/world/item/BowItem.java.patch | 14 ++ .../world/item/CrossbowItem.java.patch | 36 ++++- .../item/ProjectileWeaponItem.java.patch | 133 ++++++++++++++++-- .../minecraft/world/level/Level.java.patch | 3 +- 7 files changed, 191 insertions(+), 31 deletions(-) create mode 100644 paper-server/patches/sources/net/minecraft/world/item/BowItem.java.patch diff --git a/paper-server/patches/features/0004-Anti-Xray.patch b/paper-server/patches/features/0004-Anti-Xray.patch index 16f93f288619..8e28c51abe32 100644 --- a/paper-server/patches/features/0004-Anti-Xray.patch +++ b/paper-server/patches/features/0004-Anti-Xray.patch @@ -199,7 +199,7 @@ index a2a4dbcfb77d44657b3dfbe97cb629de215c29eb..73717609fccd9af12e2cc39824106f49 } // Paper end - Send empty chunk diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 1f26826b2161cfeb27e5b2060e178b493e9142d9..63f8b0c47e3321b74f4b6bcbc1e28cd751911198 100644 +index c3390b0703a8852c85aca6a4150f54d04acca741..f1380f545cf7212968d66275fe620269a101230f 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -132,6 +132,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl @@ -210,7 +210,7 @@ index 1f26826b2161cfeb27e5b2060e178b493e9142d9..63f8b0c47e3321b74f4b6bcbc1e28cd7 private final CraftWorld world; public boolean pvpMode; public org.bukkit.generator.ChunkGenerator generator; -@@ -201,7 +202,8 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -202,7 +203,8 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl org.bukkit.generator.BiomeProvider biomeProvider, // CraftBukkit org.bukkit.World.Environment env, // CraftBukkit java.util.function.Function, AutoCl +@@ -279,6 +281,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl public void onBorderSetDamageSafeZOne(WorldBorder border, double safeZoneRadius) {} }); // CraftBukkit end @@ -228,7 +228,7 @@ index 1f26826b2161cfeb27e5b2060e178b493e9142d9..63f8b0c47e3321b74f4b6bcbc1e28cd7 } // Paper start - Cancel hit for vanished players -@@ -483,6 +486,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -484,6 +487,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl snapshot.setFlags(flags); // Paper - always set the flag of the most recent call to mitigate issues with multiple update at the same pos with different flags } BlockState blockState = chunkAt.setBlockState(pos, state, flags); diff --git a/paper-server/patches/features/0015-Moonrise-optimisation-patches.patch b/paper-server/patches/features/0015-Moonrise-optimisation-patches.patch index 10729a44c7c4..0cd087f162f9 100644 --- a/paper-server/patches/features/0015-Moonrise-optimisation-patches.patch +++ b/paper-server/patches/features/0015-Moonrise-optimisation-patches.patch @@ -29725,7 +29725,7 @@ index 300f3ed58109219d97846082941b860585f66fed..892a7c1eb1b321ca6d5ca709142e7fea // Paper start - Affects Spawning API diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 63f8b0c47e3321b74f4b6bcbc1e28cd751911198..eb4d03cfdb34243901cfba832d35559d5be9e876 100644 +index f1380f545cf7212968d66275fe620269a101230f..e6f2fe03ec55f4ae1fa6c94af48db798795de72a 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -81,6 +81,7 @@ import net.minecraft.world.level.storage.LevelData; @@ -29754,7 +29754,7 @@ index 63f8b0c47e3321b74f4b6bcbc1e28cd751911198..eb4d03cfdb34243901cfba832d35559d @Deprecated private final RandomSource threadSafeRandom = RandomSource.createThreadSafe(); private final Holder dimensionTypeRegistration; -@@ -189,6 +190,629 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -190,6 +191,629 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl public abstract ResourceKey getTypeKey(); @@ -30384,7 +30384,7 @@ index 63f8b0c47e3321b74f4b6bcbc1e28cd751911198..eb4d03cfdb34243901cfba832d35559d protected Level( WritableLevelData levelData, ResourceKey dimension, -@@ -205,6 +829,15 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -206,6 +830,15 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, // Paper - create paper world config java.util.concurrent.Executor executor // Paper - Anti-Xray ) { @@ -30400,7 +30400,7 @@ index 63f8b0c47e3321b74f4b6bcbc1e28cd751911198..eb4d03cfdb34243901cfba832d35559d this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName()); // Spigot this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config this.generator = gen; -@@ -281,6 +914,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -282,6 +915,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl }); // CraftBukkit end this.chunkPacketBlockController = this.paperConfig().anticheat.antiXray.enabled ? new io.papermc.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) : io.papermc.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray @@ -30408,7 +30408,7 @@ index 63f8b0c47e3321b74f4b6bcbc1e28cd751911198..eb4d03cfdb34243901cfba832d35559d } // Paper start - Cancel hit for vanished players -@@ -555,7 +1189,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -556,7 +1190,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl this.setBlocksDirty(pos, blockState, blockState1); } @@ -30417,7 +30417,7 @@ index 63f8b0c47e3321b74f4b6bcbc1e28cd751911198..eb4d03cfdb34243901cfba832d35559d this.sendBlockUpdated(pos, blockState, state, flags); } -@@ -820,6 +1454,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -821,6 +1455,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl // Spigot start boolean runsNormally = this.tickRateManager().runsNormally(); @@ -30425,7 +30425,7 @@ index 63f8b0c47e3321b74f4b6bcbc1e28cd751911198..eb4d03cfdb34243901cfba832d35559d var toRemove = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet(); // Paper - Fix MC-117075; use removeAll toRemove.add(null); // Paper - Fix MC-117075 for (this.tileTickPosition = 0; this.tileTickPosition < this.blockEntityTickers.size(); this.tileTickPosition++) { // Paper - Disable tick limiters -@@ -829,6 +1464,11 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -830,6 +1465,11 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl toRemove.add(tickingBlockEntity); // Paper - Fix MC-117075; use removeAll } else if (runsNormally && this.shouldTickBlocksAt(tickingBlockEntity.getPos())) { tickingBlockEntity.tick(); @@ -30437,7 +30437,7 @@ index 63f8b0c47e3321b74f4b6bcbc1e28cd751911198..eb4d03cfdb34243901cfba832d35559d } } this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075 -@@ -849,6 +1489,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -850,6 +1490,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); // Paper end - Prevent block entity and entity crashes } @@ -30445,7 +30445,7 @@ index 63f8b0c47e3321b74f4b6bcbc1e28cd751911198..eb4d03cfdb34243901cfba832d35559d } // Paper start - Option to prevent armor stands from doing entity lookups -@@ -856,7 +1497,14 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -857,7 +1498,14 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl public boolean noCollision(@Nullable Entity entity, AABB box) { if (entity instanceof net.minecraft.world.entity.decoration.ArmorStand && !entity.level().paperConfig().entities.armorStands.doCollisionEntityLookups) return false; @@ -30461,7 +30461,7 @@ index 63f8b0c47e3321b74f4b6bcbc1e28cd751911198..eb4d03cfdb34243901cfba832d35559d } // Paper end - Option to prevent armor stands from doing entity lookups -@@ -994,7 +1642,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -995,7 +1643,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl if (this.isOutsideBuildHeight(pos)) { return null; } else { @@ -30470,7 +30470,7 @@ index 63f8b0c47e3321b74f4b6bcbc1e28cd751911198..eb4d03cfdb34243901cfba832d35559d ? null : this.getChunkAt(pos).getBlockEntity(pos, LevelChunk.EntityCreationType.IMMEDIATE); } -@@ -1087,22 +1735,16 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -1088,22 +1736,16 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl public List getEntities(@Nullable Entity entity, AABB boundingBox, Predicate predicate) { Profiler.get().incrementCounter("getEntities"); List list = Lists.newArrayList(); @@ -30501,7 +30501,7 @@ index 63f8b0c47e3321b74f4b6bcbc1e28cd751911198..eb4d03cfdb34243901cfba832d35559d } @Override -@@ -1116,33 +1758,94 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -1117,33 +1759,94 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl this.getEntities(entityTypeTest, bounds, predicate, output, Integer.MAX_VALUE); } diff --git a/paper-server/patches/features/0018-Add-Alternate-Current-redstone-implementation.patch b/paper-server/patches/features/0018-Add-Alternate-Current-redstone-implementation.patch index c505fb79b854..e49f837cb8ab 100644 --- a/paper-server/patches/features/0018-Add-Alternate-Current-redstone-implementation.patch +++ b/paper-server/patches/features/0018-Add-Alternate-Current-redstone-implementation.patch @@ -2352,10 +2352,10 @@ index 8afe96bfdc37e57129f1bb4af5b6d5cc22c11aee..32db2b9e375c12cbf7abab69cc01e8ac @Override public void onCreated(Entity entity) { diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index eb4d03cfdb34243901cfba832d35559d5be9e876..013ed7dbe2309f562f63e66203179a90566e8115 100644 +index e6f2fe03ec55f4ae1fa6c94af48db798795de72a..a031dcbcc97a3345cdd5f5bcd9d6aa23cbc1ad0d 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java -@@ -2096,6 +2096,17 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -2097,6 +2097,17 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl return 0; } diff --git a/paper-server/patches/sources/net/minecraft/world/item/BowItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/BowItem.java.patch new file mode 100644 index 000000000000..6aa97d08dd9d --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/item/BowItem.java.patch @@ -0,0 +1,14 @@ +--- a/net/minecraft/world/item/BowItem.java ++++ b/net/minecraft/world/item/BowItem.java +@@ -36,9 +_,9 @@ + if (powerForTime < 0.1) { + return false; + } else { +- List list = draw(stack, projectile, player); ++ List list = draw(stack, projectile, player, ProjectileDrawingItemConsumption.MAYBE_LATER); // Paper - prevent item consumption for cancelled events + if (level instanceof ServerLevel serverLevel && !list.isEmpty()) { +- this.shoot(serverLevel, player, player.getUsedItemHand(), stack, list, powerForTime * 3.0F, 1.0F, powerForTime == 1.0F, null); ++ if (!this.shoot(serverLevel, player, player.getUsedItemHand(), stack, new UnrealizedDrawResult(list, projectile), powerForTime * 3.0F, 1.0F, powerForTime == 1.0F, null)) return false; // Paper - prevent item consumption for cancelled events + } + + level.playSound( diff --git a/paper-server/patches/sources/net/minecraft/world/item/CrossbowItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/CrossbowItem.java.patch index ef4344e7f7c3..d3155addca5b 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/CrossbowItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/CrossbowItem.java.patch @@ -12,11 +12,24 @@ + } + + private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbowStack, boolean consume) { -+ List list = draw(crossbowStack, shooter.getProjectile(crossbowStack), shooter, consume); ++ List list = draw(crossbowStack, shooter.getProjectile(crossbowStack), shooter, consume ? ProjectileDrawingItemConsumption.IMMEDIATELY : ProjectileDrawingItemConsumption.NEVER); // Paper - prevent item consumption for cancelled events + // Paper end - Add EntityLoadCrossbowEvent if (!list.isEmpty()) { crossbowStack.set(DataComponents.CHARGED_PROJECTILES, ChargedProjectiles.of(list)); return true; +@@ -122,8 +_,10 @@ + } + + projectile.shoot(projectileShotVector.x(), projectileShotVector.y(), projectileShotVector.z(), velocity, inaccuracy); +- float shotPitch = getShotPitch(shooter.getRandom(), index); +- shooter.level().playSound(null, shooter.getX(), shooter.getY(), shooter.getZ(), SoundEvents.CROSSBOW_SHOOT, shooter.getSoundSource(), 1.0F, shotPitch); ++ // Paper start - moved up to ensure events weren't cancelled ++ // float shotPitch = getShotPitch(shooter.getRandom(), index); ++ // shooter.level().playSound(null, shooter.getX(), shooter.getY(), shooter.getZ(), SoundEvents.CROSSBOW_SHOOT, shooter.getSoundSource(), 1.0F, shotPitch); ++ // Paper end - moved up to ensure events weren't cancelled + } + + private static Vector3f getProjectileShotVector(LivingEntity shooter, Vec3 distance, float angle) { @@ -141,7 +_,11 @@ @Override protected Projectile createProjectile(Level level, LivingEntity shooter, ItemStack weapon, ItemStack ammo, boolean isCrit) { @@ -30,6 +43,27 @@ } else { Projectile projectile = super.createProjectile(level, shooter, weapon, ammo, isCrit); if (projectile instanceof AbstractArrow abstractArrow) { +@@ -161,9 +_,9 @@ + Level level, LivingEntity shooter, InteractionHand hand, ItemStack weapon, float velocity, float inaccuracy, @Nullable LivingEntity target + ) { + if (level instanceof ServerLevel serverLevel) { +- ChargedProjectiles chargedProjectiles = weapon.set(DataComponents.CHARGED_PROJECTILES, ChargedProjectiles.EMPTY); ++ ChargedProjectiles chargedProjectiles = weapon.get(DataComponents.CHARGED_PROJECTILES); // Paper - prevent item consumption for cancelled events + if (chargedProjectiles != null && !chargedProjectiles.isEmpty()) { +- this.shoot(serverLevel, shooter, hand, weapon, chargedProjectiles.getItems(), velocity, inaccuracy, shooter instanceof Player, target); ++ if (!this.shoot(serverLevel, shooter, hand, weapon, chargedProjectiles.getItems(), velocity, inaccuracy, shooter instanceof Player, target)) return; // Paper - prevent item consumption for cancelled events + if (shooter instanceof ServerPlayer serverPlayer) { + CriteriaTriggers.SHOT_CROSSBOW.trigger(serverPlayer, weapon); + serverPlayer.awardStat(Stats.ITEM_USED.get(weapon.getItem())); +@@ -172,7 +_,7 @@ + } + } + +- private static float getShotPitch(RandomSource random, int index) { ++ public static float getShotPitch(RandomSource random, int index) { + return index == 0 ? 1.0F : getRandomShotPitch((index & 1) == 1, random); + } + @@ -211,7 +_,14 @@ ); } diff --git a/paper-server/patches/sources/net/minecraft/world/item/ProjectileWeaponItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/ProjectileWeaponItem.java.patch index 012015c2670e..10ceb3d958ea 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/ProjectileWeaponItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/ProjectileWeaponItem.java.patch @@ -1,6 +1,53 @@ --- a/net/minecraft/world/item/ProjectileWeaponItem.java +++ b/net/minecraft/world/item/ProjectileWeaponItem.java -@@ -62,12 +_,29 @@ +@@ -40,7 +_,20 @@ + + public abstract int getDefaultProjectileRange(); + +- protected void shoot( ++ // Paper start - prevent item consumption for cancelled events ++ protected record UnrealizedDrawResult( ++ List projectileStacks, ++ @Nullable ItemStack originalInPlayerInventory // Null in case the unrealised draw result is a noop (case of Crossbow) ++ ) { ++ public void consumeProjectilesFromPlayerInventory(int projectStackIndex) { ++ if (projectStackIndex != 0 || originalInPlayerInventory == null) return; ++ if (projectileStacks.isEmpty()) return; // Whatever happened here, nothing ++ final ItemStack nonIntangibleStack = projectileStacks.get(projectStackIndex); ++ originalInPlayerInventory.shrink(nonIntangibleStack.getCount()); ++ } ++ } ++ protected boolean shoot( ++ // Paper end - prevent item consumption for cancelled events + ServerLevel level, + LivingEntity shooter, + InteractionHand hand, +@@ -51,6 +_,24 @@ + boolean isCrit, + @Nullable LivingEntity target + ) { ++ // Paper start - prevent item consumption for cancelled events ++ return shoot(level, shooter, hand, weapon, new UnrealizedDrawResult(projectileItems, null), velocity, inaccuracy, isCrit, target); ++ } ++ ++ protected boolean shoot( ++ ServerLevel level, ++ LivingEntity shooter, ++ InteractionHand hand, ++ ItemStack weapon, ++ UnrealizedDrawResult unrealizedDrawResult, ++ float velocity, ++ float inaccuracy, ++ boolean isCrit, ++ @Nullable LivingEntity target ++ ) { ++ List projectileItems = unrealizedDrawResult.projectileStacks(); ++ boolean atLeastOneShootBowEventUncancelled = false; ++ // Paper end - prevent item consumption for cancelled events + float f = EnchantmentHelper.processProjectileSpread(level, weapon, shooter, 0.0F); + float f1 = projectileItems.size() == 1 ? 0.0F : 2.0F * f / (projectileItems.size() - 1); + float f2 = (projectileItems.size() - 1) % 2 * f1 / 2.0F; +@@ -62,18 +_,55 @@ float f4 = f2 + f3 * ((i + 1) / 2) * f1; f3 = -f3; int i1 = i; @@ -14,11 +61,13 @@ + Projectile projectile = this.createProjectile(level, shooter, weapon, itemStack, isCrit); + this.shootProjectile(shooter, projectile, i1, velocity, inaccuracy, f4, target); + -+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(shooter, weapon, itemStack, projectile, hand, velocity, true); ++ boolean preConsumption = weapon.is(Items.CROSSBOW) || shooter.level().shouldConsumeArrow; ++ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(shooter, weapon, itemStack, projectile, hand, velocity, preConsumption); + if (event.isCancelled()) { + event.getProjectile().remove(); -+ return; ++ continue; // Paper - prevent item consumption for cancelled events; call for each shot projectile + } ++ atLeastOneShootBowEventUncancelled = true; // Paper - prevent item consumption for cancelled events + + if (event.getProjectile() == projectile.getBukkitEntity()) { + if (Projectile.spawnProjectile( @@ -29,31 +78,93 @@ + if (shooter instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { + serverPlayer.containerMenu.sendAllDataToRemote(); + } -+ return; ++ // Paper start - prevent item consumption for cancelled events ++ continue; // call for each shot projectile ++ } ++ } ++ if (this instanceof CrossbowItem crossbow) { ++ // moved up to ensure events uncancelled ++ float shotPitch = crossbow.getShotPitch(shooter.getRandom(), i1); ++ shooter.level().playSound(null, shooter.getX(), shooter.getY(), shooter.getZ(), net.minecraft.sounds.SoundEvents.CROSSBOW_SHOOT, shooter.getSoundSource(), 1.0F, shotPitch); ++ } ++ if (!event.shouldConsumeItem() && projectile instanceof final AbstractArrow abstractArrow) abstractArrow.pickup = AbstractArrow.Pickup.CREATIVE_ONLY; ++ if (event.shouldConsumeItem()) { ++ if (weapon.is(net.minecraft.world.item.Items.CROSSBOW)) { ++ List newProjectiles = new java.util.ArrayList<>(weapon.get(DataComponents.CHARGED_PROJECTILES).getItems()); ++ newProjectiles.remove(i - (projectileItems.size() - newProjectiles.size())); ++ weapon.set(DataComponents.CHARGED_PROJECTILES, net.minecraft.world.item.component.ChargedProjectiles.of(newProjectiles)); ++ } else if (level.shouldConsumeArrow) { ++ unrealizedDrawResult.consumeProjectilesFromPlayerInventory(i); ++ // Paper end - prevent item consumption for cancelled events + } + } + // CraftBukkit end weapon.hurtAndBreak(this.getDurabilityUse(itemStack), shooter, LivingEntity.getSlotForHand(hand)); if (weapon.isEmpty()) { break; -@@ -95,6 +_,11 @@ + } + } + } ++ return atLeastOneShootBowEventUncancelled; // Paper - prevent item consumption for cancelled events + } + + protected int getDurabilityUse(ItemStack stack) { +@@ -95,6 +_,21 @@ } protected static List draw(ItemStack weapon, ItemStack ammo, LivingEntity shooter) { -+ // Paper start -+ return draw(weapon, ammo, shooter, true); ++ // Paper start - prevent item consumption for cancelled events ++ return draw(weapon, ammo, shooter, ProjectileDrawingItemConsumption.IMMEDIATELY); ++ } ++ protected enum ProjectileDrawingItemConsumption { ++ // Will immediately consume from the passed projectile stack, like vanilla would ++ IMMEDIATELY, ++ // Will create a copyWithCount from the projectileStack, allowing for later reduction. ++ // The stacks yielded will adhere to vanilla's intangibility layout, with the first itemstack ++ // being tangible, allowing for it to be picked up once shot. ++ // Callers that do *not* consume later are responsible for marking the shot projectile as intangible. ++ MAYBE_LATER, ++ NEVER, + } -+ protected static List draw(ItemStack weapon, ItemStack ammo, LivingEntity shooter, boolean consume) { -+ // Paper end ++ protected static List draw(ItemStack weapon, ItemStack ammo, LivingEntity shooter, final ProjectileDrawingItemConsumption consume) { ++ // Paper end - prevent item consumption for cancelled events if (ammo.isEmpty()) { return List.of(); } else { -@@ -103,7 +_,7 @@ +@@ -102,8 +_,9 @@ + List list = new ArrayList<>(i); ItemStack itemStack = ammo.copy(); ++ shooter.level().shouldConsumeArrow = true; // Paper - prevent item consumption for cancelled events for (int i1 = 0; i1 < i; i1++) { - ItemStack itemStack1 = useAmmo(weapon, i1 == 0 ? ammo : itemStack, shooter, i1 > 0); -+ ItemStack itemStack1 = useAmmo(weapon, i1 == 0 ? ammo : itemStack, shooter, i1 > 0 || !consume); // Paper ++ ItemStack itemStack1 = useAmmo(weapon, i1 == 0 ? ammo : itemStack, shooter, i1 > 0, consume); // Paper if (!itemStack1.isEmpty()) { list.add(itemStack1); } +@@ -114,17 +_,23 @@ + } + + protected static ItemStack useAmmo(ItemStack weapon, ItemStack ammo, LivingEntity shooter, boolean intangable) { +- int i = !intangable && !shooter.hasInfiniteMaterials() && shooter.level() instanceof ServerLevel serverLevel ++ // Paper start - prevent item consumption for cancelled events ++ return useAmmo(weapon, ammo, shooter, intangable, ProjectileDrawingItemConsumption.IMMEDIATELY); ++ } ++ protected static ItemStack useAmmo(ItemStack weapon, ItemStack ammo, LivingEntity shooter, boolean intangable, final ProjectileDrawingItemConsumption consumption) { ++ int i = !intangable && consumption != ProjectileDrawingItemConsumption.NEVER && !shooter.hasInfiniteMaterials() && shooter.level() instanceof ServerLevel serverLevel + ? EnchantmentHelper.processAmmoUse(serverLevel, weapon, ammo, 1) + : 0; ++ // Paper end - prevent item consumption for cancelled events + if (i > ammo.getCount()) { + return ItemStack.EMPTY; + } else if (i == 0) { ++ if (!intangable) shooter.level().shouldConsumeArrow = false; // Paper - prevent item consumption for cancelled events + ItemStack itemStack = ammo.copyWithCount(1); + itemStack.set(DataComponents.INTANGIBLE_PROJECTILE, Unit.INSTANCE); + return itemStack; + } else { +- ItemStack itemStack = ammo.split(i); ++ ItemStack itemStack = consumption == ProjectileDrawingItemConsumption.MAYBE_LATER ? ammo.copyWithCount(i) : ammo.split(i); // Paper - prevent item consumption for cancelled events + if (ammo.isEmpty() && shooter instanceof Player player) { + player.getInventory().removeItem(ammo); + } diff --git a/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch b/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch index e037c3af1bbf..2977dd490287 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch @@ -17,7 +17,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCloseable { public static final Codec> RESOURCE_KEY_CODEC = ResourceKey.codec(Registries.DIMENSION); public static final ResourceKey OVERWORLD = ResourceKey.create(Registries.DIMENSION, ResourceLocation.withDefaultNamespace("overworld")); -@@ -121,6 +_,57 @@ +@@ -121,6 +_,58 @@ private final DamageSources damageSources; private long subTickCount; @@ -46,6 +46,7 @@ + private int tileTickPosition; + public final Map explosionDensityCache = new java.util.HashMap<>(); // Paper - Optimize explosions + public java.util.ArrayDeque redstoneUpdateInfos; // Paper - Faster redstone torch rapid clock removal; Move from Map in BlockRedstoneTorch to here ++ public boolean shouldConsumeArrow = true; // Paper - prevent item consumption for cancelled shot events + + public CraftWorld getWorld() { + return this.world;