From dab0e84bc0b4235c3d009238c44a83b7fddc3f47 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sun, 26 Jul 2020 14:40:17 -0700 Subject: [PATCH] Island levels (#178) * Stores level data on a per island basis * Migrate after BentoBox worlds have loaded. * Added new Admin set initial level handicap command * Bug fixing * Fix test * Removed code smell --- pom.xml | 2 +- src/main/java/world/bentobox/level/Level.java | 18 +- .../world/bentobox/level/LevelsManager.java | 168 +++++++++++------- .../commands/AdminSetInitialLevelCommand.java | 80 +++++++++ .../level/commands/IslandLevelCommand.java | 2 +- .../listeners/IslandActivitiesListeners.java | 11 +- .../level/listeners/JoinLeaveListener.java | 2 - .../bentobox/level/objects/IslandLevels.java | 154 ++++++++++++++++ .../bentobox/level/panels/DetailsGUITab.java | 12 +- src/main/resources/locales/en-US.yml | 6 + .../java/world/bentobox/level/LevelTest.java | 4 +- .../bentobox/level/LevelsManagerTest.java | 22 ++- 12 files changed, 383 insertions(+), 98 deletions(-) create mode 100644 src/main/java/world/bentobox/level/commands/AdminSetInitialLevelCommand.java create mode 100644 src/main/java/world/bentobox/level/objects/IslandLevels.java diff --git a/pom.xml b/pom.xml index 50dabc1..65687ab 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ -LOCAL - 2.3.4 + 2.4.0 diff --git a/src/main/java/world/bentobox/level/Level.java b/src/main/java/world/bentobox/level/Level.java index 12cf20f..007eef0 100644 --- a/src/main/java/world/bentobox/level/Level.java +++ b/src/main/java/world/bentobox/level/Level.java @@ -22,6 +22,7 @@ import world.bentobox.bentobox.database.objects.Island; import world.bentobox.level.calculators.Pipeliner; import world.bentobox.level.commands.AdminLevelCommand; import world.bentobox.level.commands.AdminLevelStatusCommand; +import world.bentobox.level.commands.AdminSetInitialLevelCommand; import world.bentobox.level.commands.AdminTopCommand; import world.bentobox.level.commands.IslandLevelCommand; import world.bentobox.level.commands.IslandTopCommand; @@ -30,7 +31,6 @@ import world.bentobox.level.config.BlockConfig; import world.bentobox.level.config.ConfigSettings; import world.bentobox.level.listeners.IslandActivitiesListeners; import world.bentobox.level.listeners.JoinLeaveListener; -import world.bentobox.level.objects.LevelsData; import world.bentobox.level.requests.LevelRequestHandler; import world.bentobox.level.requests.TopTenRequestHandler; @@ -99,6 +99,9 @@ public class Level extends Addon implements Listener { @EventHandler public void onBentoBoxReady(BentoBoxReadyEvent e) { + // Perform upgrade check + manager.migrate(); + // Load TopTens manager.loadTopTens(); /* * DEBUG code to generate fake islands and then try to level them all. @@ -119,8 +122,8 @@ public class Level extends Addon implements Listener { getIslands().getIslands().stream().filter(Island::isOwned).forEach(is -> { - this.getManager().calculateLevel(is.getOwner(), is).thenAccept(r -> - log("Result for island calc " + r.getLevel() + " at " + is.getCenter())); + this.getManager().calculateLevel(is.getOwner(), is).thenAccept(r -> + log("Result for island calc " + r.getLevel() + " at " + is.getCenter())); }); }, 60L);*/ @@ -187,6 +190,7 @@ public class Level extends Addon implements Listener { new AdminLevelCommand(this, adminCommand); new AdminTopCommand(this, adminCommand); new AdminLevelStatusCommand(this, adminCommand); + new AdminSetInitialLevelCommand(this, adminCommand); }); gm.getPlayerCommand().ifPresent(playerCmd -> { new IslandLevelCommand(this, playerCmd); @@ -319,12 +323,4 @@ public class Level extends Addon implements Listener { if (island != null) getManager().calculateLevel(playerUUID, island); } - /** - * Load a player from the cache or database - * @param targetPlayer - UUID of target player - * @return LevelsData object or null if not found - */ - public LevelsData getLevelsData(UUID targetPlayer) { - return getManager().getLevelsData(targetPlayer); - } } diff --git a/src/main/java/world/bentobox/level/LevelsManager.java b/src/main/java/world/bentobox/level/LevelsManager.java index b1517a9..4df47ea 100644 --- a/src/main/java/world/bentobox/level/LevelsManager.java +++ b/src/main/java/world/bentobox/level/LevelsManager.java @@ -9,6 +9,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.TreeMap; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -21,6 +22,8 @@ import org.bukkit.World; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; +import com.google.common.collect.Maps; + import world.bentobox.bentobox.api.events.addon.AddonBaseEvent; import world.bentobox.bentobox.api.events.addon.AddonEvent; import world.bentobox.bentobox.api.panels.PanelItem; @@ -33,6 +36,7 @@ import world.bentobox.bentobox.database.objects.Island; import world.bentobox.level.calculators.Results; import world.bentobox.level.events.IslandLevelCalculatedEvent; import world.bentobox.level.events.IslandPreLevelEvent; +import world.bentobox.level.objects.IslandLevels; import world.bentobox.level.objects.LevelsData; import world.bentobox.level.objects.TopTenData; import world.bentobox.level.panels.DetailsGUITab; @@ -55,9 +59,9 @@ public class LevelsManager { // Database handler for level data - private final Database handler; + private final Database handler; // A cache of island levels. - private final Map levelsCache; + private final Map levelsCache; private final Database topTenHandler; // Top ten lists @@ -72,7 +76,7 @@ public class LevelsManager { // Get the BentoBox database // Set up the database handler to store and retrieve data // Note that these are saved by the BentoBox database - handler = new Database<>(addon, LevelsData.class); + handler = new Database<>(addon, IslandLevels.class); // Top Ten handler topTenHandler = new Database<>(addon, TopTenData.class); // Initialize the cache @@ -83,6 +87,39 @@ public class LevelsManager { background = new PanelItemBuilder().icon(Material.BLACK_STAINED_GLASS_PANE).name(" ").build(); } + public void migrate() { + Database oldDb = new Database<>(addon, LevelsData.class); + oldDb.loadObjects().forEach(ld -> { + try { + UUID owner = UUID.fromString(ld.getUniqueId()); + // Step through each world + ld.getLevels().keySet().stream() + // World + .map(Bukkit::getWorld).filter(Objects::nonNull) + // Island + .map(w -> addon.getIslands().getIsland(w, owner)).filter(Objects::nonNull) + .forEach(i -> { + // Make new database entry + World w = i.getWorld(); + IslandLevels il = new IslandLevels(i.getUniqueId()); + il.setInitialLevel(ld.getInitialLevel(w)); + il.setLevel(ld.getLevel(w)); + il.setMdCount(ld.getMdCount(w)); + il.setPointsToNextLevel(ld.getPointsToNextLevel(w)); + il.setUwCount(ld.getUwCount(w)); + // Save it + handler.saveObjectAsync(il); + }); + // Now delete the old database entry + oldDb.deleteID(ld.getUniqueId()); + } catch (Exception e) { + addon.logError("Could not migrate level data database! " + e.getMessage()); + e.printStackTrace(); + return; + } + }); + } + /** * Add a score to the top players list * @param world - world @@ -286,9 +323,7 @@ public class LevelsManager { * @return initial level of island */ public long getInitialLevel(Island island) { - @Nullable - LevelsData ld = getLevelsData(island.getOwner()); - return ld == null ? 0 : ld.getInitialLevel(island.getWorld()); + return getLevelsData(island).getInitialLevel(); } /** @@ -299,11 +334,9 @@ public class LevelsManager { */ public long getIslandLevel(@NonNull World world, @Nullable UUID targetPlayer) { if (targetPlayer == null) return 0L; - // Get the island owner - UUID owner = addon.getIslands().getOwner(world, targetPlayer); - if (owner == null) return 0L; - LevelsData ld = getLevelsData(owner); - return ld == null ? 0L : ld.getLevel(world); + // Get the island + Island island = addon.getIslands().getIsland(world, targetPlayer); + return island == null ? 0L : getLevelsData(island).getLevel(); } /** @@ -317,23 +350,30 @@ public class LevelsManager { } /** - * Load a level data for the island owner from the cache or database. Only island owners are stored. - * @param islandOwner - UUID of island owner - * @return LevelsData object or null if not found + * Load a level data for the island from the cache or database. + * @param island - UUID of island + * @return IslandLevels object */ - @Nullable - public LevelsData getLevelsData(@NonNull UUID islandOwner) { - // Get from database if not in cache - if (!levelsCache.containsKey(islandOwner) && handler.objectExists(islandOwner.toString())) { - LevelsData ld = handler.loadObject(islandOwner.toString()); - if (ld != null) { - levelsCache.put(islandOwner, ld); - } else { - handler.deleteID(islandOwner.toString()); - } + @NonNull + public IslandLevels getLevelsData(@NonNull Island island) { + String id = island.getUniqueId(); + if (levelsCache.containsKey(id)) { + return levelsCache.get(id); } - // Return cached value or null - return levelsCache.get(islandOwner); + // Get from database if not in cache + if (handler.objectExists(id)) { + IslandLevels ld = handler.loadObject(id); + if (ld != null) { + levelsCache.put(id, ld); + } else { + handler.deleteID(id); + levelsCache.put(id, new IslandLevels(id)); + } + } else { + levelsCache.put(id, new IslandLevels(id)); + } + // Return cached value + return levelsCache.get(id); } /** @@ -344,10 +384,8 @@ public class LevelsManager { */ public String getPointsToNextString(@NonNull World world, @Nullable UUID targetPlayer) { if (targetPlayer == null) return ""; - UUID owner = addon.getIslands().getOwner(world, targetPlayer); - if (owner == null) return ""; - LevelsData ld = getLevelsData(owner); - return ld == null ? "" : String.valueOf(ld.getPointsToNextLevel(world)); + Island island = addon.getIslands().getIsland(world, targetPlayer); + return island == null ? "" : String.valueOf(getLevelsData(island).getPointsToNextLevel()); } /** @@ -394,9 +432,6 @@ public class LevelsManager { // Update based on user data // Remove any non island owners tt.getTopTen().keySet().removeIf(u -> !addon.getIslands().isOwner(world, u)); - for (UUID uuid : tt.getTopTen().keySet()) { - tt.getTopTen().compute(uuid, (k,v) -> v = updateLevel(k, world)); - } } else { addon.logError("TopTen world '" + tt.getUniqueId() + "' is not known on server. You might want to delete this table. Skipping..."); } @@ -409,14 +444,6 @@ public class LevelsManager { * @param uuid - the player's uuid */ public void removeEntry(World world, UUID uuid) { - // Load the user if they haven't yet done anything to put them in the cache - this.getLevelsData(uuid); - // Remove them - if (levelsCache.containsKey(uuid)) { - levelsCache.get(uuid).remove(world); - // Save - handler.saveObjectAsync(levelsCache.get(uuid)); - } if (topTenLists.containsKey(world)) { topTenLists.get(world).getTopTen().remove(uuid); topTenHandler.saveObjectAsync(topTenLists.get(world)); @@ -441,14 +468,14 @@ public class LevelsManager { } /** - * Set an initial island level for player - * @param island - the island to set. Must have a non-null world and owner + * Set an initial island level + * @param island - the island to set. Must have a non-null world * @param lv - initial island level */ public void setInitialIslandLevel(@NonNull Island island, long lv) { - if (island.getOwner() == null || island.getWorld() == null) return; - levelsCache.computeIfAbsent(island.getOwner(), LevelsData::new).setInitialLevel(island.getWorld(), lv); - handler.saveObjectAsync(levelsCache.get(island.getOwner())); + if (island.getWorld() == null) return; + levelsCache.computeIfAbsent(island.getUniqueId(), IslandLevels::new).setInitialLevel(lv); + handler.saveObjectAsync(levelsCache.get(island.getUniqueId())); } /** @@ -458,10 +485,18 @@ public class LevelsManager { * @param lv - level */ public void setIslandLevel(@NonNull World world, @NonNull UUID targetPlayer, long lv) { - levelsCache.computeIfAbsent(targetPlayer, LevelsData::new).setLevel(world, lv); - handler.saveObjectAsync(levelsCache.get(targetPlayer)); - // Update TopTen - addToTopTen(world, targetPlayer, levelsCache.get(targetPlayer).getLevel(world)); + // Get the island + Island island = addon.getIslands().getIsland(world, targetPlayer); + if (island != null) { + String id = island.getUniqueId(); + IslandLevels il = levelsCache.computeIfAbsent(id, IslandLevels::new); + // Remove the initial level + il.setLevel(lv - il.getInitialLevel()); + handler.saveObjectAsync(levelsCache.get(id)); + // Update TopTen + addToTopTen(world, targetPlayer, levelsCache.get(id).getLevel()); + } + } /** @@ -471,26 +506,27 @@ public class LevelsManager { * @param r - results of the calculation */ private void setIslandResults(World world, @NonNull UUID owner, Results r) { - LevelsData ld = levelsCache.computeIfAbsent(owner, LevelsData::new); - ld.setLevel(world, r.getLevel()); - ld.setUwCount(world, r.getUwCount()); - ld.setMdCount(world, r.getMdCount()); - ld.setPointsToNextLevel(world, r.getPointsToNextLevel()); - levelsCache.put(owner, ld); + // Get the island + Island island = addon.getIslands().getIsland(world, owner); + if (island == null) return; + IslandLevels ld = levelsCache.computeIfAbsent(island.getUniqueId(), IslandLevels::new); + ld.setLevel(r.getLevel() - ld.getInitialLevel()); + ld.setUwCount(Maps.asMap(r.getUwCount().elementSet(), elem -> r.getUwCount().count(elem))); + ld.setMdCount(Maps.asMap(r.getMdCount().elementSet(), elem -> r.getMdCount().count(elem))); + ld.setPointsToNextLevel(r.getPointsToNextLevel()); + levelsCache.put(island.getUniqueId(), ld); handler.saveObjectAsync(ld); // Update TopTen - addToTopTen(world, owner, ld.getLevel(world)); + addToTopTen(world, owner, ld.getLevel()); } - private Long updateLevel(UUID uuid, World world) { - if (handler.objectExists(uuid.toString())) { - @Nullable - LevelsData ld = handler.loadObject(uuid.toString()); - if (ld != null) { - return ld.getLevel(world); - } - } - return 0L; + /** + * Removes island from cache when it is deleted + * @param uniqueId - id of island + */ + public void deleteIsland(String uniqueId) { + levelsCache.remove(uniqueId); + handler.deleteID(uniqueId); } } diff --git a/src/main/java/world/bentobox/level/commands/AdminSetInitialLevelCommand.java b/src/main/java/world/bentobox/level/commands/AdminSetInitialLevelCommand.java new file mode 100644 index 0000000..0c0f89b --- /dev/null +++ b/src/main/java/world/bentobox/level/commands/AdminSetInitialLevelCommand.java @@ -0,0 +1,80 @@ +package world.bentobox.level.commands; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import org.eclipse.jdt.annotation.Nullable; + +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.util.Util; +import world.bentobox.level.Level; + +public class AdminSetInitialLevelCommand extends CompositeCommand { + + private @Nullable UUID targetUUID; + private @Nullable Island island; + private Level addon; + + public AdminSetInitialLevelCommand(Level addon, CompositeCommand parent) { + super(parent, "sethandicap"); + this.addon = addon; + } + + @Override + public void setup() { + this.setPermission("admin.level.sethandicap"); + this.setOnlyPlayer(false); + this.setParametersHelp("admin.level.sethandicap.parameters"); + this.setDescription("admin.level.sethandicap.description"); + } + + @Override + public Optional> tabComplete(User user, String alias, List args) { + String lastArg = !args.isEmpty() ? args.get(args.size()-1) : ""; + if (args.isEmpty()) { + // Don't show every player on the server. Require at least the first letter + return Optional.empty(); + } + List options = new ArrayList<>(Util.getOnlinePlayerList(user)); + return Optional.of(Util.tabLimit(options, lastArg)); + } + + @Override + public boolean execute(User user, String label, List args) { + String initialLevel = String.valueOf(addon.getManager().getInitialLevel(island)); + long lv = Long.parseLong(args.get(1)); + addon.getManager().setInitialIslandLevel(island, lv); + user.sendMessage("admin.level.sethandicap.changed", TextVariables.NUMBER, initialLevel, "[new_number]", String.valueOf(lv)); + return true; + } + + @Override + public boolean canExecute(User user, String label, List args) { + if (args.size() != 2) { + showHelp(this, user); + return false; + } + targetUUID = getAddon().getPlayers().getUUID(args.get(0)); + if (targetUUID == null) { + user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0)); + return false; + } + // Check value + if (!Util.isInteger(args.get(1), true)) { + user.sendMessage("admin.level.sethandicap.invalid-level"); + return false; + } + // Check island + island = getAddon().getIslands().getIsland(getWorld(), targetUUID); + if (island == null) { + user.sendMessage("general.errors.player-has-no-island"); + return false; + } + return true; + } +} diff --git a/src/main/java/world/bentobox/level/commands/IslandLevelCommand.java b/src/main/java/world/bentobox/level/commands/IslandLevelCommand.java index e616b4b..7642453 100644 --- a/src/main/java/world/bentobox/level/commands/IslandLevelCommand.java +++ b/src/main/java/world/bentobox/level/commands/IslandLevelCommand.java @@ -38,7 +38,7 @@ public class IslandLevelCommand extends CompositeCommand { final UUID playerUUID = getPlugin().getPlayers().getUUID(args.get(0)); if (playerUUID == null) { user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0)); - return true; + return false; } // Ops, console and admin perms can request and calculate other player levels if (!user.isPlayer() || user.isOp() || user.hasPermission(this.getPermissionPrefix() + "admin.level")) { diff --git a/src/main/java/world/bentobox/level/listeners/IslandActivitiesListeners.java b/src/main/java/world/bentobox/level/listeners/IslandActivitiesListeners.java index e68e91f..bc7792b 100644 --- a/src/main/java/world/bentobox/level/listeners/IslandActivitiesListeners.java +++ b/src/main/java/world/bentobox/level/listeners/IslandActivitiesListeners.java @@ -8,6 +8,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import world.bentobox.bentobox.api.events.island.IslandEvent.IslandCreatedEvent; +import world.bentobox.bentobox.api.events.island.IslandEvent.IslandDeleteEvent; import world.bentobox.bentobox.api.events.island.IslandEvent.IslandPreclearEvent; import world.bentobox.bentobox.api.events.island.IslandEvent.IslandRegisteredEvent; import world.bentobox.bentobox.api.events.island.IslandEvent.IslandResettedEvent; @@ -65,6 +66,12 @@ public class IslandActivitiesListeners implements Listener { remove(world, uuid); } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onIslandDeleted(IslandDeleteEvent e) { + // Remove island + addon.getManager().deleteIsland(e.getIsland().getUniqueId()); + } + private void remove(World world, UUID uuid) { if (uuid != null && world != null) { addon.getManager().removeEntry(world, uuid); @@ -88,14 +95,14 @@ public class IslandActivitiesListeners implements Listener { @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onIsland(IslandUnregisteredEvent e) { - // Remove player from the top ten and level + // Remove player from the top ten remove(e.getIsland().getWorld(), e.getPlayerUUID()); } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onIsland(IslandRegisteredEvent e) { - // Remove player from the top ten and level + // Remove player from the top ten remove(e.getIsland().getWorld(), e.getPlayerUUID()); } diff --git a/src/main/java/world/bentobox/level/listeners/JoinLeaveListener.java b/src/main/java/world/bentobox/level/listeners/JoinLeaveListener.java index 37f9776..7db49dc 100644 --- a/src/main/java/world/bentobox/level/listeners/JoinLeaveListener.java +++ b/src/main/java/world/bentobox/level/listeners/JoinLeaveListener.java @@ -27,8 +27,6 @@ public class JoinLeaveListener implements Listener { @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onPlayerJoin(PlayerJoinEvent e) { - // Load player into cache - addon.getManager().getLevelsData(e.getPlayer().getUniqueId()); // If level calc on login is enabled, run through all the worlds and calculate the level if (addon.getSettings().isCalcOnLogin()) { addon.getPlugin().getAddonsManager().getGameModeAddons().stream() diff --git a/src/main/java/world/bentobox/level/objects/IslandLevels.java b/src/main/java/world/bentobox/level/objects/IslandLevels.java new file mode 100644 index 0000000..3aa5ce2 --- /dev/null +++ b/src/main/java/world/bentobox/level/objects/IslandLevels.java @@ -0,0 +1,154 @@ +package world.bentobox.level.objects; + +import java.util.EnumMap; +import java.util.Map; + +import org.bukkit.Material; + +import com.google.gson.annotations.Expose; + +import world.bentobox.bentobox.database.objects.DataObject; +import world.bentobox.bentobox.database.objects.Table; + +/** + * Stores the levels data of the island. + * A note - if this class is extended to support new exposed fields and legacy data doesn't include those fields + * they will be set to null by GSON. They will not be initialized and if any attempt is made to use them, then + * the JVM will give up WITHOUT AN ERROR!!! That is why there are null checks throughout this class. + * + * @author tastybento + * + */ +@Table(name = "IslandLevels") +public class IslandLevels implements DataObject { + + // uniqueId is the island's UUID + @Expose + private String uniqueId = ""; + + /** + * Island level + */ + @Expose + private long level; + /** + * Initial level + */ + @Expose + private long initialLevel; + /** + * Points to next level + */ + @Expose + private long pointsToNextLevel; + + /** + * Underwater count + */ + @Expose + private Map uwCount; + + /** + * MaterialData count - count of all blocks + */ + @Expose + private Map mdCount; + + /** + * Constructor for new island + * @param islandUUID - island UUID + */ + public IslandLevels(String islandUUID) { + uniqueId = islandUUID; + uwCount = new EnumMap<>(Material.class); + mdCount = new EnumMap<>(Material.class); + } + + /** + * @return the uniqueId + */ + @Override + public String getUniqueId() { + return uniqueId; + } + + /** + * @param uniqueId the uniqueId to set + */ + @Override + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + /** + * @return the level + */ + public long getLevel() { + return level; + } + + /** + * @param level the level to set + */ + public void setLevel(long level) { + this.level = level; + } + + /** + * @return the initialLevel + */ + public long getInitialLevel() { + return initialLevel; + } + + /** + * @param initialLevel the initialLevel to set + */ + public void setInitialLevel(long initialLevel) { + this.initialLevel = initialLevel; + } + + /** + * @return the pointsToNextLevel + */ + public long getPointsToNextLevel() { + return pointsToNextLevel; + } + + /** + * @param pointsToNextLevel the pointsToNextLevel to set + */ + public void setPointsToNextLevel(long pointsToNextLevel) { + this.pointsToNextLevel = pointsToNextLevel; + } + + /** + * @return the uwCount + */ + public Map getUwCount() { + return uwCount; + } + + /** + * @param uwCount the uwCount to set + */ + public void setUwCount(Map uwCount) { + this.uwCount = uwCount; + } + + /** + * @return the mdCount + */ + public Map getMdCount() { + return mdCount; + } + + /** + * @param mdCount the mdCount to set + */ + public void setMdCount(Map mdCount) { + this.mdCount = mdCount; + } + + +} diff --git a/src/main/java/world/bentobox/level/panels/DetailsGUITab.java b/src/main/java/world/bentobox/level/panels/DetailsGUITab.java index 000cdd4..823a4df 100644 --- a/src/main/java/world/bentobox/level/panels/DetailsGUITab.java +++ b/src/main/java/world/bentobox/level/panels/DetailsGUITab.java @@ -27,7 +27,7 @@ import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.util.Util; import world.bentobox.level.Level; -import world.bentobox.level.objects.LevelsData; +import world.bentobox.level.objects.IslandLevels; /** * @author tastybento @@ -131,20 +131,20 @@ public class DetailsGUITab implements Tab, ClickHandler { private void generateReport(DetailsType type) { items = new ArrayList<>(); - LevelsData ld = addon.getManager().getLevelsData(island.getOwner()); + IslandLevels ld = addon.getManager().getLevelsData(island); // Get the items from the report Map sumTotal = new EnumMap<>(Material.class); - sumTotal.putAll(ld.getMdCount(world)); - sumTotal.putAll(ld.getUwCount(world)); + sumTotal.putAll(ld.getMdCount()); + sumTotal.putAll(ld.getUwCount()); switch(type) { case ABOVE_SEA_LEVEL_BLOCKS: - ld.getMdCount(world).forEach(this::createItem); + ld.getMdCount().forEach(this::createItem); break; case SPAWNERS: sumTotal.entrySet().stream().filter(m -> m.getKey().equals(Material.SPAWNER)).forEach(e -> createItem(e.getKey(), e.getValue())); break; case UNDERWATER_BLOCKS: - ld.getUwCount(world).forEach(this::createItem); + ld.getUwCount().forEach(this::createItem); break; default: sumTotal.forEach(this::createItem); diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml index b9e4f99..d9e99a1 100755 --- a/src/main/resources/locales/en-US.yml +++ b/src/main/resources/locales/en-US.yml @@ -7,6 +7,11 @@ admin: level: parameters: "" description: "calculate the island level for player" + sethandicap: + parameters: + description: "set the island handicap, usually the level of the starter island" + changed: "&a Initial island handicap changed from [number] to [new_number]." + invalid-level: "&c Invalid handicap. Use an integer." levelstatus: description: "show how many islands are in the queue for scanning" islands-in-queue: "&a Islands in queue: [number]" @@ -18,6 +23,7 @@ admin: description: "remove player from Top Ten" parameters: "" + island: level: parameters: "[player]" diff --git a/src/test/java/world/bentobox/level/LevelTest.java b/src/test/java/world/bentobox/level/LevelTest.java index eab9009..c94d10c 100644 --- a/src/test/java/world/bentobox/level/LevelTest.java +++ b/src/test/java/world/bentobox/level/LevelTest.java @@ -275,8 +275,8 @@ public class LevelTest { addon.onEnable(); verify(plugin).logWarning("[Level] Level Addon: No such world in blockconfig.yml : acidisland_world"); verify(plugin).log("[Level] Level hooking into BSkyBlock"); - verify(cmd, times(3)).getAddon(); // Three commands - verify(adminCmd, times(3)).getAddon(); // Three commands + verify(cmd, times(3)).getAddon(); // 3 commands + verify(adminCmd, times(4)).getAddon(); // Four commands // Placeholders verify(phm).registerPlaceholder(eq(addon), eq("bskyblock_island_level"), any()); verify(phm).registerPlaceholder(eq(addon), eq("bskyblock_visited_island_level"), any()); diff --git a/src/test/java/world/bentobox/level/LevelsManagerTest.java b/src/test/java/world/bentobox/level/LevelsManagerTest.java index 307e348..fc3aa9c 100644 --- a/src/test/java/world/bentobox/level/LevelsManagerTest.java +++ b/src/test/java/world/bentobox/level/LevelsManagerTest.java @@ -16,6 +16,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; @@ -58,7 +59,7 @@ import world.bentobox.bentobox.managers.PlayersManager; import world.bentobox.level.calculators.Pipeliner; import world.bentobox.level.calculators.Results; import world.bentobox.level.config.ConfigSettings; -import world.bentobox.level.objects.LevelsData; +import world.bentobox.level.objects.IslandLevels; import world.bentobox.level.objects.TopTenData; /** @@ -104,7 +105,7 @@ public class LevelsManagerTest { @Mock private PluginManager pim; @Mock - private LevelsData levelsData; + private IslandLevels levelsData; @Mock private IslandsManager im; @@ -125,6 +126,7 @@ public class LevelsManagerTest { /** * @throws java.lang.Exception */ + @SuppressWarnings("unchecked") @Before public void setUp() throws Exception { when(addon.getPlugin()).thenReturn(plugin); @@ -154,9 +156,11 @@ public class LevelsManagerTest { when(island.getMemberSet()).thenReturn(iset); when(island.getOwner()).thenReturn(uuid); when(island.getWorld()).thenReturn(world); + when(island.getUniqueId()).thenReturn(UUID.randomUUID().toString()); // Default to uuid's being island owners when(im.isOwner(eq(world), any())).thenReturn(true); when(im.getOwner(any(), any(UUID.class))).thenAnswer(in -> in.getArgument(1, UUID.class)); + when(im.getIsland(eq(world), eq(uuid))).thenReturn(island); // Player when(player.getUniqueId()).thenReturn(uuid); @@ -205,9 +209,10 @@ public class LevelsManagerTest { // Include a known UUID ttd.getTopTen().put(uuid, 456789L); topTen.add(ttd); - when(handler.loadObjects()).thenReturn(topTen); + // Supply no island levels first, then topTen + when(handler.loadObjects()).thenReturn(Collections.emptyList(), topTen); when(handler.objectExists(anyString())).thenReturn(true); - when(levelsData.getLevel(any())).thenReturn(-5L, -4L, -3L, -2L, -1L, 0L, 1L, 2L, 3L, 4L, 5L, 45678L); + when(levelsData.getLevel()).thenReturn(-5L, -4L, -3L, -2L, -1L, 0L, 1L, 2L, 3L, 4L, 5L, 45678L); when(levelsData.getUniqueId()).thenReturn(uuid.toString()); when(handler.loadObject(anyString())).thenReturn(levelsData ); @@ -220,6 +225,7 @@ public class LevelsManagerTest { when(iwm.getPermissionPrefix(any())).thenReturn("bskyblock."); lm = new LevelsManager(addon); + lm.migrate(); } /** @@ -252,7 +258,7 @@ public class LevelsManagerTest { lm.calculateLevel(uuid, island); cf.complete(results); - assertEquals(Long.valueOf(10000), lm.getLevelsData(uuid).getLevel(world)); + assertEquals(10000L, lm.getLevelsData(island).getLevel()); //Map tt = lm.getTopTen(world, 10); //assertEquals(1, tt.size()); //assertTrue(tt.get(uuid) == 10000); @@ -280,7 +286,9 @@ public class LevelsManagerTest { */ @Test public void testGetPointsToNextString() { - assertEquals("0", lm.getPointsToNextString(world, UUID.randomUUID())); + // No island player + assertEquals("", lm.getPointsToNextString(world, UUID.randomUUID())); + // Player has island assertEquals("0", lm.getPointsToNextString(world, uuid)); } @@ -297,7 +305,7 @@ public class LevelsManagerTest { */ @Test public void testGetLevelsData() { - assertEquals(levelsData, lm.getLevelsData(uuid)); + assertEquals(levelsData, lm.getLevelsData(island)); }