diff --git a/pom.xml b/pom.xml
index 6cc29cc..9110b4b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -65,7 +65,7 @@
-LOCAL
- 2.3.2
+ 2.3.3
diff --git a/src/main/java/world/bentobox/level/Level.java b/src/main/java/world/bentobox/level/Level.java
index f74a052..12cf20f 100644
--- a/src/main/java/world/bentobox/level/Level.java
+++ b/src/main/java/world/bentobox/level/Level.java
@@ -100,8 +100,33 @@ public class Level extends Addon implements Listener {
@EventHandler
public void onBentoBoxReady(BentoBoxReadyEvent e) {
manager.loadTopTens();
+ /*
+ * DEBUG code to generate fake islands and then try to level them all.
+ Bukkit.getScheduler().runTaskLater(getPlugin(), () -> {
+ getPlugin().getAddonsManager().getGameModeAddons().stream()
+ .filter(gm -> !settings.getGameModes().contains(gm.getDescription().getName()))
+ .forEach(gm -> {
+ for (int i = 0; i < 1000; i++) {
+ try {
+ NewIsland.builder().addon(gm).player(User.getInstance(UUID.randomUUID())).name("default").reason(Reason.CREATE).noPaste().build();
+ } catch (IOException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ }
+ });
+ // Queue all islands DEBUG
+
+ getIslands().getIslands().stream().filter(Island::isOwned).forEach(is -> {
+
+ this.getManager().calculateLevel(is.getOwner(), is).thenAccept(r ->
+ log("Result for island calc " + r.getLevel() + " at " + is.getCenter()));
+
+ });
+ }, 60L);*/
}
+
private void registerPlaceholders(GameModeAddon gm) {
if (getPlugin().getPlaceholdersManager() == null) return;
// Island Level
@@ -172,6 +197,9 @@ public class Level extends Addon implements Listener {
@Override
public void onDisable() {
+ // Stop the pipeline
+ this.getPipeliner().stop();
+ // Save player data and the top tens
if (manager != null) {
manager.save();
}
diff --git a/src/main/java/world/bentobox/level/LevelsManager.java b/src/main/java/world/bentobox/level/LevelsManager.java
index 94a4e8f..b1517a9 100644
--- a/src/main/java/world/bentobox/level/LevelsManager.java
+++ b/src/main/java/world/bentobox/level/LevelsManager.java
@@ -121,7 +121,6 @@ public class LevelsManager {
addon.getPipeliner().addIsland(island).thenAccept(r -> {
// Results are irrelevant because the island is unowned or deleted, or IslandLevelCalcEvent is cancelled
if (r == null || fireIslandLevelCalcEvent(targetPlayer, island, r)) {
- addon.logWarning("Island calcs stopped due to event cancelation");
result.complete(null);
}
// Save result
diff --git a/src/main/java/world/bentobox/level/calculators/Pipeliner.java b/src/main/java/world/bentobox/level/calculators/Pipeliner.java
index 11e08ba..dfc9462 100644
--- a/src/main/java/world/bentobox/level/calculators/Pipeliner.java
+++ b/src/main/java/world/bentobox/level/calculators/Pipeliner.java
@@ -1,6 +1,8 @@
package world.bentobox.level.calculators;
+import java.util.HashSet;
import java.util.Queue;
+import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
@@ -19,9 +21,9 @@ import world.bentobox.level.Level;
public class Pipeliner {
private static final int START_DURATION = 10; // 10 seconds
- private final Queue processQueue;
+ private final Queue toProcessQueue;
+ private final Set inProcessQueue;
private final BukkitTask task;
- private boolean inProcess;
private final Level addon;
private long time;
private long count;
@@ -31,25 +33,26 @@ public class Pipeliner {
*/
public Pipeliner(Level addon) {
this.addon = addon;
- processQueue = new ConcurrentLinkedQueue<>();
+ toProcessQueue = new ConcurrentLinkedQueue<>();
+ inProcessQueue = new HashSet<>();
// Loop continuously - check every tick if there is an island to scan
task = Bukkit.getScheduler().runTaskTimer(BentoBox.getInstance(), () -> {
if (!BentoBox.getInstance().isEnabled()) {
cancel();
return;
}
- // One island at a time
- if (inProcess || processQueue.isEmpty()) return;
-
- IslandLevelCalculator iD = processQueue.poll();
- // Ignore deleted or unonwed islands
- if (iD.getIsland().isDeleted() || iD.getIsland().isUnowned()) return;
- // Start the process
- inProcess = true;
- // Start the scanning of a island with the first chunk
- scanChunk(iD);
-
- }, 1L, 1L);
+ // Complete the current to Process queue first
+ if (!inProcessQueue.isEmpty() || toProcessQueue.isEmpty()) return;
+ for (int j = 0; j < addon.getSettings().getConcurrentIslandCalcs() && !toProcessQueue.isEmpty(); j++) {
+ IslandLevelCalculator iD = toProcessQueue.poll();
+ // Ignore deleted or unonwed islands
+ if (!iD.getIsland().isDeleted() && !iD.getIsland().isUnowned()) {
+ inProcessQueue.add(iD);
+ // Start the scanning of a island with the first chunk
+ scanChunk(iD);
+ }
+ }
+ }, 1L, 10L);
}
private void cancel() {
@@ -60,7 +63,7 @@ public class Pipeliner {
* @return number of islands currently in the queue or in process
*/
public int getIslandsInQueue() {
- return inProcess ? processQueue.size() + 1 : processQueue.size();
+ return inProcessQueue.size() + toProcessQueue.size();
}
/**
@@ -68,10 +71,9 @@ public class Pipeliner {
* @param iD
*/
private void scanChunk(IslandLevelCalculator iD) {
- if (iD.getIsland().isDeleted() || iD.getIsland().isUnowned()) {
+ if (iD.getIsland().isDeleted() || iD.getIsland().isUnowned() || task.isCancelled()) {
// Island is deleted, so finish early with nothing
- addon.log("Canceling island level calculation - island has been deleted, or has become unowned.");
- inProcess = false;
+ inProcessQueue.remove(iD);
iD.getR().complete(null);
return;
}
@@ -80,12 +82,12 @@ public class Pipeliner {
if (!Bukkit.isPrimaryThread()) {
addon.getPlugin().logError("scanChunk not on Primary Thread!");
}
- if (Boolean.TRUE.equals(r)) {
+ if (Boolean.TRUE.equals(r) || task.isCancelled()) {
// scanNextChunk returns true if there are more chunks to scan
scanChunk(iD);
} else {
// Done
- inProcess = false;
+ inProcessQueue.remove(iD);
iD.getR().complete(iD.getResults());
}
});
@@ -100,7 +102,12 @@ public class Pipeliner {
*/
public CompletableFuture addIsland(Island island) {
CompletableFuture r = new CompletableFuture<>();
- processQueue.add(new IslandLevelCalculator(addon, island, r));
+ // Check if queue already contains island
+ /*
+ if (processQueue.parallelStream().map(IslandLevelCalculator::getIsland).anyMatch(island::equals)) {
+ return CompletableFuture.completedFuture(null);
+ }*/
+ toProcessQueue.add(new IslandLevelCalculator(addon, island, r));
count++;
return r;
}
@@ -122,5 +129,15 @@ public class Pipeliner {
this.time += time;
}
+ /**
+ * Stop the current queue.
+ */
+ public void stop() {
+ addon.log("Stopping Level queue");
+ task.cancel();
+ this.inProcessQueue.clear();
+ this.toProcessQueue.clear();
+ }
+
}
diff --git a/src/main/java/world/bentobox/level/config/ConfigSettings.java b/src/main/java/world/bentobox/level/config/ConfigSettings.java
index f0b19cc..ea24e65 100644
--- a/src/main/java/world/bentobox/level/config/ConfigSettings.java
+++ b/src/main/java/world/bentobox/level/config/ConfigSettings.java
@@ -18,6 +18,12 @@ public class ConfigSettings implements ConfigObject {
@ConfigComment("Level will NOT hook into these game mode addons.")
@ConfigEntry(path = "disabled-game-modes")
private List gameModes = Collections.emptyList();
+
+ @ConfigComment("")
+ @ConfigComment("Number of concurrent island calculations")
+ @ConfigComment("If your CPU can handle it, you can run parallel island calcs if there are more than one in the queue")
+ @ConfigEntry(path = "concurrent-island-calcs")
+ private int concurrentIslandCalcs = 1;
@ConfigComment("")
@ConfigComment("Calculate island level on login")
@@ -292,6 +298,24 @@ public class ConfigSettings implements ConfigObject {
}
+ /**
+ * @return the concurrentIslandCalcs
+ */
+ public int getConcurrentIslandCalcs() {
+ if (concurrentIslandCalcs < 1) concurrentIslandCalcs = 1;
+ return concurrentIslandCalcs;
+ }
+
+
+ /**
+ * @param concurrentIslandCalcs the concurrentIslandCalcs to set
+ */
+ public void setConcurrentIslandCalcs(int concurrentIslandCalcs) {
+ if (concurrentIslandCalcs < 1) concurrentIslandCalcs = 1;
+ this.concurrentIslandCalcs = concurrentIslandCalcs;
+ }
+
+
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index d0d988f..77fda09 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -5,6 +5,10 @@
# Level will NOT hook into these game mode addons.
disabled-game-modes:
- AOneBlock
+#
+# Number of concurrent island calculations
+# If your CPU can handle it, you can run parallel island calcs if there are more than one in the queue
+concurrent-island-calcs: 1
#
# Calculate island level on login
# This silently calculates the player's island level when they login