--- a/net/minecraft/world/entity/projectile/EntityPotion.java
+++ b/net/minecraft/world/entity/projectile/EntityPotion.java
@@ -35,6 +35,18 @@
 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;
+import org.bukkit.event.entity.EntityRemoveEvent;
+// CraftBukkit end
+
 public class EntityPotion extends EntityProjectileThrowable {
 
     public static final double SPLASH_RANGE = 4.0D;
@@ -101,18 +113,18 @@
 
             if (potioncontents.is(Potions.WATER)) {
                 this.applyWater(worldserver);
-            } else if (potioncontents.hasEffects()) {
+            } else if (true || potioncontents.hasEffects()) { // CraftBukkit - Call event even if no effects to apply
                 if (this.isLingering()) {
-                    this.makeAreaOfEffectCloud(potioncontents);
+                    this.makeAreaOfEffectCloud(potioncontents, movingobjectposition); // CraftBukkit - Pass MovingObjectPosition
                 } else {
-                    this.applySplash(worldserver, potioncontents.getAllEffects(), movingobjectposition.getType() == MovingObjectPosition.EnumMovingObjectType.ENTITY ? ((MovingObjectPositionEntity) movingobjectposition).getEntity() : null);
+                    this.applySplash(worldserver, potioncontents.getAllEffects(), movingobjectposition.getType() == MovingObjectPosition.EnumMovingObjectType.ENTITY ? ((MovingObjectPositionEntity) movingobjectposition).getEntity() : null, movingobjectposition); // CraftBukkit - Pass MovingObjectPosition
                 }
             }
 
             int i = potioncontents.potion().isPresent() && ((PotionRegistry) ((Holder) potioncontents.potion().get()).value()).hasInstantEffects() ? 2007 : 2002;
 
             worldserver.levelEvent(i, this.blockPosition(), potioncontents.getColor());
-            this.discard();
+            this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause
         }
     }
 
@@ -147,9 +159,10 @@
 
     }
 
-    private void applySplash(WorldServer worldserver, Iterable<MobEffect> iterable, @Nullable Entity entity) {
+    private void applySplash(WorldServer worldserver, Iterable<MobEffect> iterable, @Nullable Entity entity, MovingObjectPosition position) { // CraftBukkit - Pass MovingObjectPosition
         AxisAlignedBB axisalignedbb = this.getBoundingBox().inflate(4.0D, 2.0D, 4.0D);
         List<EntityLiving> list = worldserver.getEntitiesOfClass(EntityLiving.class, axisalignedbb);
+        Map<LivingEntity, Double> affected = new HashMap<LivingEntity, Double>(); // CraftBukkit
 
         if (!list.isEmpty()) {
             Entity entity1 = this.getEffectSource();
@@ -170,24 +183,50 @@
                             d1 = 1.0D - Math.sqrt(d0) / 4.0D;
                         }
 
-                        Iterator iterator1 = iterable.iterator();
+                        // CraftBukkit start
+                        affected.put((LivingEntity) entityliving.getBukkitEntity(), d1);
+                    }
+                }
+            }
+        }
 
-                        while (iterator1.hasNext()) {
-                            MobEffect mobeffect = (MobEffect) iterator1.next();
-                            Holder<MobEffectList> holder = 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) holder.value()).isInstantenous()) {
-                                ((MobEffectList) holder.value()).applyInstantenousEffect(worldserver, this, this.getOwner(), entityliving, mobeffect.getAmplifier(), d1);
-                            } else {
-                                int i = mobeffect.mapDuration((j) -> {
-                                    return (int) (d1 * (double) j + 0.5D);
-                                });
-                                MobEffect mobeffect1 = new MobEffect(holder, 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 = iterable.iterator();
+
+                while (iterator1.hasNext()) {
+                    MobEffect mobeffect = (MobEffect) iterator1.next();
+                    Holder<MobEffectList> holder = 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()) {
+                        MobEffectList mobeffectlist = (MobEffectList) holder.value();
+                        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) holder.value()).isInstantenous()) {
+                        ((MobEffectList) holder.value()).applyInstantenousEffect(worldserver, this, this.getOwner(), entityliving, mobeffect.getAmplifier(), d1);
+                    } else {
+                        int i = mobeffect.mapDuration((j) -> {
+                            return (int) (d1 * (double) j + 0.5D);
+                        });
+                        MobEffect mobeffect1 = new MobEffect(holder, i, mobeffect.getAmplifier(), mobeffect.isAmbient(), mobeffect.isVisible());
+
+                        if (!mobeffect1.endsWithin(20)) {
+                            entityliving.addEffect(mobeffect1, entity1, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.POTION_SPLASH); // CraftBukkit
                         }
                     }
                 }
@@ -196,7 +235,7 @@
 
     }
 
-    private void makeAreaOfEffectCloud(PotionContents potioncontents) {
+    private void makeAreaOfEffectCloud(PotionContents potioncontents, MovingObjectPosition position) { // CraftBukkit - Pass MovingObjectPosition
         EntityAreaEffectCloud entityareaeffectcloud = new EntityAreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ());
         Entity entity = this.getOwner();
 
@@ -209,7 +248,14 @@
         entityareaeffectcloud.setWaitTime(10);
         entityareaeffectcloud.setRadiusPerTick(-entityareaeffectcloud.getRadius() / (float) entityareaeffectcloud.getDuration());
         entityareaeffectcloud.setPotionContents(potioncontents);
-        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(null); // CraftBukkit - add Bukkit remove cause
+        }
+        // CraftBukkit end
     }
 
     public boolean isLingering() {
@@ -220,13 +266,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
         }
 
     }
