Compare commits

...

4 Commits

Author SHA1 Message Date
tastybento 31c0cd58e6 Backport of RoseStacker support. 2021-08-15 15:51:06 -07:00
tastybento b5eff6ab91 Version 2.6.5 2021-08-15 15:36:07 -07:00
tastybento 6ddc0471cf Remove saving to database on disable.
https://github.com/BentoBoxWorld/Level/issues/229

First, the top ten tables are never actually used or loaded. They are
created in memory by loading the island levels. So there is no reason to
keep saving them.
Second, the island level data is saved every time it is changed, so
there is no need to save all of the cache on exit.
2021-08-08 10:33:09 -07:00
tastybento 1321bcf9d6 Release 2.6.4 2021-08-08 10:31:08 -07:00
5 changed files with 87 additions and 101 deletions

39
pom.xml
View File

@ -65,7 +65,7 @@
<!-- Do not change unless you want different name for local builds. -->
<build.number>-LOCAL</build.number>
<!-- This allows to change between versions. -->
<build.version>2.6.3</build.version>
<build.version>2.6.5</build.version>
</properties>
<!-- Profiles will allow to automatically change build version. -->
@ -108,30 +108,6 @@
<build.number></build.number>
</properties>
</profile>
<profile>
<id>sonar</id>
<properties>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
<sonar.organization>bentobox-world</sonar.organization>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.6.0.1398</version>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>sonar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<repositories>
@ -152,6 +128,11 @@
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
<!-- RoseStacker repo -->
<repository>
<id>rosewood-repo</id>
<url>https://repo.rosewooddev.io/repository/public/</url>
</repository>
</repositories>
<dependencies>
@ -192,6 +173,7 @@
<groupId>com.github.OmerBenGera</groupId>
<artifactId>WildStackerAPI</artifactId>
<version>b18</version>
<scope>provided</scope>
</dependency>
<!-- Static analysis -->
<!-- We are using Eclipse's annotations. If you're using IDEA, update
@ -206,7 +188,14 @@
<groupId>com.github.DeadSilenceIV</groupId>
<artifactId>AdvancedChestsAPI</artifactId>
<version>1.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>dev.rosewood</groupId>
<artifactId>rosestacker</artifactId>
<version>1.3.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>

View File

@ -50,6 +50,7 @@ public class Level extends Addon implements Listener {
private LevelsManager manager;
private boolean stackersEnabled;
private boolean advChestEnabled;
private boolean roseStackersEnabled;
@Override
public void onLoad() {
@ -112,6 +113,12 @@ public class Level extends Addon implements Listener {
advChestEnabled = false;
}
}
// Check if RoseStackers is enabled
roseStackersEnabled = Bukkit.getPluginManager().isPluginEnabled("RoseStacker");
if (roseStackersEnabled) {
log("Hooked into RoseStackers.");
}
}
/**
@ -247,11 +254,6 @@ public class Level extends Addon implements Listener {
public void onDisable() {
// Stop the pipeline
this.getPipeliner().stop();
// Save player data and the top tens
if (manager != null) {
manager.save();
}
}
private void loadBlockSettings() {
@ -396,4 +398,11 @@ public class Level extends Addon implements Listener {
});
return ld;
}
/**
* @return the roseStackersEnabled
*/
public boolean isRoseStackersEnabled() {
return roseStackersEnabled;
}
}

View File

@ -64,8 +64,6 @@ public class LevelsManager {
private final Database<IslandLevels> handler;
// A cache of island levels.
private final Map<String, IslandLevels> levelsCache;
private final Database<TopTenData> topTenHandler;
// Top ten lists
private final Map<World,TopTenData> topTenLists;
// Background
@ -79,8 +77,6 @@ public class LevelsManager {
// Set up the database handler to store and retrieve data
// Note that these are saved by the BentoBox database
handler = new Database<>(addon, IslandLevels.class);
// Top Ten handler
topTenHandler = new Database<>(addon, TopTenData.class);
// Initialize the cache
levelsCache = new HashMap<>();
// Initialize top ten lists
@ -181,8 +177,6 @@ public class LevelsManager {
}
// Save result
setIslandResults(island.getWorld(), island.getOwner(), r);
// Save top ten
addon.getManager().saveTopTen(island.getWorld());
// Save the island scan details
result.complete(r);
});
@ -418,11 +412,11 @@ public class LevelsManager {
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)));
}
void createAndCleanRankings(@NonNull World world) {
topTenLists.computeIfAbsent(world, TopTenData::new);
// Remove player from top ten if they are online and do not have the perm
topTenLists.get(world).getTopTen().keySet().removeIf(u -> !hasTopTenPerm(world, u));
topTenLists.get(world).getTopTen().keySet().removeIf(u -> !hasTopTenPerm(world, u));
}
/**
@ -441,12 +435,12 @@ public class LevelsManager {
public int getRank(@NonNull World world, UUID uuid) {
createAndCleanRankings(world);
Stream<Entry<UUID, Long>> stream = topTenLists.get(world).getTopTen().entrySet().stream()
.filter(e -> addon.getIslands().isOwner(world, e.getKey()))
.filter(l -> l.getValue() > 0)
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()));
.filter(e -> addon.getIslands().isOwner(world, e.getKey()))
.filter(l -> l.getValue() > 0)
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()));
return takeWhile(stream, x -> !x.getKey().equals(uuid)).map(Map.Entry::getKey).collect(Collectors.toList()).size() + 1;
}
/**
* Java 8's version of Java 9's takeWhile
* @param stream
@ -457,7 +451,7 @@ public class LevelsManager {
CustomSpliterator<T> customSpliterator = new CustomSpliterator<>(stream.spliterator(), predicate);
return StreamSupport.stream(customSpliterator, false);
}
/**
* Checks if player has the correct top ten perm to have their level saved
* @param world
@ -475,15 +469,14 @@ public class LevelsManager {
void loadTopTens() {
topTenLists.clear();
Bukkit.getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> {
addon.log("Generating Top Ten Tables");
addon.log("Generating rankings");
handler.loadObjects().forEach(il -> {
if (il.getLevel() > 0) {
addon.getIslands().getIslandById(il.getUniqueId()).ifPresent(i -> this.addToTopTen(i, il.getLevel()));
}
});
topTenLists.keySet().forEach(w -> {
addon.log("Loaded top ten for " + w.getName());
this.saveTopTen(w);
addon.log("Generated rankings for " + w.getName());
});
});
@ -497,27 +490,10 @@ public class LevelsManager {
public void removeEntry(World world, UUID uuid) {
if (topTenLists.containsKey(world)) {
topTenLists.get(world).getTopTen().remove(uuid);
topTenHandler.saveObjectAsync(topTenLists.get(world));
}
}
/**
* Saves all player data and the top ten
*/
public void save() {
levelsCache.values().forEach(handler::saveObjectAsync);
topTenLists.values().forEach(topTenHandler::saveObjectAsync);
}
/**
* Save the top ten for world
* @param world - world
*/
public void saveTopTen(World world) {
topTenHandler.saveObjectAsync(topTenLists.get(world));
}
/**
* Set an initial island level
* @param island - the island to set. Must have a non-null world

View File

@ -2,9 +2,12 @@ package world.bentobox.level.calculators;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@ -24,7 +27,6 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Slab;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import com.bgsoftware.wildstacker.api.WildStackerAPI;
@ -33,6 +35,7 @@ import com.google.common.collect.Multiset;
import com.google.common.collect.Multiset.Entry;
import com.google.common.collect.Multisets;
import dev.rosewood.rosestacker.api.RoseStackerAPI;
import us.lynuxcraft.deadsilenceiv.advancedchests.AdvancedChestsAPI;
import us.lynuxcraft.deadsilenceiv.advancedchests.chest.AdvancedChest;
import us.lynuxcraft.deadsilenceiv.advancedchests.chest.gui.page.ChestPage;
@ -45,6 +48,7 @@ import world.bentobox.level.Level;
public class IslandLevelCalculator {
private static final String LINE_BREAK = "==================================";
public static final long MAX_AMOUNT = 10000;
private final Map<Environment, World> worlds = new EnumMap<>(Environment.class);
/**
* Method to evaluate a mathematical equation
@ -151,6 +155,7 @@ public class IslandLevelCalculator {
private final Results results;
private long duration;
private final boolean zeroIsland;
private int seaHeight;
/**
* Constructor to get the level for an island
@ -170,6 +175,24 @@ public class IslandLevelCalculator {
this.limitCount = new HashMap<>(addon.getBlockConfig().getBlockLimits());
// Get the initial island level
results.initialLevel.set(addon.getInitialIslandLevel(island));
// Set up the worlds
worlds.put(Environment.NORMAL, Util.getWorld(island.getWorld()));
// Nether
if (addon.getSettings().isNether()) {
World nether = addon.getPlugin().getIWM().getNetherWorld(island.getWorld());
if (nether != null) {
worlds.put(Environment.NETHER, nether);
}
}
// End
if (addon.getSettings().isEnd()) {
World end = addon.getPlugin().getIWM().getEndWorld(island.getWorld());
if (end != null) {
worlds.put(Environment.THE_END, end);
}
}
// Sea Height
seaHeight = addon.getPlugin().getIWM().getSeaHeight(island.getWorld());
}
/**
@ -317,30 +340,28 @@ public class IslandLevelCalculator {
* @param z - chunk z coordinate
* @return a future chunk or future null if there is no chunk to load, e.g., there is no island nether
*/
private CompletableFuture<Chunk> getWorldChunk(@NonNull World world, Environment env, int x, int z) {
switch (env) {
case NETHER:
if (addon.getSettings().isNether()) {
World nether = addon.getPlugin().getIWM().getNetherWorld(island.getWorld());
if (nether != null) {
return Util.getChunkAtAsync(nether, x, z, true);
}
}
// There is no chunk to scan, so return a null chunk
return CompletableFuture.completedFuture(null);
case THE_END:
if (addon.getSettings().isEnd()) {
World end = addon.getPlugin().getIWM().getEndWorld(island.getWorld());
if (end != null) {
return Util.getChunkAtAsync(end, x, z, true);
}
}
// There is no chunk to scan, so return a null chunk
return CompletableFuture.completedFuture(null);
default:
return Util.getChunkAtAsync(world, x, z, true);
private CompletableFuture<Chunk> getWorldChunk(Environment env, int x, int z) {
if (worlds.containsKey(env)) {
CompletableFuture<Chunk> r2 = new CompletableFuture<>();
// Get the chunk, and then coincidentally check the RoseStacker
Util.getChunkAtAsync(worlds.get(env), x, z, true).thenAccept(chunk -> roseStackerCheck(r2, chunk));
return r2;
}
return CompletableFuture.completedFuture(null);
}
private void roseStackerCheck(CompletableFuture<Chunk> r2, Chunk chunk) {
if (addon.isRoseStackersEnabled()) {
RoseStackerAPI.getInstance().getStackedBlocks(Collections.singletonList(chunk)).forEach(e -> {
// Blocks below sea level can be scored differently
boolean belowSeaLevel = seaHeight > 0 && e.getLocation().getY() <= seaHeight;
// Check block once because the base block will be counted in the chunk snapshot
for (int _x = 0; _x < e.getStackSize() - 1; _x++) {
checkBlock(e.getBlock().getType(), belowSeaLevel);
}
});
}
r2.complete(chunk);
}
/**
@ -486,18 +507,17 @@ public class IslandLevelCalculator {
// Set up the result
CompletableFuture<Boolean> result = new CompletableFuture<>();
// Get chunks and scan
getWorldChunk(island.getWorld(), Environment.THE_END, p.x, p.z).thenAccept(endChunk ->
getWorldChunk(Environment.THE_END, p.x, p.z).thenAccept(endChunk ->
scanChunk(endChunk).thenAccept(b ->
getWorldChunk(island.getWorld(), Environment.NETHER, p.x, p.z).thenAccept(netherChunk ->
getWorldChunk(Environment.NETHER, p.x, p.z).thenAccept(netherChunk ->
scanChunk(netherChunk).thenAccept(b2 ->
getWorldChunk(island.getWorld(), Environment.NORMAL, p.x, p.z).thenAccept(normalChunk ->
getWorldChunk(Environment.NORMAL, p.x, p.z).thenAccept(normalChunk ->
scanChunk(normalChunk).thenAccept(b3 ->
// Complete the result now that all chunks have been scanned
result.complete(!chunksToCheck.isEmpty()))))
)
)
);
return result;
}

View File

@ -401,14 +401,6 @@ public class LevelsManagerTest {
assertFalse(tt.containsKey(uuid));
}
/**
* Test method for {@link world.bentobox.level.LevelsManager#save()}.
*/
@Test
public void testSave() {
lm.save();
}
/**
* Test method for {@link world.bentobox.level.LevelsManager#setInitialIslandLevel(world.bentobox.bentobox.database.objects.Island, long)}.
*/
@ -443,7 +435,7 @@ public class LevelsManagerTest {
}
*/
}
/**
* Test method for {@link world.bentobox.level.LevelsManager#getRank(World, UUID)}
*/
@ -453,7 +445,7 @@ public class LevelsManagerTest {
Map<World, TopTenData> ttl = lm.getTopTenLists();
Map<UUID, Long> tt = ttl.get(world).getTopTen();
for (long i = 100; i < 150; i++) {
tt.put(UUID.randomUUID(), i);
tt.put(UUID.randomUUID(), i);
}
// Put player as lowest rank
tt.put(uuid, 10L);