From ed890511504aaf78415856c79d556b699af1659d Mon Sep 17 00:00:00 2001 From: Charles Richards Date: Thu, 20 Aug 2026 00:56:04 -0700 Subject: [PATCH] Assign BlockProjectileSource before dispenser projectiles spawn ProjectileDispenseBehavior assigned projectileSource only after spawnProjectileUsingShoot had already inserted the entity into the world, so ProjectileLaunchEvent observed a null shooter. Use the existing delayed spawn path instead: create and configure the projectile, attach the CraftBlockProjectileSource, then spawn it. --- .../core/dispenser/ProjectileDispenseBehavior.java.patch | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java.patch index 772e836788a4..a32c4bc9de25 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java +++ b/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java -@@ -27,17 +_,36 @@ +@@ -27,17 +_,38 @@ ServerLevel level = source.level(); Direction direction = source.state().getValue(DispenserBlock.FACING); Position position = this.dispenseConfig.positionFunction().getDispensePosition(source, direction); @@ -40,8 +40,10 @@ + + // SPIGOT-7923: Avoid create projectiles with empty item + if (!singleItemStack.isEmpty()) { -+ Projectile projectile = Projectile.spawnProjectileUsingShoot(this.projectileItem.asProjectile(level, position, org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getItem()), direction), level, singleItemStack, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.dispenseConfig.power(), this.dispenseConfig.uncertainty()); // Paper - track changed items in the dispense event; unwrap is safe here because all uses of the stack make their own copies ++ Projectile projectile = this.projectileItem.asProjectile(level, position, org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getItem()), direction); // Paper - track changed items in the dispense event; unwrap is safe here because all uses of the stack make their own copies ++ Projectile.Delayed delayedProjectile = Projectile.spawnProjectileUsingShootDelayed(projectile, level, singleItemStack, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.dispenseConfig.power(), this.dispenseConfig.uncertainty()); + projectile.projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource(source.blockEntity()); ++ delayedProjectile.spawn(); + } + if (shrink) dispensed.shrink(1); + // CraftBukkit end