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
This commit is contained in:
Jake Potrebic 2021-05-20 20:40:53 -07:00
parent 9b7c0ce420
commit 0bf80e49be
2 changed files with 100 additions and 13 deletions

View file

@ -55,47 +55,98 @@
super(EntityType.POTION, owner, world, stack); 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)) { if (potioncontents.is(Potions.WATER)) {
this.applyWater(worldserver); - this.applyWater(worldserver);
- } else if (potioncontents.hasEffects()) { - } 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 + } else if (true || potioncontents.hasEffects()) { // CraftBukkit - Call event even if no effects to apply
if (this.isLingering()) { if (this.isLingering()) {
- this.makeAreaOfEffectCloud(potioncontents); - this.makeAreaOfEffectCloud(potioncontents);
+ this.makeAreaOfEffectCloud(potioncontents, hitResult); // CraftBukkit - Pass MovingObjectPosition + showParticles = this.makeAreaOfEffectCloud(potioncontents, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper
} else { } 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);
+ 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; int i = potioncontents.potion().isPresent() && ((Potion) ((Holder) potioncontents.potion().get()).value()).hasInstantEffects() ? 2007 : 2002;
worldserver.levelEvent(i, this.blockPosition(), potioncontents.getColor()); worldserver.levelEvent(i, this.blockPosition(), potioncontents.getColor());
- this.discard(); - this.discard();
+ } // Paper - Fix potions splash events
+ this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause + this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause
} }
} }
private void applyWater(ServerLevel world) { - private void applyWater(ServerLevel world) {
+ private static final Predicate<net.minecraft.world.entity.LivingEntity> 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); AABB axisalignedbb = this.getBoundingBox().inflate(4.0D, 2.0D, 4.0D);
- List<LivingEntity> list = this.level().getEntitiesOfClass(LivingEntity.class, axisalignedbb, ThrownPotion.WATER_SENSITIVE_OR_ON_FIRE); - List<LivingEntity> list = this.level().getEntitiesOfClass(LivingEntity.class, axisalignedbb, ThrownPotion.WATER_SENSITIVE_OR_ON_FIRE);
+ List<net.minecraft.world.entity.LivingEntity> list = this.level().getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb, ThrownPotion.WATER_SENSITIVE_OR_ON_FIRE); + // Paper start - Fix potions splash events
+ List<net.minecraft.world.entity.LivingEntity> list = this.level().getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb, ThrownPotion.APPLY_WATER_GET_ENTITIES_PREDICATE);
+ Map<LivingEntity, Double> affected = new HashMap<>();
+ java.util.Set<LivingEntity> rehydrate = new java.util.HashSet<>();
+ java.util.Set<LivingEntity> extinguish = new java.util.HashSet<>();
Iterator iterator = list.iterator(); Iterator iterator = list.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
- LivingEntity entityliving = (LivingEntity) iterator.next(); - LivingEntity entityliving = (LivingEntity) iterator.next();
+ net.minecraft.world.entity.LivingEntity entityliving = (net.minecraft.world.entity.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); double d0 = this.distanceToSqr((Entity) entityliving);
if (d0 < 16.0D) { 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<Axolotl> 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<MobEffectInstance> effects, @Nullable Entity entity) { - private void applySplash(ServerLevel world, Iterable<MobEffectInstance> effects, @Nullable Entity entity) {
+ private void applySplash(ServerLevel worldserver, Iterable<MobEffectInstance> iterable, @Nullable Entity entity, HitResult position) { // CraftBukkit - Pass MovingObjectPosition + private boolean applySplash(ServerLevel worldserver, Iterable<MobEffectInstance> 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); AABB axisalignedbb = this.getBoundingBox().inflate(4.0D, 2.0D, 4.0D);
- List<LivingEntity> list = world.getEntitiesOfClass(LivingEntity.class, axisalignedbb); - List<LivingEntity> list = world.getEntitiesOfClass(LivingEntity.class, axisalignedbb);
+ List<net.minecraft.world.entity.LivingEntity> list = worldserver.getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb); + List<net.minecraft.world.entity.LivingEntity> list = worldserver.getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb);
@ -111,7 +162,14 @@
if (entityliving.isAffectedByPotions()) { if (entityliving.isAffectedByPotions()) {
double d0 = this.distanceToSqr((Entity) entityliving); 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; 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 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()); AreaEffectCloud entityareaeffectcloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ());
Entity entity = this.getOwner(); Entity entity = this.getOwner();
@ -192,25 +251,27 @@
entityareaeffectcloud.setOwner(entityliving); entityareaeffectcloud.setOwner(entityliving);
} }
@@ -208,8 +245,15 @@ @@ -208,8 +268,17 @@
entityareaeffectcloud.setRadiusOnUse(-0.5F); entityareaeffectcloud.setRadiusOnUse(-0.5F);
entityareaeffectcloud.setWaitTime(10); entityareaeffectcloud.setWaitTime(10);
entityareaeffectcloud.setRadiusPerTick(-entityareaeffectcloud.getRadius() / (float) entityareaeffectcloud.getDuration()); entityareaeffectcloud.setRadiusPerTick(-entityareaeffectcloud.getRadius() / (float) entityareaeffectcloud.getDuration());
- entityareaeffectcloud.setPotionContents(potion); - entityareaeffectcloud.setPotionContents(potion);
- this.level().addFreshEntity(entityareaeffectcloud); - this.level().addFreshEntity(entityareaeffectcloud);
+ entityareaeffectcloud.setPotionContents(potioncontents); + entityareaeffectcloud.setPotionContents(potioncontents);
+ boolean noEffects = potioncontents.hasEffects(); // Paper - Fix potions splash events
+ // CraftBukkit start + // CraftBukkit start
+ org.bukkit.event.entity.LingeringPotionSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callLingeringPotionSplashEvent(this, position, entityareaeffectcloud); + 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); + this.level().addFreshEntity(entityareaeffectcloud);
+ } else { + } else {
+ entityareaeffectcloud.discard(null); // CraftBukkit - add Bukkit remove cause + entityareaeffectcloud.discard(null); // CraftBukkit - add Bukkit remove cause
+ } + }
+ // CraftBukkit end + // CraftBukkit end
+ return !event.isCancelled(); // Paper - Fix potions splash events
} }
public boolean isLingering() { public boolean isLingering() {
@@ -220,19 +264,31 @@ @@ -220,19 +289,31 @@
BlockState iblockdata = this.level().getBlockState(pos); BlockState iblockdata = this.level().getBlockState(pos);
if (iblockdata.is(BlockTags.FIRE)) { if (iblockdata.is(BlockTags.FIRE)) {

View file

@ -884,6 +884,32 @@ public class CraftEventFactory {
return event; 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<LivingEntity, Double> affectedEntities, java.util.Set<LivingEntity> rehydrate, java.util.Set<LivingEntity> 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 * BlockFadeEvent
*/ */