From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Thu, 20 May 2021 20:40:53 -0700 Subject: [PATCH] Fix potions splash events Fix PotionSplashEvent for water splash potions Fixes SPIGOT-6221: https://hub.spigotmc.org/jira/projects/SPIGOT/issues/SPIGOT-6221 Fix splash events cancellation that still show particles/sound diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java index 6e921bf7101224d6b8261ab8d87724080c4095d7..0204257ca0245830534592922e400a362c347715 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java +++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java @@ -106,56 +106,77 @@ public class ThrownPotion extends ThrowableItemProjectile implements ItemSupplie Potion potionregistry = PotionUtils.getPotion(itemstack); List list = PotionUtils.getMobEffects(itemstack); boolean flag = potionregistry == Potions.WATER && list.isEmpty(); + boolean showParticles = true; // Paper - Fix potions splash events if (flag) { - this.applyWater(); + showParticles = this.applyWater(hitResult); // Paper - Fix potions splash events } else if (true || !list.isEmpty()) { // CraftBukkit - Call event even if no effects to apply if (this.isLingering()) { - this.makeAreaOfEffectCloud(itemstack, potionregistry, hitResult); // CraftBukkit - Pass MovingObjectPosition + showParticles = this.makeAreaOfEffectCloud(itemstack, potionregistry, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper } else { - this.applySplash(list, hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null, hitResult); // CraftBukkit - Pass MovingObjectPosition + showParticles = this.applySplash(list, hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper } } + if (showParticles) { // Paper - Fix potions splash events int i = potionregistry.hasInstantEffects() ? 2007 : 2002; this.level().levelEvent(i, this.blockPosition(), PotionUtils.getColor(itemstack)); + } // Paper - Fix potions splash events this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause } } - private void applyWater() { + 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(@Nullable HitResult hitResult) { // Paper - Fix potions splash events AABB axisalignedbb = this.getBoundingBox().inflate(4.0D, 2.0D, 4.0D); - 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()) { 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) { if (entityliving.isSensitiveToWater()) { - entityliving.hurt(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().hurt(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(List list, @Nullable Entity entity, HitResult position) { // CraftBukkit - Pass MovingObjectPosition + private boolean applySplash(List list, @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 list1 = this.level().getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb); Map affected = new HashMap(); // CraftBukkit @@ -173,6 +194,7 @@ public class ThrownPotion extends ThrowableItemProjectile implements ItemSupplie 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 { @@ -227,10 +249,11 @@ public class ThrownPotion extends ThrowableItemProjectile implements ItemSupplie } } } + return !event.isCancelled(); // Paper - Fix potions splash events } - private void makeAreaOfEffectCloud(ItemStack itemstack, Potion potionregistry, HitResult position) { // CraftBukkit - Pass MovingObjectPosition + private boolean makeAreaOfEffectCloud(ItemStack itemstack, Potion potionregistry, HitResult position) { // CraftBukkit - Pass MovingObjectPosition // Paper - return boolean AreaEffectCloud entityareaeffectcloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ()); Entity entity = this.getOwner(); @@ -245,10 +268,12 @@ public class ThrownPotion extends ThrowableItemProjectile implements ItemSupplie entityareaeffectcloud.setPotion(potionregistry); Iterator iterator = PotionUtils.getCustomEffects(itemstack).iterator(); + boolean noEffects = potionregistry.getEffects().isEmpty(); // Paper - Fix potions splash events while (iterator.hasNext()) { MobEffectInstance mobeffect = (MobEffectInstance) iterator.next(); entityareaeffectcloud.addEffect(new MobEffectInstance(mobeffect)); + noEffects = false; // Paper - Fix potions splash events } CompoundTag nbttagcompound = itemstack.getTag(); @@ -259,12 +284,13 @@ public class ThrownPotion extends ThrowableItemProjectile implements ItemSupplie // 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.effects.isEmpty() && entityareaeffectcloud.getPotion().getEffects().isEmpty()))) { // 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() { diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index 5d4fe10d4e3a5d7a9430dbd5b3c850db482f5862..74df21363c96dbf82337550ae2d8525e82eaface 100644 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -876,6 +876,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 */