diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownPotion.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownPotion.java.patch index 78d6c5996e..36b79fa5b2 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownPotion.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownPotion.java.patch @@ -55,47 +55,98 @@ super(EntityType.POTION, owner, world, stack); } -@@ -101,28 +111,28 @@ +@@ -99,64 +109,86 @@ + ItemStack itemstack = this.getItem(); + PotionContents potioncontents = (PotionContents) itemstack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY); ++ boolean showParticles = true; // Paper - Fix potions splash events if (potioncontents.is(Potions.WATER)) { - this.applyWater(worldserver); +- this.applyWater(worldserver); - } else if (potioncontents.hasEffects()) { ++ showParticles = this.applyWater(worldserver, hitResult); // Paper - Fix potions splash events + } else if (true || potioncontents.hasEffects()) { // CraftBukkit - Call event even if no effects to apply if (this.isLingering()) { - this.makeAreaOfEffectCloud(potioncontents); -+ this.makeAreaOfEffectCloud(potioncontents, hitResult); // CraftBukkit - Pass MovingObjectPosition ++ showParticles = this.makeAreaOfEffectCloud(potioncontents, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper } else { - this.applySplash(worldserver, potioncontents.getAllEffects(), hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null); -+ this.applySplash(worldserver, potioncontents.getAllEffects(), hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null, hitResult); // CraftBukkit - Pass MovingObjectPosition ++ showParticles = this.applySplash(worldserver, potioncontents.getAllEffects(), hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper } } ++ if (showParticles) { // Paper - Fix potions splash events int i = potioncontents.potion().isPresent() && ((Potion) ((Holder) potioncontents.potion().get()).value()).hasInstantEffects() ? 2007 : 2002; worldserver.levelEvent(i, this.blockPosition(), potioncontents.getColor()); - this.discard(); ++ } // Paper - Fix potions splash events + this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause } } - private void applyWater(ServerLevel world) { +- private void applyWater(ServerLevel world) { ++ private static final Predicate APPLY_WATER_GET_ENTITIES_PREDICATE = ThrownPotion.WATER_SENSITIVE_OR_ON_FIRE.or(Axolotl.class::isInstance); // Paper - Fix potions splash events ++ private boolean applyWater(ServerLevel world, @Nullable HitResult hitResult) { // Paper - Fix potions splash events AABB axisalignedbb = this.getBoundingBox().inflate(4.0D, 2.0D, 4.0D); - List list = this.level().getEntitiesOfClass(LivingEntity.class, axisalignedbb, ThrownPotion.WATER_SENSITIVE_OR_ON_FIRE); -+ List list = this.level().getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb, ThrownPotion.WATER_SENSITIVE_OR_ON_FIRE); ++ // Paper start - Fix potions splash events ++ List list = this.level().getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb, ThrownPotion.APPLY_WATER_GET_ENTITIES_PREDICATE); ++ Map affected = new HashMap<>(); ++ java.util.Set rehydrate = new java.util.HashSet<>(); ++ java.util.Set extinguish = new java.util.HashSet<>(); Iterator iterator = list.iterator(); while (iterator.hasNext()) { - LivingEntity entityliving = (LivingEntity) iterator.next(); + net.minecraft.world.entity.LivingEntity entityliving = (net.minecraft.world.entity.LivingEntity) iterator.next(); ++ if (entityliving instanceof Axolotl axolotl) { ++ rehydrate.add(((org.bukkit.entity.Axolotl) axolotl.getBukkitEntity())); ++ } double d0 = this.distanceToSqr((Entity) entityliving); if (d0 < 16.0D) { -@@ -147,16 +157,17 @@ + if (entityliving.isSensitiveToWater()) { +- entityliving.hurtServer(world, this.damageSources().indirectMagic(this, this.getOwner()), 1.0F); ++ affected.put(entityliving.getBukkitLivingEntity(), 1.0); + } + + if (entityliving.isOnFire() && entityliving.isAlive()) { +- entityliving.extinguishFire(); ++ extinguish.add(entityliving.getBukkitLivingEntity()); + } + } + } + +- List list1 = this.level().getEntitiesOfClass(Axolotl.class, axisalignedbb); +- Iterator iterator1 = list1.iterator(); +- +- while (iterator1.hasNext()) { +- Axolotl axolotl = (Axolotl) iterator1.next(); +- +- axolotl.rehydrate(); ++ io.papermc.paper.event.entity.WaterBottleSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callWaterBottleSplashEvent( ++ this, hitResult, affected, rehydrate, extinguish ++ ); ++ if (!event.isCancelled()) { ++ for (LivingEntity affectedEntity : event.getToDamage()) { ++ ((CraftLivingEntity) affectedEntity).getHandle().hurtServer(world, this.damageSources().indirectMagic(this, this.getOwner()), 1.0F); ++ } ++ for (LivingEntity toExtinguish : event.getToExtinguish()) { ++ ((CraftLivingEntity) toExtinguish).getHandle().extinguishFire(); ++ } ++ for (LivingEntity toRehydrate : event.getToRehydrate()) { ++ if (((CraftLivingEntity) toRehydrate).getHandle() instanceof Axolotl axolotl) { ++ axolotl.rehydrate(); ++ } ++ } ++ // Paper end - Fix potions splash events + } ++ return !event.isCancelled(); // Paper - Fix potions splash events } - private void applySplash(ServerLevel world, Iterable effects, @Nullable Entity entity) { -+ private void applySplash(ServerLevel worldserver, Iterable iterable, @Nullable Entity entity, HitResult position) { // CraftBukkit - Pass MovingObjectPosition ++ private boolean applySplash(ServerLevel worldserver, Iterable iterable, @Nullable Entity entity, HitResult position) { // CraftBukkit - Pass MovingObjectPosition // Paper - Fix potions splash events AABB axisalignedbb = this.getBoundingBox().inflate(4.0D, 2.0D, 4.0D); - List list = world.getEntitiesOfClass(LivingEntity.class, axisalignedbb); + List list = worldserver.getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb); @@ -111,7 +162,14 @@ if (entityliving.isAffectedByPotions()) { double d0 = this.distanceToSqr((Entity) entityliving); -@@ -170,37 +181,63 @@ +@@ -164,43 +196,71 @@ + if (d0 < 16.0D) { + double d1; + ++ // Paper - diff on change, used when calling the splash event for water splash potions + if (entityliving == entity) { + d1 = 1.0D; + } else { d1 = 1.0D - Math.sqrt(d0) / 4.0D; } @@ -179,11 +237,12 @@ } } } ++ return !event.isCancelled(); // Paper - Fix potions splash events } - private void makeAreaOfEffectCloud(PotionContents potion) { -+ private void makeAreaOfEffectCloud(PotionContents potioncontents, HitResult position) { // CraftBukkit - Pass MovingObjectPosition ++ private boolean makeAreaOfEffectCloud(PotionContents potioncontents, HitResult position) { // CraftBukkit - Pass MovingObjectPosition AreaEffectCloud entityareaeffectcloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ()); Entity entity = this.getOwner(); @@ -192,25 +251,27 @@ entityareaeffectcloud.setOwner(entityliving); } -@@ -208,8 +245,15 @@ +@@ -208,8 +268,17 @@ entityareaeffectcloud.setRadiusOnUse(-0.5F); entityareaeffectcloud.setWaitTime(10); entityareaeffectcloud.setRadiusPerTick(-entityareaeffectcloud.getRadius() / (float) entityareaeffectcloud.getDuration()); - entityareaeffectcloud.setPotionContents(potion); - this.level().addFreshEntity(entityareaeffectcloud); + entityareaeffectcloud.setPotionContents(potioncontents); ++ boolean noEffects = potioncontents.hasEffects(); // Paper - Fix potions splash events + // CraftBukkit start + org.bukkit.event.entity.LingeringPotionSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callLingeringPotionSplashEvent(this, position, entityareaeffectcloud); -+ if (!(event.isCancelled() || entityareaeffectcloud.isRemoved())) { ++ if (!(event.isCancelled() || entityareaeffectcloud.isRemoved() || (noEffects && !entityareaeffectcloud.potionContents.hasEffects()))) { // Paper - don't spawn area effect cloud if the effects were empty and not changed during the event handling + this.level().addFreshEntity(entityareaeffectcloud); + } else { + entityareaeffectcloud.discard(null); // CraftBukkit - add Bukkit remove cause + } + // CraftBukkit end ++ return !event.isCancelled(); // Paper - Fix potions splash events } public boolean isLingering() { -@@ -220,19 +264,31 @@ +@@ -220,19 +289,31 @@ BlockState iblockdata = this.level().getBlockState(pos); if (iblockdata.is(BlockTags.FIRE)) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index 49efae4034..24f8672401 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -884,6 +884,32 @@ public class CraftEventFactory { return event; } + // Paper start - Fix potions splash events + public static io.papermc.paper.event.entity.WaterBottleSplashEvent callWaterBottleSplashEvent(net.minecraft.world.entity.projectile.ThrownPotion potion, @Nullable HitResult hitResult, Map affectedEntities, java.util.Set rehydrate, java.util.Set extinguish) { + ThrownPotion thrownPotion = (ThrownPotion) potion.getBukkitEntity(); + + Block hitBlock = null; + BlockFace hitFace = null; + org.bukkit.entity.Entity hitEntity = null; + + if (hitResult != null) { + if (hitResult.getType() == HitResult.Type.BLOCK) { + BlockHitResult blockHitResult = (BlockHitResult) hitResult; + hitBlock = CraftBlock.at(potion.level(), blockHitResult.getBlockPos()); + hitFace = CraftBlock.notchToBlockFace(blockHitResult.getDirection()); + } else if (hitResult.getType() == HitResult.Type.ENTITY) { + hitEntity = ((EntityHitResult) hitResult).getEntity().getBukkitEntity(); + } + } + + io.papermc.paper.event.entity.WaterBottleSplashEvent event = new io.papermc.paper.event.entity.WaterBottleSplashEvent( + thrownPotion, hitEntity, hitBlock, hitFace, affectedEntities, rehydrate, extinguish + ); + event.callEvent(); + return event; + } + // Paper end - Fix potions splash events + /** * BlockFadeEvent */