diff --git a/Spigot-Server-Patches/Configurable-Alternative-LootPool-Luck-Formula.patch b/Spigot-Server-Patches/Configurable-Alternative-LootPool-Luck-Formula.patch
new file mode 100644
index 0000000000..bbee8849bb
--- /dev/null
+++ b/Spigot-Server-Patches/Configurable-Alternative-LootPool-Luck-Formula.patch
@@ -0,0 +1,106 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Aikar <aikar@aikar.co>
+Date: Fri, 15 Jun 2018 00:30:32 -0400
+Subject: [PATCH] Configurable Alternative LootPool Luck Formula
+
+Rewrites the Vanilla luck application formula so that luck can be
+applied to items that do not have any quality defined.
+
+See: https://luckformula.emc.gs for data and details
+-----------
+
+The rough summary is:
+My goal was that in a pool, when luck was applied, the pool
+rebalances so the percentages for bigger items is
+lowered and smaller items is boosted.
+
+Do this by boosting and then reducing the weight value,
+so that larger numbers are penalized more than smaller numbers.
+resulting in a larger reduction of entries for more common
+items than the reduction on small weights,
+giving smaller weights more of a chance
+
+-----------
+
+This work kind of obsoletes quality, but quality would be useful
+for 2 items with same weight that you want luck to impact
+in varying directions.
+
+Fishing still falls into that as the weights are closer, so luck
+will invalidate junk more.
+
+This change will result in some major changes to fishing formulas.
+
+-----------
+
+I would love to see this change in Vanilla, so Mojang please pull :)
+
+diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
+index b602bbf12..62bce1806 100644
+--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
++++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
+@@ -0,0 +0,0 @@ public class PaperConfig {
+                     "such as inventories, experience points, advancements and the like will not be saved when they log out.");
+         }
+     }
++
++    public static boolean useAlternativeLuckFormula = false;
++    private static void useAlternativeLuckFormula() {
++        useAlternativeLuckFormula = getBoolean("settings.use-alternative-luck-formula", false);
++        if (useAlternativeLuckFormula) {
++            Bukkit.getLogger().log(Level.INFO, "Using Aikar's Alternative Luck Formula to apply Luck attribute to all loot pool calculations. See https://luckformula.emc.gs");
++        }
++    }
+ }
+diff --git a/src/main/java/net/minecraft/server/LotoSelectorEntry.java b/src/main/java/net/minecraft/server/LotoSelectorEntry.java
+index b2860555d..b5544bcf3 100644
+--- a/src/main/java/net/minecraft/server/LotoSelectorEntry.java
++++ b/src/main/java/net/minecraft/server/LotoSelectorEntry.java
+@@ -0,0 +0,0 @@ import java.util.Random;
+ 
+ public abstract class LotoSelectorEntry {
+ 
+-    protected final int c;
+-    protected final int d;
++    protected final int c; public int getWeight() { return c; } // Paper - OBFHELPER
++    protected final int d; public int getQuality() { return d; } // Paper - OBFHELPER
+     protected final LootItemCondition[] e;
+ 
+     protected LotoSelectorEntry(int i, int j, LootItemCondition[] alootitemcondition) {
+@@ -0,0 +0,0 @@ public abstract class LotoSelectorEntry {
+     }
+ 
+     public int a(float f) {
+-        return Math.max(MathHelper.d((float) this.c + (float) this.d * f), 0);
++        // Paper start - Offer an alternative loot formula to refactor how luck bonus applies
++        // SEE: https://luckformula.emc.gs for details and data
++        if (lastLuck != null && lastLuck == f) {
++            return lastWeight;
++        }
++        // This is vanilla
++        float qualityModifer = (float) this.getQuality() * f;
++        double baseWeight = (this.getWeight() + qualityModifer);
++        if (com.destroystokyo.paper.PaperConfig.useAlternativeLuckFormula) {
++            // Random boost to avoid losing precision in the final int cast on return
++            final int weightBoost = 100;
++            baseWeight *= weightBoost;
++            // If we have vanilla 1, bump that down to 0 so nothing is is impacted
++            // vanilla 3 = 300, 200 basis = impact 2%
++            // =($B2*(($B2-100)/100/100))
++            double impacted = baseWeight * ((baseWeight - weightBoost) / weightBoost / 100);
++            // =($B$7/100)
++            float luckModifier = Math.min(100, f * 10) / 100;
++            // =B2 - (C2 *($B$7/100))
++            baseWeight = Math.ceil(baseWeight - (impacted * luckModifier));
++        }
++        lastLuck = f;
++        lastWeight = (int) Math.max(0, Math.floor(baseWeight));
++        return lastWeight;
+     }
++    private Float lastLuck = null;
++    private int lastWeight = 0;
++    // Paper end
+ 
+     public abstract void a(Collection<ItemStack> collection, Random random, LootTableInfo loottableinfo);
+ 
+--
\ No newline at end of file
diff --git a/Spigot-Server-Patches/MC-Dev-fixes.patch b/Spigot-Server-Patches/MC-Dev-fixes.patch
index fcfa99be42..0dcabebdb3 100644
--- a/Spigot-Server-Patches/MC-Dev-fixes.patch
+++ b/Spigot-Server-Patches/MC-Dev-fixes.patch
@@ -92,6 +92,24 @@ index 77b81a575..ba461ad48 100644
              }
  
              EntityTypes.g.set(i, s1);
+diff --git a/src/main/java/net/minecraft/server/LotoSelectorEntry.java b/src/main/java/net/minecraft/server/LotoSelectorEntry.java
+index a540167d6..b2860555d 100644
+--- a/src/main/java/net/minecraft/server/LotoSelectorEntry.java
++++ b/src/main/java/net/minecraft/server/LotoSelectorEntry.java
+@@ -0,0 +0,0 @@ public abstract class LotoSelectorEntry {
+             return jsonobject;
+         }
+ 
+-        public JsonElement serialize(Object object, Type type, JsonSerializationContext jsonserializationcontext) {
++        public JsonElement serialize(LotoSelectorEntry object, Type type, JsonSerializationContext jsonserializationcontext) {
+             return this.a((LotoSelectorEntry) object, type, jsonserializationcontext);
+         }
+ 
+-        public Object deserialize(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException {
++        public LotoSelectorEntry deserialize(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException {
+             return this.a(jsonelement, type, jsondeserializationcontext);
+         }
+     }
 diff --git a/src/main/java/net/minecraft/server/RegistryBlockID.java b/src/main/java/net/minecraft/server/RegistryBlockID.java
 index 58f47d0de..8860a0129 100644
 --- a/src/main/java/net/minecraft/server/RegistryBlockID.java
diff --git a/scripts/importmcdev.sh b/scripts/importmcdev.sh
index a1273883bf..3094773bbf 100755
--- a/scripts/importmcdev.sh
+++ b/scripts/importmcdev.sh
@@ -80,6 +80,7 @@ import ItemBlock
 import ItemFireworks
 import ItemMonsterEgg
 import LegacyPingHandler
+import LotoSelectorEntry
 import NavigationAbstract
 import NBTTagCompound
 import NBTTagList