diff --git a/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java b/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java index 53bb296..1256210 100644 --- a/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java +++ b/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java @@ -787,12 +787,19 @@ public void tidyUp() { // Add donated block points (permanent contributions that persist across recalculations). // Recalculate from the donated blocks map using current block config values so the // level always reflects the current configuration, even if block values changed since donation. + // Also apply the current block limit: if the limit was lowered after donation, only count + // up to the current limit (donated blocks over the limit are silently ignored). Map donatedBlocksMap = addon.getManager().getDonatedBlocks(island); long donatedPoints = donatedBlocksMap.entrySet().stream() .mapToLong(entry -> { - Integer value = addon.getBlockConfig().getValue(island.getWorld(), - entry.getKey().toLowerCase(java.util.Locale.ENGLISH)); - return (long) Objects.requireNonNullElse(value, 0) * entry.getValue(); + String key = entry.getKey().toLowerCase(java.util.Locale.ENGLISH); + Integer value = addon.getBlockConfig().getValue(island.getWorld(), key); + int count = entry.getValue(); + Integer limit = addon.getBlockConfig().getLimit(key); + if (limit != null) { + count = Math.min(count, limit); + } + return (long) Objects.requireNonNullElse(value, 0) * count; }) .sum(); results.rawBlockCount.addAndGet(donatedPoints); diff --git a/src/test/java/world/bentobox/level/calculators/IslandLevelCalculatorTidyUpTest.java b/src/test/java/world/bentobox/level/calculators/IslandLevelCalculatorTidyUpTest.java index 545989b..9dfcf81 100644 --- a/src/test/java/world/bentobox/level/calculators/IslandLevelCalculatorTidyUpTest.java +++ b/src/test/java/world/bentobox/level/calculators/IslandLevelCalculatorTidyUpTest.java @@ -7,6 +7,7 @@ import static org.mockito.Mockito.when; import java.util.Collections; +import java.util.Map; import java.util.concurrent.CompletableFuture; import org.bukkit.Location; @@ -183,4 +184,72 @@ void belowStart_sqrtFormula() { long remaining = r.getPointsToNextLevel(); assertEquals(true, remaining > 0, "pointsToNextLevel should be positive, got " + remaining); } + + @Test + @DisplayName("Donated blocks under limit: full donation count is used") + void donatedBlocksUnderLimit() { + // Player donated 500 iron blocks; limit is 1000; block value is 3. + // Expected donated points = 500 * 3 = 1500. + when(manager.getDonatedBlocks(any(Island.class))).thenReturn(Map.of("IRON_BLOCK", 500)); + when(blockConfig.getValue(any(), any(String.class))).thenAnswer(inv -> { + String key = inv.getArgument(1); + return "iron_block".equals(key) ? 3 : 0; + }); + when(blockConfig.getLimit(any(String.class))).thenAnswer(inv -> { + String key = inv.getArgument(0); + return "iron_block".equals(key) ? 1000 : null; + }); + + IslandLevelCalculator calc = newCalculator(); + Results r = calc.getResults(); + r.rawBlockCount.set(INITIAL_COUNT); + calc.tidyUp(); + + assertEquals(1500L, r.getDonatedPoints(), "donated points should equal 500 * 3 = 1500"); + } + + @Test + @DisplayName("Donated blocks exceed limit: only blocks up to the current limit count") + void donatedBlocksExceedLimit() { + // Player donated 1000 iron blocks; limit was later changed to 500; block value is 3. + // Expected donated points = 500 * 3 = 1500 (NOT 1000 * 3 = 3000). + when(manager.getDonatedBlocks(any(Island.class))).thenReturn(Map.of("IRON_BLOCK", 1000)); + when(blockConfig.getValue(any(), any(String.class))).thenAnswer(inv -> { + String key = inv.getArgument(1); + return "iron_block".equals(key) ? 3 : 0; + }); + when(blockConfig.getLimit(any(String.class))).thenAnswer(inv -> { + String key = inv.getArgument(0); + return "iron_block".equals(key) ? 500 : null; + }); + + IslandLevelCalculator calc = newCalculator(); + Results r = calc.getResults(); + r.rawBlockCount.set(INITIAL_COUNT); + calc.tidyUp(); + + assertEquals(1500L, r.getDonatedPoints(), + "donated points should be capped at 500 * 3 = 1500, not 1000 * 3 = 3000"); + } + + @Test + @DisplayName("Donated blocks with no limit: full count is used") + void donatedBlocksNoLimit() { + // Player donated 1000 iron blocks; no limit configured; block value is 3. + // Expected donated points = 1000 * 3 = 3000. + when(manager.getDonatedBlocks(any(Island.class))).thenReturn(Map.of("IRON_BLOCK", 1000)); + when(blockConfig.getValue(any(), any(String.class))).thenAnswer(inv -> { + String key = inv.getArgument(1); + return "iron_block".equals(key) ? 3 : 0; + }); + when(blockConfig.getLimit(any(String.class))).thenReturn(null); + + IslandLevelCalculator calc = newCalculator(); + Results r = calc.getResults(); + r.rawBlockCount.set(INITIAL_COUNT); + calc.tidyUp(); + + assertEquals(3000L, r.getDonatedPoints(), + "donated points should equal 1000 * 3 = 3000 when no limit is configured"); + } }