Skip to content

Commit aeee20f

Browse files
tastybentoclaude
andcommitted
Remove experimental per-chunk zeroing engine from develop (#448)
The lazy-zero / per-chunk handicap / parallel chunk scan work merged via PRs #435 and #440 (plus follow-up fixes) is not production-ready: admins running CI snapshot builds saw established island levels reset and recalculations that only counted newly placed blocks (#448). That work now continues on the feat/per-chunk-zeroing branch. This commit restores the stable 2.27.0 calculation engine on develop while keeping everything safe that landed since 2.27.0: - Donation fixes: recalc donated points from donatedBlocks (#438), enforce blockconfig donation limits in GUI/prompts (#439), cap donated counts to current block limits (#443) - MockBukkit pinned to Maven Central 4.110.0 - Modrinth MC 26.1.2 game version (#444) - CI publish workflow changes (#445, #446, #447) - Version stays 2.28.0-SNAPSHOT Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y6f59pxCkwS8QXtJSe1nq6
1 parent 08298a4 commit aeee20f

30 files changed

Lines changed: 18 additions & 1237 deletions

src/main/java/world/bentobox/level/Level.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
import world.bentobox.level.listeners.IslandActivitiesListeners;
4747
import world.bentobox.level.listeners.JoinLeaveListener;
4848
import world.bentobox.level.listeners.MigrationListener;
49-
import world.bentobox.level.listeners.NewChunkListener;
5049
import world.bentobox.level.requests.LevelRequestHandler;
5150
import world.bentobox.level.requests.TopTenRequestHandler;
5251
import world.bentobox.visit.VisitAddon;
@@ -155,10 +154,6 @@ private void registerAllListeners() {
155154
registerListener(new IslandActivitiesListeners(this));
156155
registerListener(new JoinLeaveListener(this));
157156
registerListener(new MigrationListener(this));
158-
// Accumulates generator block points into initialCount as new chunks
159-
// are generated, so large protection ranges work with zero-new-island
160-
// mode without forcing the initial scan to generate the whole area.
161-
registerListener(new NewChunkListener(this));
162157
}
163158

164159
private void registerGameModeCommands() {

src/main/java/world/bentobox/level/LevelsManager.java

Lines changed: 1 addition & 363 deletions
Large diffs are not rendered by default.

src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java

Lines changed: 9 additions & 219 deletions
Large diffs are not rendered by default.

src/main/java/world/bentobox/level/calculators/Pipeliner.java

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import java.util.concurrent.ConcurrentLinkedQueue;
88

99
import org.bukkit.Bukkit;
10-
import org.bukkit.Location;
1110
import org.bukkit.scheduler.BukkitTask;
1211

1312
import world.bentobox.bentobox.BentoBox;
@@ -50,7 +49,7 @@ public Pipeliner(Level addon) {
5049
// Ignore deleted or unowned islands
5150
if (!iD.getIsland().isDeleted() && !iD.getIsland().isUnowned()) {
5251
inProcessQueue.put(iD, System.currentTimeMillis());
53-
BentoBox.getInstance().log("Starting to scan island level at " + formatCenter(iD.getIsland().getCenter()));
52+
BentoBox.getInstance().log("Starting to scan island level at " + iD.getIsland().getCenter());
5453
// Start the scanning of a island with the first chunk
5554
scanIsland(iD);
5655
}
@@ -97,34 +96,17 @@ public CompletableFuture<Results> addIsland(Island island) {
9796
.map(IslandLevelCalculator::getIsland).anyMatch(island::equals)) {
9897
return CompletableFuture.completedFuture(new Results(Result.IN_PROGRESS));
9998
}
100-
BentoBox.getInstance().log("Added island to Level queue: " + formatCenter(island.getCenter()));
99+
BentoBox.getInstance().log("Added island to Level queue: " + island.getCenter());
101100
return addToQueue(island, false);
102101
}
103102

104-
/**
105-
* Render an island centre as "<world_name> x,y,z" for log lines instead of
106-
* Bukkit's verbose Location.toString().
107-
*/
108-
static String formatCenter(Location loc) {
109-
if (loc == null) {
110-
return "?";
111-
}
112-
String worldName = loc.getWorld() == null ? "?" : loc.getWorld().getName();
113-
return worldName + " " + loc.getBlockX() + "," + loc.getBlockY() + "," + loc.getBlockZ();
114-
}
115-
116103
/**
117104
* Adds an island to the scanning queue
118105
* @param island - the island to scan
119106
* @return CompletableFuture of the results
120107
*/
121108
public CompletableFuture<Results> zeroIsland(Island island) {
122-
BentoBox.getInstance().log("Zeroing island level for island at " + formatCenter(island.getCenter()));
123-
// Begin tracking listener events during the scan so chunks that
124-
// generate after the scan polls their position (and are therefore
125-
// missed by the scan) keep their listener-credited handicap instead
126-
// of being wiped by the post-scan baseline reset.
127-
addon.getManager().beginZeroScan(island);
109+
BentoBox.getInstance().log("Zeroing island level for island at " + island.getCenter());
128110
return addToQueue(island, true);
129111
}
130112

@@ -165,17 +147,10 @@ public void stop() {
165147
/**
166148
* @return the inProcessQueue
167149
*/
168-
public Map<IslandLevelCalculator, Long> getInProcessQueue() {
150+
protected Map<IslandLevelCalculator, Long> getInProcessQueue() {
169151
return inProcessQueue;
170152
}
171153

172-
/**
173-
* @return the queue of islands waiting to start scanning
174-
*/
175-
public Queue<IslandLevelCalculator> getToProcessQueue() {
176-
return toProcessQueue;
177-
}
178-
179154
/**
180155
* @return the task
181156
*/
Lines changed: 1 addition & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
package world.bentobox.level.commands;
22

33
import java.util.List;
4-
import java.util.Map;
54

65
import world.bentobox.bentobox.api.commands.CompositeCommand;
76
import world.bentobox.bentobox.api.localization.TextVariables;
87
import world.bentobox.bentobox.api.user.User;
9-
import world.bentobox.bentobox.database.objects.Island;
10-
import world.bentobox.bentobox.util.Util;
118
import world.bentobox.level.Level;
12-
import world.bentobox.level.calculators.IslandLevelCalculator;
139

1410
public class AdminLevelStatusCommand extends CompositeCommand {
1511

@@ -29,59 +25,7 @@ public void setup() {
2925

3026
@Override
3127
public boolean execute(User user, String label, List<String> args) {
32-
int total = addon.getPipeliner().getIslandsInQueue();
33-
user.sendMessage("admin.levelstatus.islands-in-queue", TextVariables.NUMBER, String.valueOf(total));
34-
long now = System.currentTimeMillis();
35-
Map<IslandLevelCalculator, Long> inProcess = addon.getPipeliner().getInProcessQueue();
36-
inProcess.forEach((calc, started) -> {
37-
user.sendMessage(buildDetailKey(calc),
38-
"[world]", worldName(calc),
39-
"[xyz]", xyz(calc),
40-
"[type]", typeKey(user, calc),
41-
"[elapsed]", formatElapsed(now - started),
42-
"[scanned]", String.valueOf(calc.getScannedChunks()),
43-
"[total]", String.valueOf(calc.getTotalChunksToScan()));
44-
int pending = addon.getManager().getPendingZeroCount(calc.getIsland());
45-
if (pending > 0) {
46-
user.sendMessage("admin.levelstatus.pending-zeros",
47-
TextVariables.NUMBER, String.valueOf(pending));
48-
}
49-
});
50-
for (IslandLevelCalculator calc : addon.getPipeliner().getToProcessQueue()) {
51-
user.sendMessage("admin.levelstatus.island-queued",
52-
"[world]", worldName(calc),
53-
"[xyz]", xyz(calc),
54-
"[type]", typeKey(user, calc));
55-
}
28+
user.sendMessage("admin.levelstatus.islands-in-queue", TextVariables.NUMBER, String.valueOf(addon.getPipeliner().getIslandsInQueue()));
5629
return true;
5730
}
58-
59-
private String buildDetailKey(IslandLevelCalculator calc) {
60-
return "admin.levelstatus.island-detail";
61-
}
62-
63-
private String worldName(IslandLevelCalculator calc) {
64-
Island island = calc.getIsland();
65-
return island.getWorld() == null ? "?" : island.getWorld().getName();
66-
}
67-
68-
private String xyz(IslandLevelCalculator calc) {
69-
Island island = calc.getIsland();
70-
if (island.getCenter() == null) {
71-
return "?";
72-
}
73-
return Util.xyz(island.getCenter().toVector());
74-
}
75-
76-
private String typeKey(User user, IslandLevelCalculator calc) {
77-
return user.getTranslation(calc.isZeroIsland()
78-
? "admin.levelstatus.type-zero" : "admin.levelstatus.type-regular");
79-
}
80-
81-
private String formatElapsed(long ms) {
82-
long s = Math.max(0, ms / 1000);
83-
long m = s / 60;
84-
s = s % 60;
85-
return m > 0 ? (m + "m" + s + "s") : (s + "s");
86-
}
8731
}

src/main/java/world/bentobox/level/config/ConfigSettings.java

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -54,23 +54,6 @@ public class ConfigSettings implements ConfigObject {
5454
@ConfigEntry(path = "zero-new-island-levels")
5555
private boolean zeroNewIslandLevels = true;
5656

57-
@ConfigComment("")
58-
@ConfigComment("Delay (in ticks) between a chunk being freshly generated and that chunk")
59-
@ConfigComment("being scanned for the lazy-zero handicap. The delay lets neighbouring")
60-
@ConfigComment("chunks finish their decoration phase (obsidian from lava-water, ore")
61-
@ConfigComment("patches that spill across borders, broken nether portal spawns, etc.)")
62-
@ConfigComment("so the captured snapshot matches what a regular level scan would later")
63-
@ConfigComment("find. The level scan also waits for any in-flight delayed captures to")
64-
@ConfigComment("complete before returning the result, so the handicap is always up to")
65-
@ConfigComment("date with the chunks that have generated. 20 ticks = 1 second.")
66-
@ConfigComment("Underwater obsidian on AcidIsland needs lava sources to flow into")
67-
@ConfigComment("adjacent water before they convert — that can take 20-30 seconds, so")
68-
@ConfigComment("the default is set high enough to catch it. Lower if you don't care")
69-
@ConfigComment("about slow-forming terrain and want /level to settle faster after a")
70-
@ConfigComment("burst of exploration.")
71-
@ConfigEntry(path = "zero-scan-delay-ticks")
72-
private int zeroScanDelayTicks = 600;
73-
7457
@ConfigComment("")
7558
@ConfigComment("Donations-only mode")
7659
@ConfigComment("If true, the island block scan is skipped entirely and the island level")
@@ -414,20 +397,6 @@ public void setZeroNewIslandLevels(boolean zeroNewIslandLevels) {
414397
this.zeroNewIslandLevels = zeroNewIslandLevels;
415398
}
416399

417-
/**
418-
* @return the zeroScanDelayTicks
419-
*/
420-
public int getZeroScanDelayTicks() {
421-
return zeroScanDelayTicks;
422-
}
423-
424-
/**
425-
* @param zeroScanDelayTicks the zeroScanDelayTicks to set
426-
*/
427-
public void setZeroScanDelayTicks(int zeroScanDelayTicks) {
428-
this.zeroScanDelayTicks = zeroScanDelayTicks;
429-
}
430-
431400

432401
/**
433402
* @return the calculationTimeout

src/main/java/world/bentobox/level/listeners/IslandActivitiesListeners.java

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,8 @@ public IslandActivitiesListeners(Level addon) {
4141
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
4242
public void onNewIsland(IslandCreatedEvent e) {
4343
if (addon.getSettings().isZeroNewIslandLevels()) {
44-
// Delay the zero scan so decoration (fluid simulation,
45-
// late-arriving obsidian/portal frames, trial-spawner setup,
46-
// chunk-border ore patches) has time to settle before we
47-
// snapshot the baseline. Reuses the listener's decoration-settle
48-
// setting (zero-scan-delay-ticks, default 600 = 30s) so both
49-
// paths honour the same "give the world a chance to finish
50-
// generating" window.
51-
long delay = Math.max(150L, addon.getSettings().getZeroScanDelayTicks());
52-
Bukkit.getScheduler().runTaskLater(addon.getPlugin(), () -> zeroIsland(e.getIsland()), delay);
44+
// Wait a few seconds before performing the zero
45+
Bukkit.getScheduler().runTaskLater(addon.getPlugin(), () -> zeroIsland(e.getIsland()), 150L);
5346
}
5447
}
5548

@@ -64,33 +57,7 @@ private void zeroIsland(final Island island) {
6457
// Clear the island setting
6558
if (island.getOwner() != null && island.getWorld() != null) {
6659
addon.getPipeliner().zeroIsland(island)
67-
.thenAccept(results -> {
68-
if (results == null) {
69-
// Scan was aborted (island deleted/unowned mid-flight).
70-
// Drop the tracking maps so the next zero scan
71-
// for this island starts clean.
72-
addon.getManager().drainZeroScanDeferred(island);
73-
return;
74-
}
75-
// Hard reset the baseline. The calculator already
76-
// overwrote the per-chunk handicap map with the
77-
// scanned values via reconcileHandicapChunks(...,
78-
// zeroScan=true) inside tidyUp; this aligns the
79-
// initialCount with that same baseline.
80-
addon.getManager().setInitialIslandCount(island, results.getTotalPoints());
81-
// Fold in any listener credits captured during the
82-
// scan for chunks the scan didn't visit (e.g.
83-
// chunks generated mid-scan after their position
84-
// was already polled). Reconciling these as a
85-
// non-zero scan adds them to both the per-chunk
86-
// map and the initialCount in one atomic write,
87-
// so subsequent scans see those chunks as fully
88-
// accounted for.
89-
java.util.Map<String, Long> missed = addon.getManager().drainZeroScanDeferred(island);
90-
if (!missed.isEmpty()) {
91-
addon.getManager().reconcileHandicapChunks(island, missed, false);
92-
}
93-
});
60+
.thenAccept(results -> addon.getManager().setInitialIslandCount(island, results.getTotalPoints()));
9461
}
9562
}
9663

src/main/java/world/bentobox/level/listeners/NewChunkListener.java

Lines changed: 0 additions & 120 deletions
This file was deleted.

0 commit comments

Comments
 (0)