--- a/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java
+++ b/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java
@@ -122,9 +122,35 @@
     protected abstract class EntryBase implements LootPoolEntry {
         @Override
         public int getWeight(float luck) {
-            return Math.max(Mth.floor((float)LootPoolSingletonContainer.this.weight + (float)LootPoolSingletonContainer.this.quality * luck), 0);
+            // Paper start - Offer an alternative loot formula to refactor how luck bonus applies
+            // SEE: https://luckformula.emc.gs for details and data
+            if (LootPoolSingletonContainer.this.lastLuck != null && LootPoolSingletonContainer.this.lastLuck == luck) {
+                return lastWeight;
+            }
+            // This is vanilla
+            float qualityModifer = (float) LootPoolSingletonContainer.this.quality * luck;
+            double baseWeight = (LootPoolSingletonContainer.this.weight + qualityModifer);
+            if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.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, luck * 10) / 100;
+                // =B2 - (C2 *($B$7/100))
+                baseWeight = Math.ceil(baseWeight - (impacted * luckModifier));
+            }
+            LootPoolSingletonContainer.this.lastLuck = luck;
+            LootPoolSingletonContainer.this.lastWeight = (int) Math.max(Math.floor(baseWeight), 0);
+            return lastWeight;
         }
     }
+    private Float lastLuck = null;
+    private int lastWeight = 0;
+    // Paper end
 
     @FunctionalInterface
     protected interface EntryConstructor {
