9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-25 18:09:17 +00:00

Merge remote-tracking branch 'origin/ver/1.21.4' into ver/1.21.4

This commit is contained in:
Taiyou06
2025-03-19 13:02:48 +01:00
2 changed files with 243 additions and 0 deletions

View File

@@ -10,6 +10,7 @@ public net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities nearbyE
public net.minecraft.world.entity.decoration.ArmorStand noTickEquipmentDirty
public net.minecraft.world.entity.monster.Shulker MAX_SCALE
public net.minecraft.world.entity.player.Player canGlide()Z
public net.minecraft.world.item.CrossbowItem getShotPitch(Lnet/minecraft/util/RandomSource;I)F
public net.minecraft.world.level.block.entity.FuelValues values
public net.minecraft.world.level.chunk.storage.RegionFile getOversizedData(II)Lnet/minecraft/nbt/CompoundTag;
public net.minecraft.world.level.chunk.storage.RegionFile isOversized(II)Z

View File

@@ -0,0 +1,242 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tamion <70228790+notTamion@users.noreply.github.com>
Date: Sun, 16 Feb 2025 12:22:53 +0100
Subject: [PATCH] PaperPR: Fix cancelled Projectile Events still consuming
arrows
Original license: GPLv3
Original project: https://github.com/PaperMC/Paper
Paper pull request: https://github.com/PaperMC/Paper/pull/12124
fixes https://github.com/PaperMC/Paper/issues/12123
diff --git a/net/minecraft/world/item/BowItem.java b/net/minecraft/world/item/BowItem.java
index b3e003694ce0da357e91ab3ce2b1380f9ab0a32a..4d5347a6a2fc8b10d11f89220f537c81a9a7be71 100644
--- a/net/minecraft/world/item/BowItem.java
+++ b/net/minecraft/world/item/BowItem.java
@@ -41,9 +41,9 @@ public class BowItem extends ProjectileWeaponItem {
if (powerForTime < 0.1) {
return false;
} else {
- List<ItemStack> list = draw(stack, projectile, player);
+ List<ItemStack> 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, (float) serverLevel.purpurConfig.bowProjectileOffset, powerForTime == 1.0F, null); // Purpur - Projectile offset config
+ if (!this.shoot(serverLevel, player, player.getUsedItemHand(), stack, new UnrealizedDrawResult(list, projectile), powerForTime * 3.0F, (float) serverLevel.purpurConfig.bowProjectileOffset, powerForTime == 1.0F, null)) return false; // Purpur - Projectile offset config // Paper - prevent item consumption for cancelled events
}
level.playSound(
diff --git a/net/minecraft/world/item/CrossbowItem.java b/net/minecraft/world/item/CrossbowItem.java
index 318316d3aa14f1e9e863d435515c182619a81b3e..b13f03ae35e21088c2b4b388e2b12cf3fe3ef8c6 100644
--- a/net/minecraft/world/item/CrossbowItem.java
+++ b/net/minecraft/world/item/CrossbowItem.java
@@ -124,7 +124,7 @@ public class CrossbowItem extends ProjectileWeaponItem {
return CrossbowItem.tryLoadProjectiles(shooter, crossbowStack, true);
}
private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbowStack, boolean consume) {
- List<ItemStack> list = draw(crossbowStack, shooter.getProjectile(crossbowStack), shooter, consume);
+ List<ItemStack> 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));
@@ -158,8 +158,10 @@ public class CrossbowItem extends ProjectileWeaponItem {
}
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) {
@@ -201,9 +203,9 @@ public class CrossbowItem extends ProjectileWeaponItem {
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()));
diff --git a/net/minecraft/world/item/ProjectileWeaponItem.java b/net/minecraft/world/item/ProjectileWeaponItem.java
index f20c38c1ff978d00dc0c9810c050506deed44ebd..e58a40623c3a259c80d0f96686797445f54f3a6f 100644
--- a/net/minecraft/world/item/ProjectileWeaponItem.java
+++ b/net/minecraft/world/item/ProjectileWeaponItem.java
@@ -40,7 +40,20 @@ public abstract class ProjectileWeaponItem extends Item {
public abstract int getDefaultProjectileRange();
- protected void shoot(
+ // Paper start - prevent item consumption for cancelled events
+ protected record UnrealizedDrawResult(
+ List<ItemStack> 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 +64,23 @@ public abstract class ProjectileWeaponItem extends Item {
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<ItemStack> 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;
@@ -66,11 +96,13 @@ public abstract class ProjectileWeaponItem extends Item {
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(
@@ -81,7 +113,25 @@ public abstract class ProjectileWeaponItem extends Item {
if (shooter instanceof net.minecraft.server.level.ServerPlayer serverPlayer) {
serverPlayer.getBukkitEntity().updateInventory();
}
- 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<ItemStack> 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
@@ -91,6 +141,7 @@ public abstract class ProjectileWeaponItem extends Item {
}
}
}
+ return atLeastOneShootBowEventUncancelled; // Paper - prevent item consumption for cancelled events
}
protected int getDurabilityUse(ItemStack stack) {
@@ -114,11 +165,21 @@ public abstract class ProjectileWeaponItem extends Item {
}
protected static List<ItemStack> 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 static List<ItemStack> draw(ItemStack weapon, ItemStack ammo, LivingEntity shooter, boolean consume) {
- // Paper end
+ 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<ItemStack> 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 {
@@ -126,8 +187,9 @@ public abstract class ProjectileWeaponItem extends Item {
List<ItemStack> 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 || !consume); // Paper
+ ItemStack itemStack1 = useAmmo(weapon, i1 == 0 ? ammo : itemStack, shooter, i1 > 0, consume); // Paper
if (!itemStack1.isEmpty()) {
list.add(itemStack1);
}
@@ -138,17 +200,23 @@ public abstract class ProjectileWeaponItem extends Item {
}
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/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index da579769cee175cfbf342efd643efe6f87e0a822..cfd66b5987a38bb3a4e32aa4c161e06a2d6be4be 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -183,6 +183,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
private int tileTickPosition;
public final Map<ServerExplosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
public java.util.ArrayDeque<net.minecraft.world.level.block.RedstoneTorchBlock.Toggle> 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 final net.minecraft.world.level.levelgen.BitRandomSource simpleRandom = org.dreeam.leaf.config.modules.opt.FastRNG.enabled ? new org.dreeam.leaf.util.math.random.FasterRandomSource(net.minecraft.world.level.levelgen.RandomSupport.generateUniqueSeed()) : new ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom(net.minecraft.world.level.levelgen.RandomSupport.generateUniqueSeed()); // Gale - Pufferfish - move random tick random // Leaf - Faster random generator