--- a/net/minecraft/world/level/block/entity/TileEntityBeacon.java
+++ b/net/minecraft/world/level/block/entity/TileEntityBeacon.java
@@ -40,6 +40,11 @@
 import net.minecraft.world.level.levelgen.HeightMap;
 import net.minecraft.world.phys.AxisAlignedBB;
 
+// CraftBukkit start
+import org.bukkit.craftbukkit.potion.CraftPotionUtil;
+import org.bukkit.potion.PotionEffect;
+// CraftBukkit end
+
 public class TileEntityBeacon extends TileEntity implements ITileInventory {
 
     private static final int MAX_LEVELS = 4;
@@ -62,6 +67,15 @@
     public IChatBaseComponent name;
     public ChestLock lockKey;
     private final IContainerProperties dataAccess;
+    // CraftBukkit start - add fields and methods
+    public PotionEffect getPrimaryEffect() {
+        return (this.primaryPower != null) ? CraftPotionUtil.toBukkit(new MobEffect(this.primaryPower, getLevel(this.levels), getAmplification(levels, primaryPower, secondaryPower), true, true)) : null;
+    }
+
+    public PotionEffect getSecondaryEffect() {
+        return (hasSecondaryEffect(levels, primaryPower, secondaryPower)) ? CraftPotionUtil.toBukkit(new MobEffect(this.secondaryPower, getLevel(this.levels), getAmplification(levels, primaryPower, secondaryPower), true, true)) : null;
+    }
+    // CraftBukkit end
 
     public TileEntityBeacon(BlockPosition blockposition, IBlockData iblockdata) {
         super(TileEntityTypes.BEACON, blockposition, iblockdata);
@@ -230,39 +244,78 @@
         super.aa_();
     }
 
-    private static void applyEffects(World world, BlockPosition blockposition, int i, @Nullable MobEffectList mobeffectlist, @Nullable MobEffectList mobeffectlist1) {
-        if (!world.isClientSide && mobeffectlist != null) {
-            double d0 = (double) (i * 10 + 10);
+    // CraftBukkit start - split into components
+    private static byte getAmplification(int i, @Nullable MobEffectList mobeffectlist, @Nullable MobEffectList mobeffectlist1) {
+        {
             byte b0 = 0;
 
             if (i >= 4 && mobeffectlist == mobeffectlist1) {
                 b0 = 1;
             }
 
+            return b0;
+        }
+    }
+
+    private static int getLevel(int i) {
+        {
             int j = (9 + i * 2) * 20;
+            return j;
+        }
+    }
+
+    public static List getHumansInRange(World world, BlockPosition blockposition, int i) {
+        {
+            double d0 = (double) (i * 10 + 10);
+
             AxisAlignedBB axisalignedbb = (new AxisAlignedBB(blockposition)).g(d0).b(0.0D, (double) world.getHeight(), 0.0D);
             List<EntityHuman> list = world.a(EntityHuman.class, axisalignedbb);
+
+            return list;
+        }
+    }
+
+    private static void applyEffect(List list, MobEffectList mobeffectlist, int j, int b0) {
+        {
             Iterator iterator = list.iterator();
 
             EntityHuman entityhuman;
 
             while (iterator.hasNext()) {
                 entityhuman = (EntityHuman) iterator.next();
-                entityhuman.addEffect(new MobEffect(mobeffectlist, j, b0, true, true));
+                entityhuman.addEffect(new MobEffect(mobeffectlist, j, b0, true, true), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.BEACON);
             }
+        }
+    }
 
+    private static boolean hasSecondaryEffect(int i, @Nullable MobEffectList mobeffectlist, @Nullable MobEffectList mobeffectlist1) {
+        {
             if (i >= 4 && mobeffectlist != mobeffectlist1 && mobeffectlist1 != null) {
-                iterator = list.iterator();
-
-                while (iterator.hasNext()) {
-                    entityhuman = (EntityHuman) iterator.next();
-                    entityhuman.addEffect(new MobEffect(mobeffectlist1, j, 0, true, true));
-                }
+                return true;
             }
 
+            return false;
         }
     }
 
+    private static void applyEffects(World world, BlockPosition blockposition, int i, @Nullable MobEffectList mobeffectlist, @Nullable MobEffectList mobeffectlist1) {
+        if (!world.isClientSide && mobeffectlist != null) {
+            double d0 = (double) (i * 10 + 10);
+            byte b0 = getAmplification(i, mobeffectlist, mobeffectlist1);
+
+            int j = getLevel(i);
+            List list = getHumansInRange(world, blockposition, i);
+
+            applyEffect(list, mobeffectlist, j, b0);
+
+            if (hasSecondaryEffect(i, mobeffectlist, mobeffectlist1)) {
+                applyEffect(list, mobeffectlist1, j, 0);
+            }
+        }
+
+    }
+    // CraftBukkit end
+
     public static void a(World world, BlockPosition blockposition, SoundEffect soundeffect) {
         world.playSound((EntityHuman) null, blockposition, soundeffect, SoundCategory.BLOCKS, 1.0F, 1.0F);
     }
@@ -292,8 +345,11 @@
     @Override
     public void load(NBTTagCompound nbttagcompound) {
         super.load(nbttagcompound);
-        this.primaryPower = a(nbttagcompound.getInt("Primary"));
-        this.secondaryPower = a(nbttagcompound.getInt("Secondary"));
+        // CraftBukkit start - persist manually set non-default beacon effects (SPIGOT-3598)
+        this.primaryPower = MobEffectList.fromId(nbttagcompound.getInt("Primary"));
+        this.secondaryPower = MobEffectList.fromId(nbttagcompound.getInt("Secondary"));
+        this.levels = nbttagcompound.getInt("Levels"); // SPIGOT-5053, use where available
+        // CraftBukkit end
         if (nbttagcompound.hasKeyOfType("CustomName", 8)) {
             this.name = IChatBaseComponent.ChatSerializer.a(nbttagcompound.getString("CustomName"));
         }
