From b3328de9c961142f14d916b9a9b87c0570120f28 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@GMail.com>
Date: Fri, 10 Nov 2017 23:03:12 -0500
Subject: [PATCH] Option for maximum exp value when merging orbs


diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index abc967d3f5..2a50d6babf 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -338,4 +338,10 @@ public class PaperWorldConfig {
         disableCreeperLingeringEffect = getBoolean("disable-creeper-lingering-effect", false);
         log("Creeper lingering effect: " + disableCreeperLingeringEffect);
     }
+
+    public int expMergeMaxValue;
+    private void expMergeMaxValue() {
+        expMergeMaxValue = getInt("experience-merge-max-value", -1);
+        log("Experience Merge Max Value: " + expMergeMaxValue);
+    }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 3ad614b7de..87b2ad7960 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -513,16 +513,32 @@ public class CraftEventFactory {
             EntityExperienceOrb xp = (EntityExperienceOrb) entity;
             double radius = world.spigotConfig.expMerge;
             if (radius > 0) {
+                // Paper start - Maximum exp value when merging - Whole section has been tweaked, see comments for specifics
+                final int maxValue = world.paperConfig.expMergeMaxValue;
+                final boolean mergeUnconditionally = world.paperConfig.expMergeMaxValue <= 0;
+                if (mergeUnconditionally || xp.value < maxValue) { // Paper - Skip iteration if unnecessary
+
                 List<Entity> entities = world.getEntities(entity, entity.getBoundingBox().grow(radius, radius, radius));
                 for (Entity e : entities) {
                     if (e instanceof EntityExperienceOrb) {
                         EntityExperienceOrb loopItem = (EntityExperienceOrb) e;
-                        if (!loopItem.dead) {
-                            xp.value += loopItem.value;
-                            loopItem.die();
+                        // Paper start
+                        if (!loopItem.dead && !(maxValue > 0 && loopItem.value >= maxValue)) {
+                            long newTotal = (long)xp.value + (long)loopItem.value;
+                            if ((int) newTotal < 0) continue; // Overflow
+                            if (maxValue > 0 && newTotal > (long)maxValue) {
+                                loopItem.value = (int) (newTotal - maxValue);
+                                xp.value = maxValue;
+                            } else {
+                                xp.value += loopItem.value;
+                                loopItem.die();
+                            }
+                            // Paper end
                         }
                     }
                 }
+
+                } // Paper end - End iteration skip check - All tweaking ends here
             }
         // Spigot end
         } else if (!(entity instanceof EntityPlayer)) {
-- 
2.21.0