--- a/net/minecraft/world/entity/projectile/EntityPotion.java
+++ b/net/minecraft/world/entity/projectile/EntityPotion.java
@@ -31,6 +31,17 @@
 import net.minecraft.world.phys.MovingObjectPositionBlock;
 import net.minecraft.world.phys.MovingObjectPositionEntity;
 
+// CraftBukkit start
+import java.util.HashMap;
+import java.util.Map;
+import net.minecraft.server.level.EntityPlayer;
+import net.minecraft.world.effect.MobEffects;
+import net.minecraft.world.level.block.Blocks;
+import org.bukkit.craftbukkit.entity.CraftLivingEntity;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.entity.LivingEntity;
+// CraftBukkit end
+
 public class EntityPotion extends EntityProjectileThrowable implements ItemSupplier {
 
     public static final double SPLASH_RANGE = 4.0D;
@@ -99,11 +110,11 @@
 
             if (flag) {
                 this.applyWater();
-            } else if (!list.isEmpty()) {
+            } else if (true || !list.isEmpty()) { // CraftBukkit - Call event even if no effects to apply
                 if (this.isLingering()) {
-                    this.makeAreaOfEffectCloud(itemstack, potionregistry);
+                    this.makeAreaOfEffectCloud(itemstack, potionregistry, movingobjectposition); // CraftBukkit - Pass MovingObjectPosition
                 } else {
-                    this.applySplash(list, movingobjectposition.getType() == MovingObjectPosition.EnumMovingObjectType.ENTITY ? ((MovingObjectPositionEntity) movingobjectposition).getEntity() : null);
+                    this.applySplash(list, movingobjectposition.getType() == MovingObjectPosition.EnumMovingObjectType.ENTITY ? ((MovingObjectPositionEntity) movingobjectposition).getEntity() : null, movingobjectposition); // CraftBukkit - Pass MovingObjectPosition
                 }
             }
 
@@ -145,9 +156,10 @@
 
     }
 
-    private void applySplash(List<MobEffect> list, @Nullable Entity entity) {
+    private void applySplash(List<MobEffect> list, @Nullable Entity entity, MovingObjectPosition position) { // CraftBukkit - Pass MovingObjectPosition
         AxisAlignedBB axisalignedbb = this.getBoundingBox().inflate(4.0D, 2.0D, 4.0D);
         List<EntityLiving> list1 = this.level().getEntitiesOfClass(EntityLiving.class, axisalignedbb);
+        Map<LivingEntity, Double> affected = new HashMap<LivingEntity, Double>(); // CraftBukkit
 
         if (!list1.isEmpty()) {
             Entity entity1 = this.getEffectSource();
@@ -168,24 +180,49 @@
                             d1 = 1.0D - Math.sqrt(d0) / 4.0D;
                         }
 
-                        Iterator iterator1 = list.iterator();
+                        // CraftBukkit start
+                        affected.put((LivingEntity) entityliving.getBukkitEntity(), d1);
+                    }
+                }
+            }
+        }
 
-                        while (iterator1.hasNext()) {
-                            MobEffect mobeffect = (MobEffect) iterator1.next();
-                            MobEffectList mobeffectlist = mobeffect.getEffect();
+        org.bukkit.event.entity.PotionSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPotionSplashEvent(this, position, affected);
+        if (!event.isCancelled() && list != null && !list.isEmpty()) { // do not process effects if there are no effects to process
+            Entity entity1 = this.getEffectSource();
+            for (LivingEntity victim : event.getAffectedEntities()) {
+                if (!(victim instanceof CraftLivingEntity)) {
+                    continue;
+                }
 
-                            if (mobeffectlist.isInstantenous()) {
-                                mobeffectlist.applyInstantenousEffect(this, this.getOwner(), entityliving, mobeffect.getAmplifier(), d1);
-                            } else {
-                                int i = mobeffect.mapDuration((j) -> {
-                                    return (int) (d1 * (double) j + 0.5D);
-                                });
-                                MobEffect mobeffect1 = new MobEffect(mobeffectlist, i, mobeffect.getAmplifier(), mobeffect.isAmbient(), mobeffect.isVisible());
+                EntityLiving entityliving = ((CraftLivingEntity) victim).getHandle();
+                double d1 = event.getIntensity(victim);
+                // CraftBukkit end
 
-                                if (!mobeffect1.endsWithin(20)) {
-                                    entityliving.addEffect(mobeffect1, entity1);
-                                }
-                            }
+                Iterator iterator1 = list.iterator();
+
+                while (iterator1.hasNext()) {
+                    MobEffect mobeffect = (MobEffect) iterator1.next();
+                    MobEffectList mobeffectlist = mobeffect.getEffect();
+                    // CraftBukkit start - Abide by PVP settings - for players only!
+                    if (!this.level().pvpMode && this.getOwner() instanceof EntityPlayer && entityliving instanceof EntityPlayer && entityliving != this.getOwner()) {
+                        if (mobeffectlist == MobEffects.MOVEMENT_SLOWDOWN || mobeffectlist == MobEffects.DIG_SLOWDOWN || mobeffectlist == MobEffects.HARM || mobeffectlist == MobEffects.BLINDNESS
+                                || mobeffectlist == MobEffects.HUNGER || mobeffectlist == MobEffects.WEAKNESS || mobeffectlist == MobEffects.POISON) {
+                            continue;
+                        }
+                    }
+                    // CraftBukkit end
+
+                    if (mobeffectlist.isInstantenous()) {
+                        mobeffectlist.applyInstantenousEffect(this, this.getOwner(), entityliving, mobeffect.getAmplifier(), d1);
+                    } else {
+                        int i = mobeffect.mapDuration((j) -> {
+                            return (int) (d1 * (double) j + 0.5D);
+                        });
+                        MobEffect mobeffect1 = new MobEffect(mobeffectlist, i, mobeffect.getAmplifier(), mobeffect.isAmbient(), mobeffect.isVisible());
+
+                        if (!mobeffect1.endsWithin(20)) {
+                            entityliving.addEffect(mobeffect1, entity1, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.POTION_SPLASH); // CraftBukkit
                         }
                     }
                 }
@@ -194,7 +231,7 @@
 
     }
 
-    private void makeAreaOfEffectCloud(ItemStack itemstack, PotionRegistry potionregistry) {
+    private void makeAreaOfEffectCloud(ItemStack itemstack, PotionRegistry potionregistry, MovingObjectPosition position) { // CraftBukkit - Pass MovingObjectPosition
         EntityAreaEffectCloud entityareaeffectcloud = new EntityAreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ());
         Entity entity = this.getOwner();
 
@@ -221,7 +258,14 @@
             entityareaeffectcloud.setFixedColor(nbttagcompound.getInt("CustomPotionColor"));
         }
 
-        this.level().addFreshEntity(entityareaeffectcloud);
+        // CraftBukkit start
+        org.bukkit.event.entity.LingeringPotionSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callLingeringPotionSplashEvent(this, position, entityareaeffectcloud);
+        if (!(event.isCancelled() || entityareaeffectcloud.isRemoved())) {
+            this.level().addFreshEntity(entityareaeffectcloud);
+        } else {
+            entityareaeffectcloud.discard();
+        }
+        // CraftBukkit end
     }
 
     public boolean isLingering() {
@@ -232,13 +276,25 @@
         IBlockData iblockdata = this.level().getBlockState(blockposition);
 
         if (iblockdata.is(TagsBlock.FIRE)) {
-            this.level().destroyBlock(blockposition, false, this);
+            // CraftBukkit start
+            if (CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, Blocks.AIR.defaultBlockState())) {
+                this.level().destroyBlock(blockposition, false, this);
+            }
+            // CraftBukkit end
         } else if (AbstractCandleBlock.isLit(iblockdata)) {
-            AbstractCandleBlock.extinguish((EntityHuman) null, iblockdata, this.level(), blockposition);
+            // CraftBukkit start
+            if (CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.setValue(AbstractCandleBlock.LIT, false))) {
+                AbstractCandleBlock.extinguish((EntityHuman) null, iblockdata, this.level(), blockposition);
+            }
+            // CraftBukkit end
         } else if (BlockCampfire.isLitCampfire(iblockdata)) {
-            this.level().levelEvent((EntityHuman) null, 1009, blockposition, 0);
-            BlockCampfire.dowse(this.getOwner(), this.level(), blockposition, iblockdata);
-            this.level().setBlockAndUpdate(blockposition, (IBlockData) iblockdata.setValue(BlockCampfire.LIT, false));
+            // CraftBukkit start
+            if (CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.setValue(BlockCampfire.LIT, false))) {
+                this.level().levelEvent((EntityHuman) null, 1009, blockposition, 0);
+                BlockCampfire.dowse(this.getOwner(), this.level(), blockposition, iblockdata);
+                this.level().setBlockAndUpdate(blockposition, (IBlockData) iblockdata.setValue(BlockCampfire.LIT, false));
+            }
+            // CraftBukkit end
         }
 
     }
