--- a/net/minecraft/world/entity/AreaEffectCloud.java
+++ b/net/minecraft/world/entity/AreaEffectCloud.java
@@ -5,11 +5,14 @@
 import com.mojang.brigadier.StringReader;
 import com.mojang.brigadier.exceptions.CommandSyntaxException;
 import com.mojang.logging.LogUtils;
+import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 import javax.annotation.Nullable;
 import net.minecraft.commands.arguments.ParticleArgument;
+import net.minecraft.core.HolderLookup;
 import net.minecraft.core.particles.ParticleOptions;
 import net.minecraft.core.particles.ParticleTypes;
 import net.minecraft.core.registries.BuiltInRegistries;
@@ -18,6 +21,7 @@
 import net.minecraft.network.syncher.EntityDataAccessor;
 import net.minecraft.network.syncher.EntityDataSerializers;
 import net.minecraft.network.syncher.SynchedEntityData;
+import net.minecraft.resources.ResourceLocation;
 import net.minecraft.server.level.ServerLevel;
 import net.minecraft.util.Mth;
 import net.minecraft.world.effect.MobEffectInstance;
@@ -27,8 +31,12 @@
 import net.minecraft.world.level.Level;
 import net.minecraft.world.level.material.PushReaction;
 import org.slf4j.Logger;
+import org.bukkit.craftbukkit.v1_19_R2.entity.CraftLivingEntity;
+import org.bukkit.entity.LivingEntity;
+// CraftBukkit end
 
 public class AreaEffectCloud extends Entity {
+
     private static final Logger LOGGER = LogUtils.getLogger();
     private static final int TIME_BETWEEN_APPLICATIONS = 5;
     private static final EntityDataAccessor<Float> DATA_RADIUS = SynchedEntityData.defineId(AreaEffectCloud.class, EntityDataSerializers.FLOAT);
@@ -40,23 +48,29 @@
     private static final float DEFAULT_RADIUS = 3.0F;
     public static final float DEFAULT_WIDTH = 6.0F;
     public static final float HEIGHT = 0.5F;
-    private Potion potion = Potions.EMPTY;
-    public List<MobEffectInstance> effects = Lists.newArrayList();
-    private final Map<Entity, Integer> victims = Maps.newHashMap();
-    private int duration = 600;
-    public int waitTime = 20;
-    public int reapplicationDelay = 20;
+    private Potion potion;
+    public List<MobEffectInstance> effects;
+    private final Map<Entity, Integer> victims;
+    private int duration;
+    public int waitTime;
+    public int reapplicationDelay;
     private boolean fixedColor;
     public int durationOnUse;
     public float radiusOnUse;
     public float radiusPerTick;
     @Nullable
-    private LivingEntity owner;
+    private net.minecraft.world.entity.LivingEntity owner;
     @Nullable
     private UUID ownerUUID;
 
     public AreaEffectCloud(EntityType<? extends AreaEffectCloud> type, Level world) {
         super(type, world);
+        this.potion = Potions.EMPTY;
+        this.effects = Lists.newArrayList();
+        this.victims = Maps.newHashMap();
+        this.duration = 600;
+        this.waitTime = 20;
+        this.reapplicationDelay = 20;
         this.noPhysics = true;
     }
 
@@ -67,30 +81,31 @@
 
     @Override
     protected void defineSynchedData() {
-        this.getEntityData().define(DATA_COLOR, 0);
-        this.getEntityData().define(DATA_RADIUS, 3.0F);
-        this.getEntityData().define(DATA_WAITING, false);
-        this.getEntityData().define(DATA_PARTICLE, ParticleTypes.ENTITY_EFFECT);
+        this.getEntityData().define(AreaEffectCloud.DATA_COLOR, 0);
+        this.getEntityData().define(AreaEffectCloud.DATA_RADIUS, 3.0F);
+        this.getEntityData().define(AreaEffectCloud.DATA_WAITING, false);
+        this.getEntityData().define(AreaEffectCloud.DATA_PARTICLE, ParticleTypes.ENTITY_EFFECT);
     }
 
     public void setRadius(float radius) {
         if (!this.level.isClientSide) {
-            this.getEntityData().set(DATA_RADIUS, Mth.clamp(radius, 0.0F, 32.0F));
+            this.getEntityData().set(AreaEffectCloud.DATA_RADIUS, Mth.clamp(radius, 0.0F, 32.0F));
         }
 
     }
 
     @Override
     public void refreshDimensions() {
-        double d = this.getX();
-        double e = this.getY();
-        double f = this.getZ();
+        double d0 = this.getX();
+        double d1 = this.getY();
+        double d2 = this.getZ();
+
         super.refreshDimensions();
-        this.setPos(d, e, f);
+        this.setPos(d0, d1, d2);
     }
 
     public float getRadius() {
-        return this.getEntityData().get(DATA_RADIUS);
+        return (Float) this.getEntityData().get(AreaEffectCloud.DATA_RADIUS);
     }
 
     public void setPotion(Potion potion) {
@@ -103,9 +118,9 @@
 
     private void updateColor() {
         if (this.potion == Potions.EMPTY && this.effects.isEmpty()) {
-            this.getEntityData().set(DATA_COLOR, 0);
+            this.getEntityData().set(AreaEffectCloud.DATA_COLOR, 0);
         } else {
-            this.getEntityData().set(DATA_COLOR, PotionUtils.getColor(PotionUtils.getAllEffects(this.potion, this.effects)));
+            this.getEntityData().set(AreaEffectCloud.DATA_COLOR, PotionUtils.getColor((Collection) PotionUtils.getAllEffects(this.potion, this.effects)));
         }
 
     }
@@ -118,29 +133,45 @@
 
     }
 
+    // CraftBukkit start accessor methods
+    public void refreshEffects() {
+        if (!this.fixedColor) {
+            this.getEntityData().set(AreaEffectCloud.DATA_COLOR, PotionUtils.getColor((Collection) PotionUtils.getAllEffects(this.potion, this.effects)));
+        }
+    }
+
+    public String getPotionType() {
+        return ((ResourceLocation) BuiltInRegistries.POTION.getKey(this.potion)).toString();
+    }
+
+    public void setPotionType(String string) {
+        this.setPotion(BuiltInRegistries.POTION.get(new ResourceLocation(string)));
+    }
+    // CraftBukkit end
+
     public int getColor() {
-        return this.getEntityData().get(DATA_COLOR);
+        return (Integer) this.getEntityData().get(AreaEffectCloud.DATA_COLOR);
     }
 
     public void setFixedColor(int rgb) {
         this.fixedColor = true;
-        this.getEntityData().set(DATA_COLOR, rgb);
+        this.getEntityData().set(AreaEffectCloud.DATA_COLOR, rgb);
     }
 
     public ParticleOptions getParticle() {
-        return this.getEntityData().get(DATA_PARTICLE);
+        return (ParticleOptions) this.getEntityData().get(AreaEffectCloud.DATA_PARTICLE);
     }
 
     public void setParticle(ParticleOptions particle) {
-        this.getEntityData().set(DATA_PARTICLE, particle);
+        this.getEntityData().set(AreaEffectCloud.DATA_PARTICLE, particle);
     }
 
     protected void setWaiting(boolean waiting) {
-        this.getEntityData().set(DATA_WAITING, waiting);
+        this.getEntityData().set(AreaEffectCloud.DATA_WAITING, waiting);
     }
 
     public boolean isWaiting() {
-        return this.getEntityData().get(DATA_WAITING);
+        return (Boolean) this.getEntityData().get(AreaEffectCloud.DATA_WAITING);
     }
 
     public int getDuration() {
@@ -151,52 +182,68 @@
         this.duration = duration;
     }
 
+    // Spigot start - copied from below
+    @Override
+    public void inactiveTick() {
+        super.inactiveTick();
+
+        if (this.tickCount >= this.waitTime + this.duration) {
+            this.discard();
+            return;
+        }
+    }
+    // Spigot end
+
     @Override
     public void tick() {
         super.tick();
-        boolean bl = this.isWaiting();
+        boolean flag = this.isWaiting();
         float f = this.getRadius();
+
         if (this.level.isClientSide) {
-            if (bl && this.random.nextBoolean()) {
+            if (flag && this.random.nextBoolean()) {
                 return;
             }
 
-            ParticleOptions particleOptions = this.getParticle();
+            ParticleOptions particleparam = this.getParticle();
             int i;
-            float g;
-            if (bl) {
+            float f1;
+
+            if (flag) {
                 i = 2;
-                g = 0.2F;
+                f1 = 0.2F;
             } else {
-                i = Mth.ceil((float)Math.PI * f * f);
-                g = f;
+                i = Mth.ceil(3.1415927F * f * f);
+                f1 = f;
             }
 
-            for(int k = 0; k < i; ++k) {
-                float l = this.random.nextFloat() * ((float)Math.PI * 2F);
-                float m = Mth.sqrt(this.random.nextFloat()) * g;
-                double d = this.getX() + (double)(Mth.cos(l) * m);
-                double e = this.getY();
-                double n = this.getZ() + (double)(Mth.sin(l) * m);
-                double p;
-                double q;
-                double r;
-                if (particleOptions.getType() == ParticleTypes.ENTITY_EFFECT) {
-                    int o = bl && this.random.nextBoolean() ? 16777215 : this.getColor();
-                    p = (double)((float)(o >> 16 & 255) / 255.0F);
-                    q = (double)((float)(o >> 8 & 255) / 255.0F);
-                    r = (double)((float)(o & 255) / 255.0F);
-                } else if (bl) {
-                    p = 0.0D;
-                    q = 0.0D;
-                    r = 0.0D;
+            for (int j = 0; j < i; ++j) {
+                float f2 = this.random.nextFloat() * 6.2831855F;
+                float f3 = Mth.sqrt(this.random.nextFloat()) * f1;
+                double d0 = this.getX() + (double) (Mth.cos(f2) * f3);
+                double d1 = this.getY();
+                double d2 = this.getZ() + (double) (Mth.sin(f2) * f3);
+                double d3;
+                double d4;
+                double d5;
+
+                if (particleparam.getType() == ParticleTypes.ENTITY_EFFECT) {
+                    int k = flag && this.random.nextBoolean() ? 16777215 : this.getColor();
+
+                    d3 = (double) ((float) (k >> 16 & 255) / 255.0F);
+                    d4 = (double) ((float) (k >> 8 & 255) / 255.0F);
+                    d5 = (double) ((float) (k & 255) / 255.0F);
+                } else if (flag) {
+                    d3 = 0.0D;
+                    d4 = 0.0D;
+                    d5 = 0.0D;
                 } else {
-                    p = (0.5D - this.random.nextDouble()) * 0.15D;
-                    q = (double)0.01F;
-                    r = (0.5D - this.random.nextDouble()) * 0.15D;
+                    d3 = (0.5D - this.random.nextDouble()) * 0.15D;
+                    d4 = 0.009999999776482582D;
+                    d5 = (0.5D - this.random.nextDouble()) * 0.15D;
                 }
 
-                this.level.addAlwaysVisibleParticle(particleOptions, d, e, n, p, q, r);
+                this.level.addAlwaysVisibleParticle(particleparam, d0, d1, d2, d3, d4, d5);
             }
         } else {
             if (this.tickCount >= this.waitTime + this.duration) {
@@ -204,12 +251,13 @@
                 return;
             }
 
-            boolean bl2 = this.tickCount < this.waitTime;
-            if (bl != bl2) {
-                this.setWaiting(bl2);
+            boolean flag1 = this.tickCount < this.waitTime;
+
+            if (flag != flag1) {
+                this.setWaiting(flag1);
             }
 
-            if (bl2) {
+            if (flag1) {
                 return;
             }
 
@@ -225,33 +273,57 @@
 
             if (this.tickCount % 5 == 0) {
                 this.victims.entrySet().removeIf((entry) -> {
-                    return this.tickCount >= entry.getValue();
+                    return this.tickCount >= (Integer) entry.getValue();
                 });
                 List<MobEffectInstance> list = Lists.newArrayList();
+                Iterator iterator = this.potion.getEffects().iterator();
 
-                for(MobEffectInstance mobEffectInstance : this.potion.getEffects()) {
-                    list.add(new MobEffectInstance(mobEffectInstance.getEffect(), mobEffectInstance.getDuration() / 4, mobEffectInstance.getAmplifier(), mobEffectInstance.isAmbient(), mobEffectInstance.isVisible()));
+                while (iterator.hasNext()) {
+                    MobEffectInstance mobeffect = (MobEffectInstance) iterator.next();
+
+                    list.add(new MobEffectInstance(mobeffect.getEffect(), mobeffect.getDuration() / 4, mobeffect.getAmplifier(), mobeffect.isAmbient(), mobeffect.isVisible()));
                 }
 
                 list.addAll(this.effects);
                 if (list.isEmpty()) {
                     this.victims.clear();
                 } else {
-                    List<LivingEntity> list2 = this.level.getEntitiesOfClass(LivingEntity.class, this.getBoundingBox());
-                    if (!list2.isEmpty()) {
-                        for(LivingEntity livingEntity : list2) {
-                            if (!this.victims.containsKey(livingEntity) && livingEntity.isAffectedByPotions()) {
-                                double y = livingEntity.getX() - this.getX();
-                                double z = livingEntity.getZ() - this.getZ();
-                                double aa = y * y + z * z;
-                                if (aa <= (double)(f * f)) {
-                                    this.victims.put(livingEntity, this.tickCount + this.reapplicationDelay);
+                    List<net.minecraft.world.entity.LivingEntity> list1 = this.level.getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, this.getBoundingBox());
 
-                                    for(MobEffectInstance mobEffectInstance2 : list) {
-                                        if (mobEffectInstance2.getEffect().isInstantenous()) {
-                                            mobEffectInstance2.getEffect().applyInstantenousEffect(this, this.getOwner(), livingEntity, mobEffectInstance2.getAmplifier(), 0.5D);
+                    if (!list1.isEmpty()) {
+                        Iterator iterator1 = list1.iterator();
+
+                        List<LivingEntity> entities = new java.util.ArrayList<LivingEntity>(); // CraftBukkit
+                        while (iterator1.hasNext()) {
+                            net.minecraft.world.entity.LivingEntity entityliving = (net.minecraft.world.entity.LivingEntity) iterator1.next();
+
+                            if (!this.victims.containsKey(entityliving) && entityliving.isAffectedByPotions()) {
+                                double d6 = entityliving.getX() - this.getX();
+                                double d7 = entityliving.getZ() - this.getZ();
+                                double d8 = d6 * d6 + d7 * d7;
+
+                                if (d8 <= (double) (f * f)) {
+                                    // CraftBukkit start
+                                    entities.add((LivingEntity) entityliving.getBukkitEntity());
+                                }
+                            }
+                        }
+                        org.bukkit.event.entity.AreaEffectCloudApplyEvent event = org.bukkit.craftbukkit.v1_19_R2.event.CraftEventFactory.callAreaEffectCloudApplyEvent(this, entities);
+                        if (!event.isCancelled()) {
+                            for (LivingEntity entity : event.getAffectedEntities()) {
+                                if (entity instanceof CraftLivingEntity) {
+                                    net.minecraft.world.entity.LivingEntity entityliving = ((CraftLivingEntity) entity).getHandle();
+                                    // CraftBukkit end
+                                    this.victims.put(entityliving, this.tickCount + this.reapplicationDelay);
+                                    Iterator iterator2 = list.iterator();
+
+                                    while (iterator2.hasNext()) {
+                                        MobEffectInstance mobeffect1 = (MobEffectInstance) iterator2.next();
+
+                                        if (mobeffect1.getEffect().isInstantenous()) {
+                                            mobeffect1.getEffect().applyInstantenousEffect(this, this.getOwner(), entityliving, mobeffect1.getAmplifier(), 0.5D);
                                         } else {
-                                            livingEntity.addEffect(new MobEffectInstance(mobEffectInstance2), this);
+                                            entityliving.addEffect(new MobEffectInstance(mobeffect1), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.AREA_EFFECT_CLOUD); // CraftBukkit
                                         }
                                     }
 
@@ -314,17 +386,18 @@
         this.waitTime = waitTime;
     }
 
-    public void setOwner(@Nullable LivingEntity owner) {
+    public void setOwner(@Nullable net.minecraft.world.entity.LivingEntity owner) {
         this.owner = owner;
         this.ownerUUID = owner == null ? null : owner.getUUID();
     }
 
     @Nullable
-    public LivingEntity getOwner() {
+    public net.minecraft.world.entity.LivingEntity getOwner() {
         if (this.owner == null && this.ownerUUID != null && this.level instanceof ServerLevel) {
-            Entity entity = ((ServerLevel)this.level).getEntity(this.ownerUUID);
-            if (entity instanceof LivingEntity) {
-                this.owner = (LivingEntity)entity;
+            Entity entity = ((ServerLevel) this.level).getEntity(this.ownerUUID);
+
+            if (entity instanceof net.minecraft.world.entity.LivingEntity) {
+                this.owner = (net.minecraft.world.entity.LivingEntity) entity;
             }
         }
 
@@ -347,9 +420,9 @@
 
         if (nbt.contains("Particle", 8)) {
             try {
-                this.setParticle(ParticleArgument.readParticle(new StringReader(nbt.getString("Particle")), BuiltInRegistries.PARTICLE_TYPE.asLookup()));
-            } catch (CommandSyntaxException var5) {
-                LOGGER.warn("Couldn't load custom particle {}", nbt.getString("Particle"), var5);
+                this.setParticle(ParticleArgument.readParticle(new StringReader(nbt.getString("Particle")), (HolderLookup) BuiltInRegistries.PARTICLE_TYPE.asLookup()));
+            } catch (CommandSyntaxException commandsyntaxexception) {
+                AreaEffectCloud.LOGGER.warn("Couldn't load custom particle {}", nbt.getString("Particle"), commandsyntaxexception);
             }
         }
 
@@ -362,13 +435,15 @@
         }
 
         if (nbt.contains("Effects", 9)) {
-            ListTag listTag = nbt.getList("Effects", 10);
+            ListTag nbttaglist = nbt.getList("Effects", 10);
+
             this.effects.clear();
 
-            for(int i = 0; i < listTag.size(); ++i) {
-                MobEffectInstance mobEffectInstance = MobEffectInstance.load(listTag.getCompound(i));
-                if (mobEffectInstance != null) {
-                    this.addEffect(mobEffectInstance);
+            for (int i = 0; i < nbttaglist.size(); ++i) {
+                MobEffectInstance mobeffect = MobEffectInstance.load(nbttaglist.getCompound(i));
+
+                if (mobeffect != null) {
+                    this.addEffect(mobeffect);
                 }
             }
         }
@@ -399,20 +474,23 @@
         }
 
         if (!this.effects.isEmpty()) {
-            ListTag listTag = new ListTag();
+            ListTag nbttaglist = new ListTag();
+            Iterator iterator = this.effects.iterator();
 
-            for(MobEffectInstance mobEffectInstance : this.effects) {
-                listTag.add(mobEffectInstance.save(new CompoundTag()));
+            while (iterator.hasNext()) {
+                MobEffectInstance mobeffect = (MobEffectInstance) iterator.next();
+
+                nbttaglist.add(mobeffect.save(new CompoundTag()));
             }
 
-            nbt.put("Effects", listTag);
+            nbt.put("Effects", nbttaglist);
         }
 
     }
 
     @Override
     public void onSyncedDataUpdated(EntityDataAccessor<?> data) {
-        if (DATA_RADIUS.equals(data)) {
+        if (AreaEffectCloud.DATA_RADIUS.equals(data)) {
             this.refreshDimensions();
         }
 
