From 91a69adae18935b8369ace9e203494a166f11d26 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sat, 9 Nov 2019 20:09:16 -0800 Subject: [PATCH 01/23] Split out Results class. --- .../calculators/IslandLevelCalculator.java | 10 + .../bentobox/level/calculators/Results.java | 173 ++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java create mode 100644 src/main/java/world/bentobox/level/calculators/Results.java diff --git a/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java b/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java new file mode 100644 index 0000000..d3cde39 --- /dev/null +++ b/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java @@ -0,0 +1,10 @@ +package world.bentobox.level.calculators; + +public interface IslandLevelCalculator { + + /** + * @return the results of the island calculation + */ + public Results getResult(); + +} diff --git a/src/main/java/world/bentobox/level/calculators/Results.java b/src/main/java/world/bentobox/level/calculators/Results.java new file mode 100644 index 0000000..28b70b9 --- /dev/null +++ b/src/main/java/world/bentobox/level/calculators/Results.java @@ -0,0 +1,173 @@ +package world.bentobox.level.calculators; + +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.Material; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; + +/** + * Results class + * + */ +public class Results { + private int deathHandicap = 0; + private long initialLevel = 0; + private long level = 0; + private final Multiset mdCount = HashMultiset.create(); + private final Multiset ncCount = HashMultiset.create(); + private final Multiset ofCount = HashMultiset.create(); + private long pointsToNextLevel = 0; + private long rawBlockCount = 0; + private List report = new ArrayList<>(); + private long underWaterBlockCount = 0; + private final Multiset uwCount = HashMultiset.create(); + + /** + * @return the deathHandicap + */ + public int getDeathHandicap() { + return deathHandicap; + } + + public long getInitialLevel() { + return initialLevel; + } + /** + * @return the level + */ + public long getLevel() { + return level; + } + /** + * @return the mdCount + */ + public Multiset getMdCount() { + return mdCount; + } + /** + * @return the ncCount + */ + public Multiset getNcCount() { + return ncCount; + } + + /** + * @return the ofCount + */ + public Multiset getOfCount() { + return ofCount; + } + + /** + * @return the pointsToNextLevel + */ + public long getPointsToNextLevel() { + return pointsToNextLevel; + } + + /** + * @return the rawBlockCount + */ + public long getRawBlockCount() { + return rawBlockCount; + } + + /** + * @return the report + */ + public List getReport() { + return report; + } + + /** + * @return the underWaterBlockCount + */ + public long getUnderWaterBlockCount() { + return underWaterBlockCount; + } + + /** + * @return the uwCount + */ + public Multiset getUwCount() { + return uwCount; + } + + /** + * @param deathHandicap the deathHandicap to set + */ + public void setDeathHandicap(int deathHandicap) { + this.deathHandicap = deathHandicap; + } + + public void setInitialLevel(long initialLevel) { + this.initialLevel = initialLevel; + } + + /** + * Set level + * @param level - level + */ + public void setLevel(int level) { + this.level = level; + } + + /** + * @param level the level to set + */ + public void setLevel(long level) { + this.level = level; + } + + /** + * @param pointsToNextLevel the pointsToNextLevel to set + */ + public void setPointsToNextLevel(long pointsToNextLevel) { + this.pointsToNextLevel = pointsToNextLevel; + } + + /** + * @param rawBlockCount the rawBlockCount to set + */ + public void setRawBlockCount(long rawBlockCount) { + this.rawBlockCount = rawBlockCount; + } + + /** + * @param report the report to set + */ + public void setReport(List report) { + this.report = report; + } + + /** + * @param underWaterBlockCount the underWaterBlockCount to set + */ + public void setUnderWaterBlockCount(long underWaterBlockCount) { + this.underWaterBlockCount = underWaterBlockCount; + } + + /** + * Add to death handicap + * @param deaths - number to add + */ + public void addToDeathHandicap(int deaths) { + this.deathHandicap += deaths; + + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "Results [report=" + report + ", mdCount=" + mdCount + ", uwCount=" + getUwCount() + ", ncCount=" + + ncCount + ", ofCount=" + ofCount + ", rawBlockCount=" + rawBlockCount + ", underWaterBlockCount=" + + getUnderWaterBlockCount() + ", level=" + level + ", deathHandicap=" + deathHandicap + + ", pointsToNextLevel=" + pointsToNextLevel + ", initialLevel=" + initialLevel + "]"; + } + +} \ No newline at end of file From 55f6a124bf2021810941d5b91962774a7bc192e1 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sat, 9 Nov 2019 20:34:12 -0800 Subject: [PATCH 02/23] Does not save chunks on unloading. --- .../java/world/bentobox/level/calculators/CalcIslandLevel.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java index 3971fab..60a07fc 100644 --- a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java +++ b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java @@ -104,9 +104,8 @@ public class CalcIslandLevel { Pair pair = it.next(); for (World worldToScan : worlds) { if (!worldToScan.isChunkLoaded(pair.x, pair.z)) { - worldToScan.loadChunk(pair.x, pair.z); chunkSnapshot.add(worldToScan.getChunkAt(pair.x, pair.z).getChunkSnapshot()); - worldToScan.unloadChunk(pair.x, pair.z); + worldToScan.unloadChunk(pair.x, pair.z, false); } else { chunkSnapshot.add(worldToScan.getChunkAt(pair.x, pair.z).getChunkSnapshot()); } From 4e33df1927d6aef826261002fa987eede3b4e38f Mon Sep 17 00:00:00 2001 From: tastybento Date: Sat, 9 Nov 2019 20:51:41 -0800 Subject: [PATCH 03/23] Added forced chunk loading back in. --- .../java/world/bentobox/level/calculators/CalcIslandLevel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java index 60a07fc..9c611d4 100644 --- a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java +++ b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java @@ -104,6 +104,7 @@ public class CalcIslandLevel { Pair pair = it.next(); for (World worldToScan : worlds) { if (!worldToScan.isChunkLoaded(pair.x, pair.z)) { + worldToScan.loadChunk(pair.x, pair.z); chunkSnapshot.add(worldToScan.getChunkAt(pair.x, pair.z).getChunkSnapshot()); worldToScan.unloadChunk(pair.x, pair.z, false); } else { From e383f79e3e8848c0f29f4bdf465e2a818909d712 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sun, 10 Nov 2019 15:06:30 -0800 Subject: [PATCH 04/23] Remove loadchunk from chunk snapshot. --- .../java/world/bentobox/level/calculators/CalcIslandLevel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java index 9c611d4..9eb846a 100644 --- a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java +++ b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java @@ -104,7 +104,7 @@ public class CalcIslandLevel { Pair pair = it.next(); for (World worldToScan : worlds) { if (!worldToScan.isChunkLoaded(pair.x, pair.z)) { - worldToScan.loadChunk(pair.x, pair.z); + //worldToScan.loadChunk(pair.x, pair.z); chunkSnapshot.add(worldToScan.getChunkAt(pair.x, pair.z).getChunkSnapshot()); worldToScan.unloadChunk(pair.x, pair.z, false); } else { From d4c9bd654dbb6fa77241da2db0733a61b66019f4 Mon Sep 17 00:00:00 2001 From: tastybento Date: Fri, 15 Nov 2019 19:31:58 -0800 Subject: [PATCH 05/23] Uses PaperLib to get chunks async (#95) * Uses PaperLib to get chunks async. Appears to work fine on regular Spigot too. * Removes config settings not required anymore. * Future is on main thread, so do calcs async * Implements multi-threaded level calculation. * Remove debug from version --- pom.xml | 34 ++- .../level/calculators/CalcIslandLevel.java | 220 +++++++++++------- .../level/calculators/PlayerLevel.java | 2 +- .../world/bentobox/level/config/Settings.java | 66 +----- src/main/resources/config.yml | 16 +- 5 files changed, 183 insertions(+), 155 deletions(-) diff --git a/pom.xml b/pom.xml index 3054232..93f075a 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ -LOCAL - 1.8.0 + 1.8.1 @@ -147,6 +147,10 @@ codemc-public https://repo.codemc.org/repository/maven-public/ + + papermc + https://papermc.io/repo/repository/maven-public/ + @@ -182,6 +186,12 @@ ${bentobox.version} provided + + io.papermc + paperlib + 1.0.2 + compile + @@ -278,6 +288,28 @@ maven-deploy-plugin 2.8.2 + + org.apache.maven.plugins + maven-shade-plugin + 3.1.1 + + ${project.build.directory}/dependency-reduced-pom.xml + + + io.papermc.lib + world.bentobox.level.paperlib + + + + + + package + + shade + + + + org.jacoco jacoco-maven-plugin diff --git a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java index 9eb846a..4a19578 100644 --- a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java +++ b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java @@ -8,6 +8,8 @@ import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import org.bukkit.Bukkit; import org.bukkit.ChunkSnapshot; @@ -16,13 +18,13 @@ import org.bukkit.Tag; import org.bukkit.World; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.type.Slab; -import org.bukkit.scheduler.BukkitTask; import com.google.common.collect.HashMultiset; import com.google.common.collect.Multiset; import com.google.common.collect.Multiset.Entry; import com.google.common.collect.Multisets; +import io.papermc.lib.PaperLib; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.util.Pair; import world.bentobox.bentobox.util.Util; @@ -31,11 +33,9 @@ import world.bentobox.level.Level; public class CalcIslandLevel { - private final int maxChunks; - private final long speed; private static final String LINE_BREAK = "=================================="; - private boolean checking; - private final BukkitTask task; + + public static final long MAX_AMOUNT = 10000; private final Level addon; @@ -49,6 +49,8 @@ public class CalcIslandLevel { private final World world; private final List worlds; + private int count; + /** * Calculate the island's level @@ -78,56 +80,22 @@ public class CalcIslandLevel { result = new Results(); // Set the initial island handicap - result.initialLevel = addon.getInitialIslandLevel(island); - - speed = addon.getSettings().getUpdateTickDelay(); - maxChunks = addon.getSettings().getChunksPerTick(); + result.setInitialLevel(addon.getInitialIslandLevel(island)); // Get chunks to scan chunksToScan = getChunksToScan(island); - - // Start checking - checking = true; - - // Start a recurring task until done or cancelled - task = addon.getServer().getScheduler().runTaskTimer(addon.getPlugin(), () -> { - Set chunkSnapshot = new HashSet<>(); - if (checking) { - Iterator> it = chunksToScan.iterator(); - if (!it.hasNext()) { - // Nothing left - tidyUp(); - return; - } - // Add chunk snapshots to the list - while (it.hasNext() && chunkSnapshot.size() < maxChunks) { - Pair pair = it.next(); - for (World worldToScan : worlds) { - if (!worldToScan.isChunkLoaded(pair.x, pair.z)) { - //worldToScan.loadChunk(pair.x, pair.z); - chunkSnapshot.add(worldToScan.getChunkAt(pair.x, pair.z).getChunkSnapshot()); - worldToScan.unloadChunk(pair.x, pair.z, false); - } else { - chunkSnapshot.add(worldToScan.getChunkAt(pair.x, pair.z).getChunkSnapshot()); - } + count = 0; + chunksToScan.forEach(c -> { + PaperLib.getChunkAtAsync(world, c.x, c.z).thenAccept(ch -> { + ChunkSnapshot snapShot = ch.getChunkSnapshot(); + Bukkit.getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> { + this.scanChunk(snapShot); + count++; + if (count == chunksToScan.size()) { + this.tidyUp(); } - it.remove(); - } - // Move to next step - checking = false; - checkChunksAsync(chunkSnapshot); - } - }, 0L, speed); - } - - private void checkChunksAsync(final Set chunkSnapshot) { - // Run async task to scan chunks - addon.getServer().getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> { - for (ChunkSnapshot chunk: chunkSnapshot) { - scanChunk(chunk); - } - // Nothing happened, change state - checking = true; + }); + }); }); } @@ -168,10 +136,10 @@ public class CalcIslandLevel { private void checkBlock(BlockData bd, boolean belowSeaLevel) { int count = limitCount(bd.getMaterial()); if (belowSeaLevel) { - result.underWaterBlockCount += count; + result.underWaterBlockCount.addAndGet(count); result.uwCount.add(bd.getMaterial()); } else { - result.rawBlockCount += count; + result.rawBlockCount.addAndGet(count); result.mdCount.add(bd.getMaterial()); } } @@ -231,40 +199,40 @@ public class CalcIslandLevel { } private void tidyUp() { - // Cancel - task.cancel(); // Finalize calculations - result.rawBlockCount += (long)(result.underWaterBlockCount * addon.getSettings().getUnderWaterMultiplier()); + result.rawBlockCount.addAndGet((long)(result.underWaterBlockCount.get() * addon.getSettings().getUnderWaterMultiplier())); // Set the death penalty if (this.addon.getSettings().isSumTeamDeaths()) { for (UUID uuid : this.island.getMemberSet()) { - this.result.deathHandicap += this.addon.getPlayers().getDeaths(this.world, uuid); + this.result.deathHandicap.addAndGet(this.addon.getPlayers().getDeaths(this.world, uuid)); } } else { // At this point, it may be that the island has become unowned. - this.result.deathHandicap = this.island.getOwner() == null ? 0 : - this.addon.getPlayers().getDeaths(this.world, this.island.getOwner()); + this.result.deathHandicap.set(this.island.getOwner() == null ? 0 : + this.addon.getPlayers().getDeaths(this.world, this.island.getOwner())); } - long blockAndDeathPoints = this.result.rawBlockCount; + long blockAndDeathPoints = this.result.rawBlockCount.get(); if (this.addon.getSettings().getDeathPenalty() > 0) { // Proper death penalty calculation. - blockAndDeathPoints -= this.result.deathHandicap * this.addon.getSettings().getDeathPenalty(); + blockAndDeathPoints -= this.result.deathHandicap.get() * this.addon.getSettings().getDeathPenalty(); } - - this.result.level = blockAndDeathPoints / this.addon.getSettings().getLevelCost() - this.island.getLevelHandicap() - result.initialLevel; - + this.result.level.set(calculateLevel(blockAndDeathPoints)); // Calculate how many points are required to get to the next level - this.result.pointsToNextLevel = this.addon.getSettings().getLevelCost() - - (blockAndDeathPoints % this.addon.getSettings().getLevelCost()); + long nextLevel = this.result.level.get(); + long blocks = blockAndDeathPoints; + while (nextLevel < this.result.level.get() + 1 && blocks - blockAndDeathPoints < MAX_AMOUNT) { + nextLevel = calculateLevel(++blocks); + } + this.result.pointsToNextLevel.set(blocks - blockAndDeathPoints); // Report result.report = getReport(); @@ -275,16 +243,23 @@ public class CalcIslandLevel { } + private long calculateLevel(long blockAndDeathPoints) { + String calcString = addon.getSettings().getLevelCalc(); + String withValues = calcString.replace("blocks", String.valueOf(blockAndDeathPoints)).replace("level_cost", String.valueOf(this.addon.getSettings().getLevelCost())); + return (long)eval(withValues) - this.island.getLevelHandicap() - result.initialLevel.get(); + } + private List getReport() { List reportLines = new ArrayList<>(); // provide counts reportLines.add("Level Log for island in " + addon.getPlugin().getIWM().getFriendlyName(island.getWorld()) + " at " + Util.xyz(island.getCenter().toVector())); reportLines.add("Island owner UUID = " + island.getOwner()); - reportLines.add("Total block value count = " + String.format("%,d",result.rawBlockCount)); + reportLines.add("Total block value count = " + String.format("%,d",result.rawBlockCount.get())); + reportLines.add("Formula to calculate island level: " + addon.getSettings().getLevelCalc()); reportLines.add("Level cost = " + addon.getSettings().getLevelCost()); - reportLines.add("Deaths handicap = " + result.deathHandicap); - reportLines.add("Initial island level = " + (0L - result.initialLevel)); - reportLines.add("Level calculated = " + result.level); + reportLines.add("Deaths handicap = " + result.deathHandicap.get()); + reportLines.add("Initial island level = " + (0L - result.initialLevel.get())); + reportLines.add("Level calculated = " + result.level.get()); reportLines.add(LINE_BREAK); int total = 0; if (!result.uwCount.isEmpty()) { @@ -359,18 +334,19 @@ public class CalcIslandLevel { private final Multiset uwCount = HashMultiset.create(); private final Multiset ncCount = HashMultiset.create(); private final Multiset ofCount = HashMultiset.create(); - private long rawBlockCount = 0; - private long underWaterBlockCount = 0; - private long level = 0; - private int deathHandicap = 0; - private long pointsToNextLevel = 0; - private long initialLevel = 0; + // AtomicLong and AtomicInteger must be used because they are changed by multiple concurrent threads + private AtomicLong rawBlockCount = new AtomicLong(0); + private AtomicLong underWaterBlockCount = new AtomicLong(0); + private AtomicLong level = new AtomicLong(0); + private AtomicInteger deathHandicap = new AtomicInteger(0); + private AtomicLong pointsToNextLevel = new AtomicLong(0); + private AtomicLong initialLevel = new AtomicLong(0); /** * @return the deathHandicap */ public int getDeathHandicap() { - return deathHandicap; + return deathHandicap.get(); } /** @@ -384,27 +360,27 @@ public class CalcIslandLevel { * @param level - level */ public void setLevel(int level) { - this.level = level; + this.level.set(level); } /** * @return the level */ public long getLevel() { - return level; + return level.get(); } /** * @return the pointsToNextLevel */ public long getPointsToNextLevel() { - return pointsToNextLevel; + return pointsToNextLevel.get(); } public long getInitialLevel() { - return initialLevel; + return initialLevel.get(); } public void setInitialLevel(long initialLevel) { - this.initialLevel = initialLevel; + this.initialLevel.set(initialLevel); } /* (non-Javadoc) @@ -419,4 +395,84 @@ public class CalcIslandLevel { } } + + private static double eval(final String str) { + return new Object() { + int pos = -1, ch; + + void nextChar() { + ch = (++pos < str.length()) ? str.charAt(pos) : -1; + } + + boolean eat(int charToEat) { + while (ch == ' ') nextChar(); + if (ch == charToEat) { + nextChar(); + return true; + } + return false; + } + + double parse() { + nextChar(); + double x = parseExpression(); + if (pos < str.length()) throw new RuntimeException("Unexpected: " + (char)ch); + return x; + } + + // Grammar: + // expression = term | expression `+` term | expression `-` term + // term = factor | term `*` factor | term `/` factor + // factor = `+` factor | `-` factor | `(` expression `)` + // | number | functionName factor | factor `^` factor + + double parseExpression() { + double x = parseTerm(); + for (;;) { + if (eat('+')) x += parseTerm(); // addition + else if (eat('-')) x -= parseTerm(); // subtraction + else return x; + } + } + + double parseTerm() { + double x = parseFactor(); + for (;;) { + if (eat('*')) x *= parseFactor(); // multiplication + else if (eat('/')) x /= parseFactor(); // division + else return x; + } + } + + double parseFactor() { + if (eat('+')) return parseFactor(); // unary plus + if (eat('-')) return -parseFactor(); // unary minus + + double x; + int startPos = this.pos; + if (eat('(')) { // parentheses + x = parseExpression(); + eat(')'); + } else if ((ch >= '0' && ch <= '9') || ch == '.') { // numbers + while ((ch >= '0' && ch <= '9') || ch == '.') nextChar(); + x = Double.parseDouble(str.substring(startPos, this.pos)); + } else if (ch >= 'a' && ch <= 'z') { // functions + while (ch >= 'a' && ch <= 'z') nextChar(); + String func = str.substring(startPos, this.pos); + x = parseFactor(); + if (func.equals("sqrt")) x = Math.sqrt(x); + else if (func.equals("sin")) x = Math.sin(Math.toRadians(x)); + else if (func.equals("cos")) x = Math.cos(Math.toRadians(x)); + else if (func.equals("tan")) x = Math.tan(Math.toRadians(x)); + else throw new RuntimeException("Unknown function: " + func); + } else { + throw new RuntimeException("Unexpected: " + (char)ch); + } + + if (eat('^')) x = Math.pow(x, parseFactor()); // exponentiation + + return x; + } + }.parse(); + } } diff --git a/src/main/java/world/bentobox/level/calculators/PlayerLevel.java b/src/main/java/world/bentobox/level/calculators/PlayerLevel.java index 68a71e4..90e3f3f 100644 --- a/src/main/java/world/bentobox/level/calculators/PlayerLevel.java +++ b/src/main/java/world/bentobox/level/calculators/PlayerLevel.java @@ -90,7 +90,7 @@ public class PlayerLevel { asker.sendMessage("island.level.deaths", "[number]", String.valueOf(results.getDeathHandicap())); } // Send player how many points are required to reach next island level - if (results.getPointsToNextLevel() >= 0) { + if (results.getPointsToNextLevel() >= 0 && results.getPointsToNextLevel() < CalcIslandLevel.MAX_AMOUNT) { asker.sendMessage("island.level.required-points-to-next-level", "[points]", String.valueOf(results.getPointsToNextLevel())); } // Tell other team members diff --git a/src/main/java/world/bentobox/level/config/Settings.java b/src/main/java/world/bentobox/level/config/Settings.java index a0e1e31..bdd290e 100644 --- a/src/main/java/world/bentobox/level/config/Settings.java +++ b/src/main/java/world/bentobox/level/config/Settings.java @@ -23,16 +23,6 @@ public class Settings { private long levelCost; private int levelWait; - /** - * Stores number of chunks that can be updated in single tick. - */ - private int chunksPerTick; - - /** - * Stores number of tick delay between each chunk loading. - */ - private long updateTickDelay; - private List gameModes; @@ -43,22 +33,6 @@ public class Settings { // GameModes gameModes = level.getConfig().getStringList("game-modes"); - // Level calculation chunk load speed - this.setUpdateTickDelay(level.getConfig().getLong("updatetickdelay", 1)); - - if (this.getUpdateTickDelay() <= 0) - { - this.setUpdateTickDelay(1); - } - - // Level calculation chunk count per update - this.setChunksPerTick(level.getConfig().getInt("chunkspertick", 200)); - - if (this.getChunksPerTick() <= 0) - { - this.setChunksPerTick(200); - } - setLevelWait(level.getConfig().getInt("levelwait", 60)); if (getLevelWait() < 0) { setLevelWait(0); @@ -246,45 +220,11 @@ public class Settings { return level.getConfig().getBoolean("shorthand"); } - /** - * This method returns the number of chunks that can be processed at single tick. - * @return the value of chunksPerTick. + * @return the formula to calculate island levels */ - public int getChunksPerTick() - { - return this.chunksPerTick; + public String getLevelCalc() { + return level.getConfig().getString("level-calc", "blocks / level_cost"); } - - /** - * This method sets the chunksPerTick value. - * @param chunksPerTick the chunksPerTick new value. - * - */ - public void setChunksPerTick(int chunksPerTick) - { - this.chunksPerTick = chunksPerTick; - } - - - /** - * This method returns the delay between each update call. - * @return the value of updateTickDelay. - */ - public long getUpdateTickDelay() - { - return this.updateTickDelay; - } - - - /** - * This method sets the updateTickDelay value. - * @param updateTickDelay the updateTickDelay new value. - * - */ - public void setUpdateTickDelay(long updateTickDelay) - { - this.updateTickDelay = updateTickDelay; - } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index ad79e4a..ae1f500 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -37,17 +37,17 @@ underwater: 1.0 # Value of one island level. Default 100. Minimum value is 1. levelcost: 100 +# Island level calculation formula +# blocks - the sum total of all block values, less any death penalty +# level_cost - in a linear equation, the value of one level +# This formula can include +,=,*,/,sqrt,^,sin,cos,tan. Result will always be rounded to a long integer +# for example, an alternative non-linear option could be: 3 * sqrt(blocks / level_cost) +level-calc: blocks / level_cost + + # Cooldown between level requests in seconds levelwait: 60 -# Delay between each task that loads chunks for calculating island level. -# Increasing this will increase time to calculate island level. -updatetickdelay: 1 - -# Number of chunks that will be processed at the same tick. -# Decreasing this will increase time to calculate island level. -chunkspertick: 200 - # Death penalty # How many block values a player will lose per death. # Default value of 100 means that for every death, the player will lose 1 level (if levelcost is 100) From 838507cc4aeb8e836dd7219f990420f0619cde5a Mon Sep 17 00:00:00 2001 From: tastybento Date: Sat, 16 Nov 2019 15:31:58 -0800 Subject: [PATCH 06/23] Uses BentoBox 1.9.0 API for PaperLib --- pom.xml | 36 ++----------------- .../level/calculators/CalcIslandLevel.java | 3 +- 2 files changed, 3 insertions(+), 36 deletions(-) diff --git a/pom.xml b/pom.xml index 93f075a..036adc1 100644 --- a/pom.xml +++ b/pom.xml @@ -59,13 +59,13 @@ 2.0.2 1.14.4-R0.1-SNAPSHOT - 1.8.0 + 1.9.0-SNAPSHOT ${build.version}-SNAPSHOT -LOCAL - 1.8.1 + 1.9.0 @@ -147,10 +147,6 @@ codemc-public https://repo.codemc.org/repository/maven-public/ - - papermc - https://papermc.io/repo/repository/maven-public/ - @@ -186,12 +182,6 @@ ${bentobox.version} provided - - io.papermc - paperlib - 1.0.2 - compile - @@ -288,28 +278,6 @@ maven-deploy-plugin 2.8.2 - - org.apache.maven.plugins - maven-shade-plugin - 3.1.1 - - ${project.build.directory}/dependency-reduced-pom.xml - - - io.papermc.lib - world.bentobox.level.paperlib - - - - - - package - - shade - - - - org.jacoco jacoco-maven-plugin diff --git a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java index 4a19578..9d27c12 100644 --- a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java +++ b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java @@ -24,7 +24,6 @@ import com.google.common.collect.Multiset; import com.google.common.collect.Multiset.Entry; import com.google.common.collect.Multisets; -import io.papermc.lib.PaperLib; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.util.Pair; import world.bentobox.bentobox.util.Util; @@ -86,7 +85,7 @@ public class CalcIslandLevel { chunksToScan = getChunksToScan(island); count = 0; chunksToScan.forEach(c -> { - PaperLib.getChunkAtAsync(world, c.x, c.z).thenAccept(ch -> { + Util.getChunkAtAsync(world, c.x, c.z).thenAccept(ch -> { ChunkSnapshot snapShot = ch.getChunkSnapshot(); Bukkit.getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> { this.scanChunk(snapShot); From d6117e69d8d2c08442c0fa2083178aef81ce159c Mon Sep 17 00:00:00 2001 From: tastybento Date: Sat, 16 Nov 2019 17:24:11 -0800 Subject: [PATCH 07/23] Properly deletes hidden players from top ten https://github.com/BentoBoxWorld/Level/issues/98 --- src/main/java/world/bentobox/level/TopTen.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/world/bentobox/level/TopTen.java b/src/main/java/world/bentobox/level/TopTen.java index 63044b9..5cefebd 100644 --- a/src/main/java/world/bentobox/level/TopTen.java +++ b/src/main/java/world/bentobox/level/TopTen.java @@ -107,6 +107,8 @@ public class TopTen implements Listener { if (!entry.hasPermission(permPrefix + "intopten")) { it.remove(); show = false; + // Remove from Top Ten completely + topTenList.get(world).remove(topTenUUID); } } if (show) { From 7ef2e35d9233cbd1af41e5e9b8f06411247c5dae Mon Sep 17 00:00:00 2001 From: tastybento Date: Sat, 16 Nov 2019 18:25:54 -0800 Subject: [PATCH 08/23] Create ro.yml --- src/main/resources/locales/ro.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/main/resources/locales/ro.yml diff --git a/src/main/resources/locales/ro.yml b/src/main/resources/locales/ro.yml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/main/resources/locales/ro.yml @@ -0,0 +1 @@ + From d227606f7ad80777e6569bfb6b6316da78156284 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sat, 16 Nov 2019 18:26:04 -0800 Subject: [PATCH 09/23] Create id.yml --- src/main/resources/locales/id.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/main/resources/locales/id.yml diff --git a/src/main/resources/locales/id.yml b/src/main/resources/locales/id.yml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/main/resources/locales/id.yml @@ -0,0 +1 @@ + From 05437ca14a28c43509d9e0c2103f6d37af85ea4f Mon Sep 17 00:00:00 2001 From: tastybento Date: Sat, 16 Nov 2019 18:56:33 -0800 Subject: [PATCH 10/23] Added admin top remove command to remove players from top ten https://github.com/BentoBoxWorld/Level/issues/98 --- .../java/world/bentobox/level/TopTen.java | 2 + .../level/commands/admin/AdminTopCommand.java | 1 + .../commands/admin/AdminTopRemoveCommand.java | 55 +++++ src/main/resources/locales/en-US.yml | 3 + .../admin/AdminTopRemoveCommandTest.java | 188 ++++++++++++++++++ 5 files changed, 249 insertions(+) create mode 100644 src/main/java/world/bentobox/level/commands/admin/AdminTopRemoveCommand.java create mode 100644 src/test/java/world/bentobox/level/commands/admin/AdminTopRemoveCommandTest.java diff --git a/src/main/java/world/bentobox/level/TopTen.java b/src/main/java/world/bentobox/level/TopTen.java index 5cefebd..ae17305 100644 --- a/src/main/java/world/bentobox/level/TopTen.java +++ b/src/main/java/world/bentobox/level/TopTen.java @@ -13,6 +13,7 @@ import org.bukkit.ChatColor; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.event.Listener; +import org.eclipse.jdt.annotation.NonNull; import world.bentobox.bentobox.api.panels.PanelItem; import world.bentobox.bentobox.api.panels.builders.PanelBuilder; @@ -152,6 +153,7 @@ public class TopTen implements Listener { * @param world - world * @return top ten data object */ + @NonNull public TopTenData getTopTenList(World world) { topTenList.putIfAbsent(world, new TopTenData()); return topTenList.get(world); diff --git a/src/main/java/world/bentobox/level/commands/admin/AdminTopCommand.java b/src/main/java/world/bentobox/level/commands/admin/AdminTopCommand.java index 30598e7..b04aa0e 100644 --- a/src/main/java/world/bentobox/level/commands/admin/AdminTopCommand.java +++ b/src/main/java/world/bentobox/level/commands/admin/AdminTopCommand.java @@ -16,6 +16,7 @@ public class AdminTopCommand extends CompositeCommand { public AdminTopCommand(Level levelPlugin, CompositeCommand parent) { super(parent, "top", "topten"); this.levelPlugin = levelPlugin; + new AdminTopRemoveCommand(levelPlugin, this); } @Override diff --git a/src/main/java/world/bentobox/level/commands/admin/AdminTopRemoveCommand.java b/src/main/java/world/bentobox/level/commands/admin/AdminTopRemoveCommand.java new file mode 100644 index 0000000..4778903 --- /dev/null +++ b/src/main/java/world/bentobox/level/commands/admin/AdminTopRemoveCommand.java @@ -0,0 +1,55 @@ +package world.bentobox.level.commands.admin; + +import java.util.List; + +import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.localization.TextVariables; +import world.bentobox.bentobox.api.user.User; +import world.bentobox.level.Level; + +/** + * Removes a player from the top ten + * @author tastybento + * + */ +public class AdminTopRemoveCommand extends CompositeCommand { + + private final Level addon; + private User target; + + public AdminTopRemoveCommand(Level addon, CompositeCommand parent) { + super(parent, "remove", "delete"); + this.addon = addon; + } + + @Override + public void setup() { + this.setPermission("admin.top.remove"); + this.setOnlyPlayer(false); + this.setParametersHelp("admin.top.remove.parameters"); + this.setDescription("admin.top.remove.description"); + } + + /* (non-Javadoc) + * @see world.bentobox.bentobox.api.commands.BentoBoxCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List) + */ + @Override + public boolean canExecute(User user, String label, List args) { + if (args.size() != 1) { + this.showHelp(this, user); + return false; + } + target = getPlayers().getUser(args.get(0)); + if (target == null) { + user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0)); + return false; + } + return true; + } + @Override + public boolean execute(User user, String label, List args) { + addon.getTopTen().getTopTenList(getWorld()).remove(target.getUniqueId()); + user.sendMessage("general.success"); + return true; + } +} diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml index 2d9cf43..7fc5eb9 100755 --- a/src/main/resources/locales/en-US.yml +++ b/src/main/resources/locales/en-US.yml @@ -28,6 +28,9 @@ island: gui-heading: "&6[name]: &B[rank]" island-level: "&BLevel [level]" warp-to: "&AWarping to [name]'s island" + remove: + description: "remove player from Top Ten" + parameters: "" value: description: "shows the value of any block" diff --git a/src/test/java/world/bentobox/level/commands/admin/AdminTopRemoveCommandTest.java b/src/test/java/world/bentobox/level/commands/admin/AdminTopRemoveCommandTest.java new file mode 100644 index 0000000..78b8699 --- /dev/null +++ b/src/test/java/world/bentobox/level/commands/admin/AdminTopRemoveCommandTest.java @@ -0,0 +1,188 @@ +package world.bentobox.level.commands.admin; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Collections; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; + +import world.bentobox.bentobox.BentoBox; +import world.bentobox.bentobox.api.addons.GameModeAddon; +import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.localization.TextVariables; +import world.bentobox.bentobox.api.user.User; +import world.bentobox.bentobox.database.objects.Island; +import world.bentobox.bentobox.managers.IslandWorldManager; +import world.bentobox.bentobox.managers.IslandsManager; +import world.bentobox.bentobox.managers.LocalesManager; +import world.bentobox.bentobox.managers.PlayersManager; +import world.bentobox.level.Level; +import world.bentobox.level.TopTen; +import world.bentobox.level.objects.TopTenData; + +/** + * @author tastybento + * + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest({Bukkit.class, BentoBox.class}) +public class AdminTopRemoveCommandTest { + + @Mock + private CompositeCommand ic; + private UUID uuid; + @Mock + private User user; + @Mock + private IslandsManager im; + @Mock + private Island island; + @Mock + private Level addon; + @Mock + private World world; + @Mock + private IslandWorldManager iwm; + @Mock + private GameModeAddon gameModeAddon; + @Mock + private Player p; + @Mock + private LocalesManager lm; + @Mock + private PlayersManager pm; + + private AdminTopRemoveCommand atrc; + @Mock + private TopTen tt; + @Mock + private TopTenData ttd; + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + // Set up plugin + BentoBox plugin = mock(BentoBox.class); + Whitebox.setInternalState(BentoBox.class, "instance", plugin); + User.setPlugin(plugin); + // Addon + when(ic.getAddon()).thenReturn(addon); + when(ic.getPermissionPrefix()).thenReturn("bskyblock."); + when(ic.getLabel()).thenReturn("island"); + when(ic.getTopLabel()).thenReturn("island"); + when(ic.getWorld()).thenReturn(world); + when(ic.getTopLabel()).thenReturn("bsb"); + + + // IWM friendly name + when(plugin.getIWM()).thenReturn(iwm); + when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock"); + + // World + when(world.toString()).thenReturn("world"); + when(world.getName()).thenReturn("BSkyBlock_world"); + + + // Player manager + when(plugin.getPlayers()).thenReturn(pm); + when(pm.getUser(anyString())).thenReturn(user); + // topTen + when(addon.getTopTen()).thenReturn(tt); + when(tt.getTopTenList(any())).thenReturn(ttd); + // User + uuid = UUID.randomUUID(); + when(user.getUniqueId()).thenReturn(uuid); + when(user.getTranslation(any())).thenAnswer(invocation -> invocation.getArgument(0, String.class)); + + atrc = new AdminTopRemoveCommand(addon, ic); + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception { + User.clearUsers(); + } + + /** + * Test method for {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#AdminTopRemoveCommand(world.bentobox.level.Level, world.bentobox.bentobox.api.commands.CompositeCommand)}. + */ + @Test + public void testAdminTopRemoveCommand() { + assertEquals("remove", atrc.getLabel()); + assertEquals("delete", atrc.getAliases().get(0)); + } + + /** + * Test method for {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#setup()}. + */ + @Test + public void testSetup() { + assertEquals("bskyblock.admin.top.remove", atrc.getPermission()); + assertEquals("admin.top.remove.parameters", atrc.getParameters()); + assertEquals("admin.top.remove.description", atrc.getDescription()); + assertFalse(atrc.isOnlyPlayer()); + + } + + /** + * Test method for {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testCanExecuteWrongArgs() { + assertFalse(atrc.canExecute(user, "delete", Collections.emptyList())); + verify(user).sendMessage(eq("commands.help.header"), eq(TextVariables.LABEL), eq("BSkyBlock")); + } + + /** + * Test method for {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testCanExecuteUnknown() { + when(pm.getUser(anyString())).thenReturn(null); + assertFalse(atrc.canExecute(user, "delete", Collections.singletonList("tastybento"))); + verify(user).sendMessage(eq("general.errors.unknown-player"), eq(TextVariables.NAME), eq("tastybento")); + } + + /** + * Test method for {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testCanExecuteKnown() { + assertTrue(atrc.canExecute(user, "delete", Collections.singletonList("tastybento"))); + } + + /** + * Test method for {@link world.bentobox.level.commands.admin.AdminTopRemoveCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testExecuteUserStringListOfString() { + testCanExecuteKnown(); + assertTrue(atrc.execute(user, "delete", Collections.singletonList("tastybento"))); + verify(ttd).remove(eq(uuid)); + verify(user).sendMessage(eq("general.success")); + } + +} From 255711afa4de242b7625ed2a4c8f8087ec132e7e Mon Sep 17 00:00:00 2001 From: tastybento Date: Sat, 16 Nov 2019 19:19:03 -0800 Subject: [PATCH 11/23] Fixed bugs and removed code smells. --- README.md | 6 +-- .../java/world/bentobox/level/TopTen.java | 4 +- .../level/calculators/CalcIslandLevel.java | 52 +++++++++---------- .../calculators/IslandLevelCalculator.java | 2 +- .../commands/island/IslandValueCommand.java | 2 +- .../world/bentobox/level/config/Settings.java | 11 ++-- .../level/placeholders/LevelPlaceholder.java | 4 +- .../level/requests/LevelRequestHandler.java | 2 +- .../level/requests/TopTenRequestHandler.java | 4 +- src/main/resources/locales/en-US.yml | 6 +-- .../java/world/bentobox/level/TopTenTest.java | 8 ++- .../admin/AdminTopRemoveCommandTest.java | 10 +--- .../level/objects/TopTenDataTest.java | 21 ++------ 13 files changed, 55 insertions(+), 77 deletions(-) diff --git a/README.md b/README.md index 2ff2a20..c2b75a7 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ for game modes listed in the config.yml. 1. Read the release notes carefully, but you may have to delete the old config.yml to use a new one. -## Permissons -Permissions are given automatically to players as listed below for BSkyBlock, AcidIsland and CaveBlock. If your permissions plugin strips permissions then you may have to allocate these manually. Note that if a player doesn't have the intopten permission, they will not be listed in the top ten. +## Permissions +Permissions are given automatically to players as listed below for BSkyBlock, AcidIsland and CaveBlock. If your permissions plugin strips permissions then you may have to allocate these manually. Note that if a player doesn't have the `intopten` permission, they will not be listed in the top ten. ``` permissions: @@ -61,7 +61,7 @@ This section defines a number of overall settings for the add-on. * Underwater block multiplier - default value = 1. If this value is > 1 then blocks below sea level will have a greater value. * Level cost - Value of one island level. Default 100. Minimum value is 1. -* Level wait - Cooldown between level requests in seconds +* Level wait - Cool down between level requests in seconds * Death penalty - How many block values a player will lose per death. Default value of 100 means that for every death, the player will lose 1 level (if levelcost is 100) * Sum Team Deaths - if true, all the team member deaths are summed. If false, only the leader's deaths counts. * Max deaths - If player dies more than this, it doesn't count anymore. diff --git a/src/main/java/world/bentobox/level/TopTen.java b/src/main/java/world/bentobox/level/TopTen.java index ae17305..6cc1375 100644 --- a/src/main/java/world/bentobox/level/TopTen.java +++ b/src/main/java/world/bentobox/level/TopTen.java @@ -29,11 +29,11 @@ import world.bentobox.level.objects.TopTenData; * */ public class TopTen implements Listener { - private Level addon; + private final Level addon; // Top ten list of players private Map topTenList; private final int[] SLOTS = new int[] {4, 12, 14, 19, 20, 21, 22, 23, 24, 25}; - private Database handler; + private final Database handler; public TopTen(Level addon) { this.addon = addon; diff --git a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java index 9d27c12..398f8ef 100644 --- a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java +++ b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java @@ -46,7 +46,6 @@ public class CalcIslandLevel { // Copy the limits hash map private final HashMap limitCount; private final World world; - private final List worlds; private int count; @@ -62,16 +61,6 @@ public class CalcIslandLevel { this.addon = addon; this.island = island; this.world = island.getWorld(); - this.worlds = new ArrayList<>(); - this.worlds.add(world); - if (addon.getSettings().isNether()) { - World netherWorld = addon.getPlugin().getIWM().getNetherWorld(world); - if (netherWorld != null) this.worlds.add(netherWorld); - } - if (addon.getSettings().isEnd()) { - World endWorld = addon.getPlugin().getIWM().getEndWorld(world); - if (endWorld != null) this.worlds.add(endWorld); - } this.limitCount = new HashMap<>(addon.getSettings().getBlockLimits()); this.onExit = onExit; @@ -84,18 +73,16 @@ public class CalcIslandLevel { // Get chunks to scan chunksToScan = getChunksToScan(island); count = 0; - chunksToScan.forEach(c -> { - Util.getChunkAtAsync(world, c.x, c.z).thenAccept(ch -> { - ChunkSnapshot snapShot = ch.getChunkSnapshot(); - Bukkit.getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> { - this.scanChunk(snapShot); - count++; - if (count == chunksToScan.size()) { - this.tidyUp(); - } - }); + chunksToScan.forEach(c -> Util.getChunkAtAsync(world, c.x, c.z).thenAccept(ch -> { + ChunkSnapshot snapShot = ch.getChunkSnapshot(); + Bukkit.getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> { + this.scanChunk(snapShot); + count++; + if (count == chunksToScan.size()) { + this.tidyUp(); + } }); - }); + })); } @@ -459,11 +446,22 @@ public class CalcIslandLevel { while (ch >= 'a' && ch <= 'z') nextChar(); String func = str.substring(startPos, this.pos); x = parseFactor(); - if (func.equals("sqrt")) x = Math.sqrt(x); - else if (func.equals("sin")) x = Math.sin(Math.toRadians(x)); - else if (func.equals("cos")) x = Math.cos(Math.toRadians(x)); - else if (func.equals("tan")) x = Math.tan(Math.toRadians(x)); - else throw new RuntimeException("Unknown function: " + func); + switch (func) { + case "sqrt": + x = Math.sqrt(x); + break; + case "sin": + x = Math.sin(Math.toRadians(x)); + break; + case "cos": + x = Math.cos(Math.toRadians(x)); + break; + case "tan": + x = Math.tan(Math.toRadians(x)); + break; + default: + throw new RuntimeException("Unknown function: " + func); + } } else { throw new RuntimeException("Unexpected: " + (char)ch); } diff --git a/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java b/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java index d3cde39..5293f3b 100644 --- a/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java +++ b/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java @@ -5,6 +5,6 @@ public interface IslandLevelCalculator { /** * @return the results of the island calculation */ - public Results getResult(); + Results getResult(); } diff --git a/src/main/java/world/bentobox/level/commands/island/IslandValueCommand.java b/src/main/java/world/bentobox/level/commands/island/IslandValueCommand.java index 2610a56..51b04bf 100644 --- a/src/main/java/world/bentobox/level/commands/island/IslandValueCommand.java +++ b/src/main/java/world/bentobox/level/commands/island/IslandValueCommand.java @@ -34,7 +34,7 @@ public class IslandValueCommand extends CompositeCommand { int value = plugin.getConfig().getInt("blocks." + material.toString()); user.sendMessage("island.value.success", "[value]", value + ""); if (plugin.getConfig().get("underwater") != null) { - Double underWater = plugin.getConfig().getDouble("underwater"); + double underWater = plugin.getConfig().getDouble("underwater"); if (underWater > 1.0) { user.sendMessage("island.value.success-underwater", "[value]", (underWater * value) + ""); } diff --git a/src/main/java/world/bentobox/level/config/Settings.java b/src/main/java/world/bentobox/level/config/Settings.java index bdd290e..4bd5a4c 100644 --- a/src/main/java/world/bentobox/level/config/Settings.java +++ b/src/main/java/world/bentobox/level/config/Settings.java @@ -3,6 +3,7 @@ package world.bentobox.level.config; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -13,7 +14,7 @@ import world.bentobox.level.Level; public class Settings { - private Level level; + private final Level level; private boolean sumTeamDeaths; private Map blockLimits = new HashMap<>(); private Map blockValues = new HashMap<>(); @@ -48,7 +49,7 @@ public class Settings { if (level.getConfig().isSet("limits")) { HashMap bl = new HashMap<>(); - for (String material : level.getConfig().getConfigurationSection("limits").getKeys(false)) { + for (String material : Objects.requireNonNull(level.getConfig().getConfigurationSection("limits")).getKeys(false)) { try { Material mat = Material.valueOf(material); bl.put(mat, level.getConfig().getInt("limits." + material, 0)); @@ -60,7 +61,7 @@ public class Settings { } if (level.getConfig().isSet("blocks")) { Map bv = new HashMap<>(); - for (String material : level.getConfig().getConfigurationSection("blocks").getKeys(false)) { + for (String material : Objects.requireNonNull(level.getConfig().getConfigurationSection("blocks")).getKeys(false)) { try { Material mat = Material.valueOf(material); @@ -76,11 +77,11 @@ public class Settings { // Worlds if (level.getConfig().isSet("worlds")) { ConfigurationSection worlds = level.getConfig().getConfigurationSection("worlds"); - for (String world : worlds.getKeys(false)) { + for (String world : Objects.requireNonNull(worlds).getKeys(false)) { World bWorld = Bukkit.getWorld(world); if (bWorld != null) { ConfigurationSection worldValues = worlds.getConfigurationSection(world); - for (String material : worldValues.getKeys(false)) { + for (String material : Objects.requireNonNull(worldValues).getKeys(false)) { Material mat = Material.valueOf(material); Map values = worldBlockValues.getOrDefault(bWorld, new HashMap<>()); values.put(mat, worldValues.getInt(material)); diff --git a/src/main/java/world/bentobox/level/placeholders/LevelPlaceholder.java b/src/main/java/world/bentobox/level/placeholders/LevelPlaceholder.java index 4bf27ee..bacd986 100644 --- a/src/main/java/world/bentobox/level/placeholders/LevelPlaceholder.java +++ b/src/main/java/world/bentobox/level/placeholders/LevelPlaceholder.java @@ -11,8 +11,8 @@ import world.bentobox.level.Level; */ public class LevelPlaceholder implements PlaceholderReplacer { - private Level addon; - private GameModeAddon gm; + private final Level addon; + private final GameModeAddon gm; /** * Provides placeholder support diff --git a/src/main/java/world/bentobox/level/requests/LevelRequestHandler.java b/src/main/java/world/bentobox/level/requests/LevelRequestHandler.java index 747bda0..2798e67 100644 --- a/src/main/java/world/bentobox/level/requests/LevelRequestHandler.java +++ b/src/main/java/world/bentobox/level/requests/LevelRequestHandler.java @@ -10,7 +10,7 @@ import world.bentobox.level.Level; public class LevelRequestHandler extends AddonRequestHandler { - private Level addon; + private final Level addon; public LevelRequestHandler(Level addon) { super("island-level"); diff --git a/src/main/java/world/bentobox/level/requests/TopTenRequestHandler.java b/src/main/java/world/bentobox/level/requests/TopTenRequestHandler.java index 556434c..6c92f4c 100644 --- a/src/main/java/world/bentobox/level/requests/TopTenRequestHandler.java +++ b/src/main/java/world/bentobox/level/requests/TopTenRequestHandler.java @@ -20,7 +20,7 @@ public class TopTenRequestHandler extends AddonRequestHandler { /** * The level addon field. */ - private Level addon; + private final Level addon; /** * This constructor creates a new TopTenRequestHandler instance. @@ -33,7 +33,7 @@ public class TopTenRequestHandler extends AddonRequestHandler { } /** - * @see {@link AddonRequestHandler#handle(Map)} + * See {@link AddonRequestHandler#handle(Map)} */ @Override public Object handle(Map map) { diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml index 7fc5eb9..dcae349 100755 --- a/src/main/resources/locales/en-US.yml +++ b/src/main/resources/locales/en-US.yml @@ -11,6 +11,9 @@ admin: description: "show the top ten list" unknown-world: "&cUnknown world!" display: "&f[rank]. &a[name] &7- &b[level]" + remove: + description: "remove player from Top Ten" + parameters: "" island: level: @@ -28,9 +31,6 @@ island: gui-heading: "&6[name]: &B[rank]" island-level: "&BLevel [level]" warp-to: "&AWarping to [name]'s island" - remove: - description: "remove player from Top Ten" - parameters: "" value: description: "shows the value of any block" diff --git a/src/test/java/world/bentobox/level/TopTenTest.java b/src/test/java/world/bentobox/level/TopTenTest.java index 8dd3807..d0a78d9 100644 --- a/src/test/java/world/bentobox/level/TopTenTest.java +++ b/src/test/java/world/bentobox/level/TopTenTest.java @@ -2,7 +2,6 @@ package world.bentobox.level; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; @@ -59,7 +58,6 @@ public class TopTenTest { private BentoBox plugin; @Mock private static AbstractDatabaseHandler handler; - private List topTen; @Mock private IslandsManager im; @Mock @@ -106,7 +104,7 @@ public class TopTenTest { // Fill the top ten TopTenData ttd = new TopTenData(); ttd.setUniqueId("world"); - topTen = new ArrayList<>(); + List topTen = new ArrayList<>(); for (long i = -100; i < 100; i ++) { ttd.addLevel(UUID.randomUUID(), i); topTen.add(ttd); @@ -184,7 +182,7 @@ public class TopTenTest { TopTen tt = new TopTen(addon); UUID ownerUUID = UUID.randomUUID(); tt.addEntry(world, ownerUUID, 200L); - assertTrue(tt.getTopTenList(world).getTopTen().get(ownerUUID) == 200L); + assertEquals(200L, (long) tt.getTopTenList(world).getTopTen().get(ownerUUID)); } @Test @@ -264,7 +262,7 @@ public class TopTenTest { TopTen tt = new TopTen(addon); UUID ownerUUID = UUID.randomUUID(); tt.addEntry(world, ownerUUID, 200L); - assertTrue(tt.getTopTenList(world).getTopTen().get(ownerUUID) == 200L); + assertEquals(200L, (long) tt.getTopTenList(world).getTopTen().get(ownerUUID)); // Remove it tt.removeEntry(world, ownerUUID); assertNull(tt.getTopTenList(world).getTopTen().get(ownerUUID)); diff --git a/src/test/java/world/bentobox/level/commands/admin/AdminTopRemoveCommandTest.java b/src/test/java/world/bentobox/level/commands/admin/AdminTopRemoveCommandTest.java index 78b8699..bebad5c 100644 --- a/src/test/java/world/bentobox/level/commands/admin/AdminTopRemoveCommandTest.java +++ b/src/test/java/world/bentobox/level/commands/admin/AdminTopRemoveCommandTest.java @@ -77,11 +77,8 @@ public class AdminTopRemoveCommandTest { @Mock private TopTenData ttd; - /** - * @throws java.lang.Exception - */ @Before - public void setUp() throws Exception { + public void setUp() { // Set up plugin BentoBox plugin = mock(BentoBox.class); Whitebox.setInternalState(BentoBox.class, "instance", plugin); @@ -118,11 +115,8 @@ public class AdminTopRemoveCommandTest { atrc = new AdminTopRemoveCommand(addon, ic); } - /** - * @throws java.lang.Exception - */ @After - public void tearDown() throws Exception { + public void tearDown() { User.clearUsers(); } diff --git a/src/test/java/world/bentobox/level/objects/TopTenDataTest.java b/src/test/java/world/bentobox/level/objects/TopTenDataTest.java index a0da168..e1d9cc6 100644 --- a/src/test/java/world/bentobox/level/objects/TopTenDataTest.java +++ b/src/test/java/world/bentobox/level/objects/TopTenDataTest.java @@ -7,7 +7,6 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.UUID; -import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -17,15 +16,12 @@ import org.junit.Test; */ public class TopTenDataTest { - private Map topTen = new LinkedHashMap<>(); + private final Map topTen = new LinkedHashMap<>(); private TopTenData ttd; - private UUID uuid = UUID.randomUUID(); + private final UUID uuid = UUID.randomUUID(); - /** - * @throws java.lang.Exception - */ @Before - public void setUp() throws Exception { + public void setUp() { // Create a top ten map for (long i = 0; i < 100; i++) { topTen.put(UUID.randomUUID(), i); @@ -39,13 +35,6 @@ public class TopTenDataTest { ttd = new TopTenData(); } - /** - * @throws java.lang.Exception - */ - @After - public void tearDown() throws Exception { - } - /** * Test method for {@link world.bentobox.level.objects.TopTenData#getTopTen()}. */ @@ -93,9 +82,7 @@ public class TopTenDataTest { @Test public void testAddAndGetLevel() { topTen.forEach(ttd::addLevel); - topTen.keySet().forEach(k -> { - assertTrue(topTen.get(k) == ttd.getLevel(k)); - }); + topTen.keySet().forEach(k -> assertEquals((long) topTen.get(k), ttd.getLevel(k))); } /** From 9066c8ddf2188685b3a8fd4d428449af81b882f0 Mon Sep 17 00:00:00 2001 From: "gitlocalize-app[bot]" <55277160+gitlocalize-app[bot]@users.noreply.github.com> Date: Sun, 17 Nov 2019 15:45:41 -0800 Subject: [PATCH 12/23] Translate fr.yml via GitLocalize (#100) --- src/main/resources/locales/fr.yml | 72 +++++++++++++++---------------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/src/main/resources/locales/fr.yml b/src/main/resources/locales/fr.yml index 740436c..3f906c0 100644 --- a/src/main/resources/locales/fr.yml +++ b/src/main/resources/locales/fr.yml @@ -1,41 +1,37 @@ -########################################################################################### -# This is a YML file. Be careful when editing. Check your edits in a YAML checker like # -# the one at http://yaml-online-parser.appspot.com # -########################################################################################### - +--- +admin: + level: + description: calcule le niveau d'île d'un joueur + parameters: "" + top: + description: affiche le top 10 des îles + display: "&f[rank]. &a[name] &7- &b[level]" + unknown-world: "&cMonde inconnu." + remove: + description: retire le joueur du top 10 + parameters: "" +island: + level: + calculating: "&aCalcul du niveau en cours..." + deaths: "&c([number] morts)" + description: calcule le niveau de votre île ou affiche le niveau d'un [joueur] + island-level-is: "&aLe niveau d'île est &b[level]" + parameters: "[joueur]" + required-points-to-next-level: "&a[points] points avant le prochain niveau" + cooldown: "&cVous devez attendre &b[time] &csecondes avant de pouvoir refaire + cette action" + top: + description: affiche le top 10 + gui-heading: "&6[name]: &B[rank]" + gui-title: "&aTop 10" + island-level: "&BNiveau [level]" + warp-to: "&ATéléportation vers l'île de [name]" + value: + description: affiche la valeur d'un bloc + success: "&7Valeur de ce bloc : &e[value]" + success-underwater: "&7Valeur de ce bloc en dessous du niveau de la mer : &e[value]" + empty-hand: "&cIl n'y a aucun bloc dans votre main" + no-value: "&cCet objet n'a pas de valeur." meta: authors: - plagoutte - -admin: - level: - parameters: "" - description: "calcule le niveau d'île d'un joueur" - top: - description: "affiche le top 10 des îles" - unknown-world: "&cMonde inconnu." - display: "&f[rank]. &a[name] &7- &b[level]" - -island: - level: - parameters: "[joueur]" - description: "calcule le niveau de votre île ou affiche le niveau d'un [joueur]" - calculating: "&aCalcul du niveau en cours..." - island-level-is: "&aLe niveau d'île est &b[level]" - required-points-to-next-level: "&a[points] points avant le prochain niveau" - deaths: "&c([number] morts)" - cooldown: "&cVous devez attendre &b[time] &csecondes avant de pouvoir re-faire cette action" - - top: - description: "affiche le top 10" - gui-title: "&aTop 10" - gui-heading: "&6[name]: &B[rank]" - island-level: "&BNiveau [level]" - warp-to: "&ATéléportation vers l'île de [name]" - - value: - description: "affiche la valeur d'un bloc" - success: "§7Valeur de ce bloc : §e[value]" - success-underwater: "§7Valeur de ce bloc en dessous du niveau de la mer : §e[value]" - empty-hand: "§cIl n'y a aucun bloc dans votre main" - no-value: "§cCet objet n'a pas de valeur." From 2cea8e942fe71a06494dca2cdad795a0fc6d25b9 Mon Sep 17 00:00:00 2001 From: "gitlocalize-app[bot]" <55277160+gitlocalize-app[bot]@users.noreply.github.com> Date: Sun, 17 Nov 2019 15:46:11 -0800 Subject: [PATCH 13/23] Updated German localization (#99) * Translate de.yml via GitLocalize * Translate de.yml via GitLocalize --- src/main/resources/locales/de.yml | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/main/resources/locales/de.yml diff --git a/src/main/resources/locales/de.yml b/src/main/resources/locales/de.yml new file mode 100644 index 0000000..950b8c0 --- /dev/null +++ b/src/main/resources/locales/de.yml @@ -0,0 +1,34 @@ +--- +admin: + level: + parameters: "" + description: Berechne das Insel Level für den Spieler + top: + remove: + description: entferne Spieler von Top-10 + parameters: "" + description: Zeige die Top-10 Liste + unknown-world: "&cUnbekannte Welt!" + display: "&f[rank]. &a[name] &7- &b[level]" +island: + level: + parameters: "[Spieler]" + description: Berechne dein Insel Level oder zeige das Level von [Spieler] + required-points-to-next-level: "&a[points] Punkte werden für das nächste Level + benötigt" + calculating: "&aBerechne Level..." + island-level-is: "&aInsel Level: &b[level]" + deaths: "&c([number] Tode)" + cooldown: "&cDu musst &b[time] &csekunden warten bevor du das erneut machen kannst." + value: + description: Zeige den Wert jedes Blockes + success-underwater: "&7Wert des Blockes Unterwasser: &e[value]" + success: "&7Wert: &e[value]" + empty-hand: "&cDu hast keinen Block in der Hand" + no-value: "&cDas Item hat kein wert!" + top: + description: Zeige die Top-10 + gui-title: "&aTop Zehn" + gui-heading: "&6[name]: &B[rank]" + island-level: "&BLevel [level]" + warp-to: "&ATeleportiere zu [name]'s Insel" From b3d82a6456ace184e2412a41fc1caa6ff5fbb472 Mon Sep 17 00:00:00 2001 From: tastybento Date: Tue, 19 Nov 2019 13:06:29 -0800 Subject: [PATCH 14/23] Adds back in nether and end level calcs. https://github.com/BentoBoxWorld/Level/issues/101 --- .../level/calculators/CalcIslandLevel.java | 76 +++++++++++++------ 1 file changed, 52 insertions(+), 24 deletions(-) diff --git a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java index 398f8ef..6882eb2 100644 --- a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java +++ b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java @@ -12,6 +12,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Material; import org.bukkit.Tag; @@ -45,10 +46,13 @@ public class CalcIslandLevel { // Copy the limits hash map private final HashMap limitCount; + private final List worlds; private final World world; private int count; + private int total; + /** * Calculate the island's level @@ -63,6 +67,9 @@ public class CalcIslandLevel { this.world = island.getWorld(); this.limitCount = new HashMap<>(addon.getSettings().getBlockLimits()); this.onExit = onExit; + this.worlds = new ArrayList<>(); + this.worlds.add(world); + // Results go here result = new Results(); @@ -73,17 +80,38 @@ public class CalcIslandLevel { // Get chunks to scan chunksToScan = getChunksToScan(island); count = 0; - chunksToScan.forEach(c -> Util.getChunkAtAsync(world, c.x, c.z).thenAccept(ch -> { - ChunkSnapshot snapShot = ch.getChunkSnapshot(); - Bukkit.getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> { - this.scanChunk(snapShot); - count++; - if (count == chunksToScan.size()) { - this.tidyUp(); - } - }); - })); + // Total number of chunks to scan + total = chunksToScan.size(); + // Add nether world scanning + if (addon.getSettings().isNether()) { + World netherWorld = addon.getPlugin().getIWM().getNetherWorld(world); + if (netherWorld != null) { + this.worlds.add(netherWorld); + total += chunksToScan.size(); + } + } + // Add End world scanning + if (addon.getSettings().isEnd()) { + World endWorld = addon.getPlugin().getIWM().getEndWorld(world); + if (endWorld != null) { + this.worlds.add(endWorld); + total += chunksToScan.size(); + } + } + chunksToScan.forEach(c -> worlds.forEach(w -> Util.getChunkAtAsync(w, c.x, c.z).thenAccept(this::getChunk))); + + } + + private void getChunk(Chunk ch) { + ChunkSnapshot snapShot = ch.getChunkSnapshot(); + Bukkit.getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> { + this.scanChunk(snapShot); + count++; + if (count == total) { + this.tidyUp(); + } + }); } private void scanChunk(ChunkSnapshot chunk) { @@ -447,20 +475,20 @@ public class CalcIslandLevel { String func = str.substring(startPos, this.pos); x = parseFactor(); switch (func) { - case "sqrt": - x = Math.sqrt(x); - break; - case "sin": - x = Math.sin(Math.toRadians(x)); - break; - case "cos": - x = Math.cos(Math.toRadians(x)); - break; - case "tan": - x = Math.tan(Math.toRadians(x)); - break; - default: - throw new RuntimeException("Unknown function: " + func); + case "sqrt": + x = Math.sqrt(x); + break; + case "sin": + x = Math.sin(Math.toRadians(x)); + break; + case "cos": + x = Math.cos(Math.toRadians(x)); + break; + case "tan": + x = Math.tan(Math.toRadians(x)); + break; + default: + throw new RuntimeException("Unknown function: " + func); } } else { throw new RuntimeException("Unexpected: " + (char)ch); From 7803e71a7c75b12ce022b04807d3b29fb8c054d6 Mon Sep 17 00:00:00 2001 From: tastybento Date: Tue, 19 Nov 2019 15:41:45 -0800 Subject: [PATCH 15/23] Create FUNDING.yml --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..be52336 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: tastybento From 43a8cb415359e4dca39d6ac76cbc6854bce9ac0f Mon Sep 17 00:00:00 2001 From: tastybento Date: Fri, 22 Nov 2019 20:14:47 -0800 Subject: [PATCH 16/23] Updated .gitignore --- .gitignore | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5e2fb46 --- /dev/null +++ b/.gitignore @@ -0,0 +1,87 @@ + # Git +*.orig +!.gitignore +/.settings/ + + # Windows +Thumbs.db +ehthumbs.db +ehthumbs_vista.db +*.stackdump +[Dd]esktop.ini +$RECYCLE.BIN/ +*.lnk + + # Linux +*~ +.fuse_hidden* +.directory +.Trash-* +.nfs* + + # MacOS +.DS_Store +.AppleDouble +.LSOverride +._* + + # Java +*.class +*.log +*.ctxt +.mtj.tmp/ +*.jar +*.war +*.nar +*.ear +hs_err_pid* + + # Maven +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties + + # Intellij +*.iml +*.java___jb_tmp___ +.idea/* +*.ipr +*.iws +/out/ +.idea_modules/ + + # Eclipse +*.pydevproject +.metadata +.gradle +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.project +.externalToolBuilders/ +*.launch +.cproject +.classpath +.buildpath +.target + + # NetBeans +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +nbactions.xml +nb-configuration.xml +.nb-gradle/ \ No newline at end of file From 0eb3881a56077bcf2f8069cc70923fd1baad6a80 Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 22 Nov 2019 23:21:01 -0500 Subject: [PATCH 17/23] add throttle to calculate chunks (#102) * add throttle to calculate chunks * dont think the synchronized is needed --- .../level/calculators/CalcIslandLevel.java | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java index 6882eb2..e64b31d 100644 --- a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java +++ b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java @@ -1,13 +1,6 @@ package world.bentobox.level.calculators; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -49,10 +42,11 @@ public class CalcIslandLevel { private final List worlds; private final World world; - private int count; + private AtomicInteger count; private int total; - + private Queue q; + private int queueid; /** * Calculate the island's level @@ -69,7 +63,7 @@ public class CalcIslandLevel { this.onExit = onExit; this.worlds = new ArrayList<>(); this.worlds.add(world); - + q = new LinkedList<>(); // Results go here result = new Results(); @@ -79,7 +73,7 @@ public class CalcIslandLevel { // Get chunks to scan chunksToScan = getChunksToScan(island); - count = 0; + count = new AtomicInteger(); // Total number of chunks to scan total = chunksToScan.size(); // Add nether world scanning @@ -98,17 +92,33 @@ public class CalcIslandLevel { total += chunksToScan.size(); } } - - chunksToScan.forEach(c -> worlds.forEach(w -> Util.getChunkAtAsync(w, c.x, c.z).thenAccept(this::getChunk))); + queueid = Bukkit.getScheduler().scheduleSyncRepeatingTask(addon.getPlugin(), new Runnable() { + public void run() { + for (int i = 0; i < 10; i++) { + if (q.size() == 0) { + return; + } + Chunk c = q.remove(); + getChunk(c); + } + } + }, 1L, 1L); + chunksToScan.forEach(c -> worlds.forEach(w -> Util.getChunkAtAsync(w, c.x, c.z).thenAccept(this::addChunkQueue))); } - private void getChunk(Chunk ch) { + private void addChunkQueue(Chunk ch) { + q.add(ch); + } + + private void getChunk(Chunk ch) { ChunkSnapshot snapShot = ch.getChunkSnapshot(); + Bukkit.getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> { this.scanChunk(snapShot); - count++; - if (count == total) { + count.getAndIncrement(); + if (count.get() == total) { + Bukkit.getScheduler().cancelTask(queueid); this.tidyUp(); } }); From f97a25284005e32a7b5f9513729bc067e4d317ba Mon Sep 17 00:00:00 2001 From: Florian CUNY Date: Sat, 23 Nov 2019 14:08:12 +0100 Subject: [PATCH 18/23] Removed issue templates and FUNDING: using organization's ones --- .github/FUNDING.yml | 1 - .github/ISSUE_TEMPLATE/bug_report.md | 33 ----------------------- .github/ISSUE_TEMPLATE/feature_request.md | 17 ------------ 3 files changed, 51 deletions(-) delete mode 100644 .github/FUNDING.yml delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index be52336..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -github: tastybento diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index b10469f..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve - ---- - -**Description** -A clear and concise description of what the bug is. - -**Steps to reproduce the behavior:** -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Server Information:** - -[Please complete the following information:] - - Database being used (YAML, JSON, MySQL, MongoDB): [] - - OS: [e.g. iOS] - - Java Version: [e.g. Java 8] - - BentoBox version: [e.g. 1.7.2.21] - - Addons installed? [Do '/bentobox version' and copy/paste from the console] - - Other plugins? [Do '/plugins' and copy/paste from the console] - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 066b2d9..0000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. From 8181fbc431365adefcb12636e5e9fdbca93b7c7c Mon Sep 17 00:00:00 2001 From: Florian CUNY Date: Sat, 23 Nov 2019 14:43:24 +0100 Subject: [PATCH 19/23] "Deprecated" current placeholders (their name need to be changed) and their implementation --- src/main/java/world/bentobox/level/Level.java | 2 ++ .../world/bentobox/level/placeholders/LevelPlaceholder.java | 5 +++++ .../bentobox/level/placeholders/TopTenNamePlaceholder.java | 6 +++++- .../bentobox/level/placeholders/TopTenPlaceholder.java | 6 +++++- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/java/world/bentobox/level/Level.java b/src/main/java/world/bentobox/level/Level.java index 181faf5..548263d 100644 --- a/src/main/java/world/bentobox/level/Level.java +++ b/src/main/java/world/bentobox/level/Level.java @@ -143,6 +143,8 @@ public class Level extends Addon { }); // Register placeholders if (getPlugin().getPlaceholdersManager() != null) { + // DEPRECATED PLACEHOLDERS - remove in an upcoming version + getPlugin().getPlaceholdersManager().registerPlaceholder(this, gm.getDescription().getName().toLowerCase() + "-island-level", new LevelPlaceholder(this, gm)); // Top Ten for (int i = 1; i < 11; i++) { diff --git a/src/main/java/world/bentobox/level/placeholders/LevelPlaceholder.java b/src/main/java/world/bentobox/level/placeholders/LevelPlaceholder.java index bacd986..928e20a 100644 --- a/src/main/java/world/bentobox/level/placeholders/LevelPlaceholder.java +++ b/src/main/java/world/bentobox/level/placeholders/LevelPlaceholder.java @@ -8,7 +8,9 @@ import world.bentobox.level.Level; /** * @author tastybento * + * @deprecated As of 1.9.0, for removal. */ +@Deprecated public class LevelPlaceholder implements PlaceholderReplacer { private final Level addon; @@ -29,6 +31,9 @@ public class LevelPlaceholder implements PlaceholderReplacer { */ @Override public String onReplace(User user) { + addon.logWarning("You are using a deprecated placeholder."); + addon.log("Please replace any occurrence of 'Level_" + gm.getDescription().getName().toLowerCase() + "-island-level'"); + addon.log("by 'Level_" + gm.getDescription().getName().toLowerCase() + "_island_level'"); return addon.getLevelPresenter().getLevelString(addon.getIslandLevel(gm.getOverWorld(), user.getUniqueId())); } diff --git a/src/main/java/world/bentobox/level/placeholders/TopTenNamePlaceholder.java b/src/main/java/world/bentobox/level/placeholders/TopTenNamePlaceholder.java index b0e7c67..bd613ab 100644 --- a/src/main/java/world/bentobox/level/placeholders/TopTenNamePlaceholder.java +++ b/src/main/java/world/bentobox/level/placeholders/TopTenNamePlaceholder.java @@ -10,8 +10,9 @@ import world.bentobox.level.Level; /** * @author tastybento - * + * @deprecated As of 1.9.0, for removal. */ +@Deprecated public class TopTenNamePlaceholder implements PlaceholderReplacer { private final Level level; @@ -29,6 +30,9 @@ public class TopTenNamePlaceholder implements PlaceholderReplacer { */ @Override public String onReplace(User user) { + level.logWarning("You are using a deprecated placeholder."); + level.log("Please replace any occurrence of 'Level_" + gm.getDescription().getName().toLowerCase() + "-island-top-name-#'"); + level.log("by 'Level_" + gm.getDescription().getName().toLowerCase() + "_island_top_name_#'"); Collection values = level.getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().keySet(); return values.size() < i ? "" : level.getPlayers().getName(values.stream().skip(i).findFirst().orElse(null)); } diff --git a/src/main/java/world/bentobox/level/placeholders/TopTenPlaceholder.java b/src/main/java/world/bentobox/level/placeholders/TopTenPlaceholder.java index 0da18d3..0567a41 100644 --- a/src/main/java/world/bentobox/level/placeholders/TopTenPlaceholder.java +++ b/src/main/java/world/bentobox/level/placeholders/TopTenPlaceholder.java @@ -10,8 +10,9 @@ import world.bentobox.level.Level; /** * Provides the level values to placeholders * @author tastybento - * + * @deprecated As of 1.9.0, for removal. */ +@Deprecated public class TopTenPlaceholder implements PlaceholderReplacer { private final Level level; @@ -29,6 +30,9 @@ public class TopTenPlaceholder implements PlaceholderReplacer { */ @Override public String onReplace(User user) { + level.logWarning("You are using a deprecated placeholder."); + level.log("Please replace any occurrence of 'Level_" + gm.getDescription().getName().toLowerCase() + "-island-top-value-#'"); + level.log("by 'Level_" + gm.getDescription().getName().toLowerCase() + "_island_top_value_#'"); Collection values = level.getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().values(); return values.size() < i ? "" : values.stream().skip(i).findFirst().map(String::valueOf).orElse(""); } From 801bfe6a396abe61ad1a2ba14afa7ac91b72edac Mon Sep 17 00:00:00 2001 From: Florian CUNY Date: Sat, 23 Nov 2019 14:45:21 +0100 Subject: [PATCH 20/23] New name for the level placeholder; added visited island level placeholder Implements https://github.com/BentoBoxWorld/Level/issues/103 --- src/main/java/world/bentobox/level/Level.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/world/bentobox/level/Level.java b/src/main/java/world/bentobox/level/Level.java index 548263d..dd1d086 100644 --- a/src/main/java/world/bentobox/level/Level.java +++ b/src/main/java/world/bentobox/level/Level.java @@ -26,7 +26,6 @@ import world.bentobox.level.placeholders.TopTenPlaceholder; import world.bentobox.level.requests.LevelRequestHandler; import world.bentobox.level.requests.TopTenRequestHandler; - /** * Addon to BSkyBlock/AcidIsland that enables island level scoring and top ten functionality * @author tastybento @@ -151,6 +150,21 @@ public class Level extends Addon { getPlugin().getPlaceholdersManager().registerPlaceholder(this, gm.getDescription().getName().toLowerCase() + "-island-level-top-value-" + i, new TopTenPlaceholder(this, gm, i)); getPlugin().getPlaceholdersManager().registerPlaceholder(this, gm.getDescription().getName().toLowerCase() + "-island-level-top-name-" + i, new TopTenNamePlaceholder(this, gm, i)); } + + // --------------------- + + // Island Level + getPlugin().getPlaceholdersManager().registerPlaceholder(this, + gm.getDescription().getName().toLowerCase() + "_island_level", + user -> getLevelPresenter().getLevelString(getIslandLevel(gm.getOverWorld(), user.getUniqueId()))); + + // Visited Island Level + getPlugin().getPlaceholdersManager().registerPlaceholder(this, + gm.getDescription().getName().toLowerCase() + "_visited_island_level", + user -> getPlugin().getIslands().getIslandAt(user.getLocation()) + .map(island -> getIslandLevel(gm.getOverWorld(), island.getOwner())) + .map(level -> getLevelPresenter().getLevelString(level)) + .orElse("0")); } }); From dae58b8dff14b6b0009d8b97afa052d2d77e09f2 Mon Sep 17 00:00:00 2001 From: Florian CUNY Date: Sat, 23 Nov 2019 14:55:58 +0100 Subject: [PATCH 21/23] Added the new top ten placeholders Level_[gamemode]-island-top-name-# -> Level_[gamemode]_top_name_# Level_[gamemode]-island-top-value-# -> Level_[gamemode]_top_value_# --- src/main/java/world/bentobox/level/Level.java | 21 +++++++++++++++++++ .../placeholders/TopTenNamePlaceholder.java | 2 +- .../level/placeholders/TopTenPlaceholder.java | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/main/java/world/bentobox/level/Level.java b/src/main/java/world/bentobox/level/Level.java index dd1d086..4710e11 100644 --- a/src/main/java/world/bentobox/level/Level.java +++ b/src/main/java/world/bentobox/level/Level.java @@ -1,5 +1,6 @@ package world.bentobox.level; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -165,6 +166,26 @@ public class Level extends Addon { .map(island -> getIslandLevel(gm.getOverWorld(), island.getOwner())) .map(level -> getLevelPresenter().getLevelString(level)) .orElse("0")); + + // Top Ten + for (int i = 1; i <= 10; i++) { + final int rank = i; + // Value + getPlugin().getPlaceholdersManager().registerPlaceholder(this, + gm.getDescription().getName().toLowerCase() + "_top_value_" + rank, + user -> { + Collection values = getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().values(); + return values.size() < rank ? "" : values.stream().skip(rank).findFirst().map(String::valueOf).orElse(""); + }); + + // Name + getPlugin().getPlaceholdersManager().registerPlaceholder(this, + gm.getDescription().getName().toLowerCase() + "_top_name_" + rank, + user -> { + Collection values = getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().keySet(); + return values.size() < rank ? "" : getPlayers().getName(values.stream().skip(rank).findFirst().orElse(null)); + }); + } } }); diff --git a/src/main/java/world/bentobox/level/placeholders/TopTenNamePlaceholder.java b/src/main/java/world/bentobox/level/placeholders/TopTenNamePlaceholder.java index bd613ab..3da3725 100644 --- a/src/main/java/world/bentobox/level/placeholders/TopTenNamePlaceholder.java +++ b/src/main/java/world/bentobox/level/placeholders/TopTenNamePlaceholder.java @@ -32,7 +32,7 @@ public class TopTenNamePlaceholder implements PlaceholderReplacer { public String onReplace(User user) { level.logWarning("You are using a deprecated placeholder."); level.log("Please replace any occurrence of 'Level_" + gm.getDescription().getName().toLowerCase() + "-island-top-name-#'"); - level.log("by 'Level_" + gm.getDescription().getName().toLowerCase() + "_island_top_name_#'"); + level.log("by 'Level_" + gm.getDescription().getName().toLowerCase() + "_top_name_#'"); Collection values = level.getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().keySet(); return values.size() < i ? "" : level.getPlayers().getName(values.stream().skip(i).findFirst().orElse(null)); } diff --git a/src/main/java/world/bentobox/level/placeholders/TopTenPlaceholder.java b/src/main/java/world/bentobox/level/placeholders/TopTenPlaceholder.java index 0567a41..e68a449 100644 --- a/src/main/java/world/bentobox/level/placeholders/TopTenPlaceholder.java +++ b/src/main/java/world/bentobox/level/placeholders/TopTenPlaceholder.java @@ -32,7 +32,7 @@ public class TopTenPlaceholder implements PlaceholderReplacer { public String onReplace(User user) { level.logWarning("You are using a deprecated placeholder."); level.log("Please replace any occurrence of 'Level_" + gm.getDescription().getName().toLowerCase() + "-island-top-value-#'"); - level.log("by 'Level_" + gm.getDescription().getName().toLowerCase() + "_island_top_value_#'"); + level.log("by 'Level_" + gm.getDescription().getName().toLowerCase() + "_top_value_#'"); Collection values = level.getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().values(); return values.size() < i ? "" : values.stream().skip(i).findFirst().map(String::valueOf).orElse(""); } From cc1cca1453eb390e0691ac738689c238b4c18565 Mon Sep 17 00:00:00 2001 From: Florian CUNY Date: Sat, 23 Nov 2019 15:19:56 +0100 Subject: [PATCH 22/23] Fixed the "deprecated" messages for topten placeholders --- .../bentobox/level/placeholders/TopTenNamePlaceholder.java | 2 +- .../world/bentobox/level/placeholders/TopTenPlaceholder.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/world/bentobox/level/placeholders/TopTenNamePlaceholder.java b/src/main/java/world/bentobox/level/placeholders/TopTenNamePlaceholder.java index 3da3725..3e43d47 100644 --- a/src/main/java/world/bentobox/level/placeholders/TopTenNamePlaceholder.java +++ b/src/main/java/world/bentobox/level/placeholders/TopTenNamePlaceholder.java @@ -31,7 +31,7 @@ public class TopTenNamePlaceholder implements PlaceholderReplacer { @Override public String onReplace(User user) { level.logWarning("You are using a deprecated placeholder."); - level.log("Please replace any occurrence of 'Level_" + gm.getDescription().getName().toLowerCase() + "-island-top-name-#'"); + level.log("Please replace any occurrence of 'Level_" + gm.getDescription().getName().toLowerCase() + "-island-level-top-name-#'"); level.log("by 'Level_" + gm.getDescription().getName().toLowerCase() + "_top_name_#'"); Collection values = level.getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().keySet(); return values.size() < i ? "" : level.getPlayers().getName(values.stream().skip(i).findFirst().orElse(null)); diff --git a/src/main/java/world/bentobox/level/placeholders/TopTenPlaceholder.java b/src/main/java/world/bentobox/level/placeholders/TopTenPlaceholder.java index e68a449..7fbd9b6 100644 --- a/src/main/java/world/bentobox/level/placeholders/TopTenPlaceholder.java +++ b/src/main/java/world/bentobox/level/placeholders/TopTenPlaceholder.java @@ -31,7 +31,7 @@ public class TopTenPlaceholder implements PlaceholderReplacer { @Override public String onReplace(User user) { level.logWarning("You are using a deprecated placeholder."); - level.log("Please replace any occurrence of 'Level_" + gm.getDescription().getName().toLowerCase() + "-island-top-value-#'"); + level.log("Please replace any occurrence of 'Level_" + gm.getDescription().getName().toLowerCase() + "-island-level-top-value-#'"); level.log("by 'Level_" + gm.getDescription().getName().toLowerCase() + "_top_value_#'"); Collection values = level.getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().values(); return values.size() < i ? "" : values.stream().skip(i).findFirst().map(String::valueOf).orElse(""); From 61d3fb57792a9f9309cba4b9edf32e1e1842ed90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20Marczink=C3=B3?= Date: Sun, 24 Nov 2019 22:51:07 +0100 Subject: [PATCH 23/23] Translated into Hungarian (#104) --- src/main/resources/locales/hu.yml | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/main/resources/locales/hu.yml diff --git a/src/main/resources/locales/hu.yml b/src/main/resources/locales/hu.yml new file mode 100644 index 0000000..f8131c8 --- /dev/null +++ b/src/main/resources/locales/hu.yml @@ -0,0 +1,40 @@ +########################################################################################### +# This is a YML file. Be careful when editing. Check your edits in a YAML checker like # +# the one at http://yaml-online-parser.appspot.com # +########################################################################################### + +admin: + level: + parameters: "" + description: "Egy játékos sziget szintjének kiszámítása" + top: + description: "Top Tíz lista megtekintése" + unknown-world: "&cIsmeretlen világ!" + display: "&f[rank]. &a[name] &7- &b[level]" + +island: + level: + parameters: "[player]" + description: "A saját vagy más játékos sziget szintjének kiszámítása" + calculating: "&aSziget szint kiszámítása..." + island-level-is: "&aA sziget szint: &b[level]" + required-points-to-next-level: "&a[points] pont szükséges a következő szinthez." + deaths: "&c([number] halál)" + cooldown: "&cVárnod kell &b[time] &cmásodpercet, hogy újra használhasd." + + top: + description: "Top Tíz lista megtekintése" + gui-title: "&aTop Tíz" + gui-heading: "&6[name]: &B[rank]" + island-level: "&BLevel [level]" + warp-to: "&ATeleportálás [name] szigetére." + remove: + description: "játékos törlése a Top Tízből" + parameters: "" + + value: + description: "Bármely blokk értékét mutatja" + success: "&7Ennek a blokknak az értéke: &e[value]" + success-underwater: "&7Ennek a blokknak a tengerszint alatti értéke: &e[value]" + empty-hand: "&cNincsenek blokkok a kezedben" + no-value: "&cEnnek nincs értéke."