diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d3087e4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,277 @@ +Eclipse Public License - v 2.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION + OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + + a) in the case of the initial Contributor, the initial content + Distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + where such changes and/or additions to the Program originate from + and are Distributed by that particular Contributor. A Contribution + "originates" from a Contributor if it was added to the Program by + such Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include changes or additions to the Program that + are not Modified Works. + +"Contributor" means any person or entity that Distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which +are necessarily infringed by the use or sale of its Contribution alone +or when combined with the Program. + +"Program" means the Contributions Distributed in accordance with this +Agreement. + +"Recipient" means anyone who receives the Program under this Agreement +or any Secondary License (as applicable), including Contributors. + +"Derivative Works" shall mean any work, whether in Source Code or other +form, that is based on (or derived from) the Program and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. + +"Modified Works" shall mean any work in Source Code or other form that +results from an addition to, deletion from, or modification of the +contents of the Program, including, for purposes of clarity any new file +in Source Code form that contains any contents of the Program. Modified +Works shall not include works that contain only declarations, +interfaces, types, classes, structures, or files of the Program solely +in each case in order to link to, bind by name, or subclass the Program +or Modified Works thereof. + +"Distribute" means the acts of a) distributing or b) making available +in any manner that enables the transfer of a copy. + +"Source Code" means the form of a Program preferred for making +modifications, including but not limited to software source code, +documentation source, and configuration files. + +"Secondary License" means either the GNU General Public License, +Version 2.0, or any later versions of that license, including any +exceptions or additional permissions as identified by the initial +Contributor. + +2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare Derivative Works of, publicly display, + publicly perform, Distribute and sublicense the Contribution of such + Contributor, if any, and such Derivative Works. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, + if any, in Source Code or other form. This patent license shall + apply to the combination of the Contribution and the Program if, at + the time the Contribution is added by the Contributor, such addition + of the Contribution causes such combination to be covered by the + Licensed Patents. The patent license shall not apply to any other + combinations which include the Contribution. No hardware per se is + licensed hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. + Each Contributor disclaims any liability to Recipient for claims + brought by any other entity based on infringement of intellectual + property rights or otherwise. As a condition to exercising the + rights and licenses granted hereunder, each Recipient hereby + assumes sole responsibility to secure any other intellectual + property rights needed, if any. For example, if a third party + patent license is required to allow Recipient to Distribute the + Program, it is Recipient's responsibility to acquire that license + before distributing the Program. + + d) Each Contributor represents that to its knowledge it has + sufficient copyright rights in its Contribution, if any, to grant + the copyright license set forth in this Agreement. + + e) Notwithstanding the terms of any Secondary License, no + Contributor makes additional grants to any Recipient (other than + those set forth in this Agreement) as a result of such Recipient's + receipt of the Program under the terms of a Secondary License + (if permitted under the terms of Section 3). + +3. REQUIREMENTS + +3.1 If a Contributor Distributes the Program in any form, then: + + a) the Program must also be made available as Source Code, in + accordance with section 3.2, and the Contributor must accompany + the Program with a statement that the Source Code for the Program + is available under this Agreement, and informs Recipients how to + obtain it in a reasonable manner on or through a medium customarily + used for software exchange; and + + b) the Contributor may Distribute the Program under a license + different than this Agreement, provided that such license: + i) effectively disclaims on behalf of all other Contributors all + warranties and conditions, express and implied, including + warranties or conditions of title and non-infringement, and + implied warranties or conditions of merchantability and fitness + for a particular purpose; + + ii) effectively excludes on behalf of all other Contributors all + liability for damages, including direct, indirect, special, + incidental and consequential damages, such as lost profits; + + iii) does not attempt to limit or alter the recipients' rights + in the Source Code under section 3.2; and + + iv) requires any subsequent distribution of the Program by any + party to be under a license that satisfies the requirements + of this section 3. + +3.2 When the Program is Distributed as Source Code: + + a) it must be made available under this Agreement, or if the + Program (i) is combined with other material in a separate file or + files made available under a Secondary License, and (ii) the initial + Contributor attached to the Source Code the notice described in + Exhibit A of this Agreement, then the Program may be made available + under the terms of such Secondary Licenses, and + + b) a copy of this Agreement must be included with each copy of + the Program. + +3.3 Contributors may not remove or alter any copyright, patent, +trademark, attribution notices, disclaimers of warranty, or limitations +of liability ("notices") contained within the Program from any copy of +the Program which they Distribute, provided that Contributors may add +their own appropriate notices. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities +with respect to end users, business partners and the like. While this +license is intended to facilitate the commercial use of the Program, +the Contributor who includes the Program in a commercial product +offering should do so in a manner which does not create potential +liability for other Contributors. Therefore, if a Contributor includes +the Program in a commercial product offering, such Contributor +("Commercial Contributor") hereby agrees to defend and indemnify every +other Contributor ("Indemnified Contributor") against any losses, +damages and costs (collectively "Losses") arising from claims, lawsuits +and other legal actions brought by a third party against the Indemnified +Contributor to the extent caused by the acts or omissions of such +Commercial Contributor in connection with its distribution of the Program +in a commercial product offering. The obligations in this section do not +apply to any claims or Losses relating to any actual or alleged +intellectual property infringement. In order to qualify, an Indemnified +Contributor must: a) promptly notify the Commercial Contributor in +writing of such claim, and b) allow the Commercial Contributor to control, +and cooperate with the Commercial Contributor in, the defense and any +related settlement negotiations. The Indemnified Contributor may +participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial +product offering, Product X. That Contributor is then a Commercial +Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Contributor's responsibility +alone. Under this section, the Commercial Contributor would have to +defend claims against the other Contributors related to those performance +claims and warranties, and if a court requires any other Contributor to +pay any damages as a result, the Commercial Contributor must pay +those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" +BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR +IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF +TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR +PURPOSE. Each Recipient is solely responsible for determining the +appropriateness of using and distributing the Program and assumes all +risks associated with its exercise of rights under this Agreement, +including but not limited to the risks and costs of program errors, +compliance with applicable laws, damage to or loss of data, programs +or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS +SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST +PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE +EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further +action by the parties hereto, such provision shall be reformed to the +minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other software +or hardware) infringes such Recipient's patent(s), then such Recipient's +rights granted under Section 2(b) shall terminate as of the date such +litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it +fails to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of +time after becoming aware of such noncompliance. If all Recipient's +rights under this Agreement terminate, Recipient agrees to cease use +and distribution of the Program as soon as reasonably practicable. +However, Recipient's obligations under this Agreement and any licenses +granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, +but in order to avoid inconsistency the Agreement is copyrighted and +may only be modified in the following manner. The Agreement Steward +reserves the right to publish new versions (including revisions) of +this Agreement from time to time. No one other than the Agreement +Steward has the right to modify this Agreement. The Eclipse Foundation +is the initial Agreement Steward. The Eclipse Foundation may assign the +responsibility to serve as the Agreement Steward to a suitable separate +entity. Each new version of the Agreement will be given a distinguishing +version number. The Program (including Contributions) may always be +Distributed subject to the version of the Agreement under which it was +received. In addition, after a new version of the Agreement is published, +Contributor may elect to Distribute the Program (including its +Contributions) under the new version. + +Except as expressly stated in Sections 2(a) and 2(b) above, Recipient +receives no rights or licenses to the intellectual property of any +Contributor under this Agreement, whether expressly, by implication, +estoppel or otherwise. All rights in the Program not expressly granted +under this Agreement are reserved. Nothing in this Agreement is intended +to be enforceable by any entity that is not a Contributor or Recipient. +No third-party beneficiary rights are created under this Agreement. + +Exhibit A - Form of Secondary Licenses Notice + +"This Source Code may also be made available under the following +Secondary Licenses when the conditions for such availability set forth +in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), +version(s), and exceptions or additional permissions here}." + + Simply including a copy of this Agreement, including this Exhibit A + is not sufficient to license the Source Code under Secondary Licenses. + + If it is not possible or desirable to put the notice in a particular + file, then You may include the notice in a location (such as a LICENSE + file in a relevant directory) where a recipient would be likely to + look for such a notice. + + You may add additional accurate notices of copyright ownership. diff --git a/pom.xml b/pom.xml index 091de22..2417dc5 100644 --- a/pom.xml +++ b/pom.xml @@ -5,8 +5,8 @@ 4.0.0 world.bentobox - Level - 0.2.0 + level + 1.2.2-SNAPSHOT Level Level is an add-on for BentoBox, an expandable Minecraft Bukkit plugin for island-type games like SkyBlock or AcidIsland. @@ -86,7 +86,7 @@ world.bentobox bentobox - 0.18.0-SNAPSHOT + 1.3.0-SNAPSHOT provided @@ -214,6 +214,7 @@ https://sonarcloud.io bentobox-world + BentoBoxWorld_Level diff --git a/src/main/java/world/bentobox/level/Level.java b/src/main/java/world/bentobox/level/Level.java index b8e3240..074e44e 100644 --- a/src/main/java/world/bentobox/level/Level.java +++ b/src/main/java/world/bentobox/level/Level.java @@ -6,19 +6,21 @@ import java.util.UUID; import org.bukkit.World; +import world.bentobox.bentobox.api.addons.Addon; +import world.bentobox.bentobox.api.user.User; +import world.bentobox.bentobox.database.Database; +import world.bentobox.bentobox.database.objects.Island; import world.bentobox.level.commands.admin.AdminLevelCommand; import world.bentobox.level.commands.admin.AdminTopCommand; import world.bentobox.level.commands.island.IslandLevelCommand; import world.bentobox.level.commands.island.IslandTopCommand; import world.bentobox.level.config.Settings; -import world.bentobox.level.objects.LevelsData; +import world.bentobox.level.listeners.IslandTeamListeners; import world.bentobox.level.listeners.JoinLeaveListener; -import world.bentobox.level.listeners.NewIslandListener; -import world.bentobox.bentobox.api.addons.Addon; -import world.bentobox.bentobox.api.commands.CompositeCommand; -import world.bentobox.bentobox.api.user.User; -import world.bentobox.bentobox.database.Database; -import world.bentobox.bentobox.database.objects.Island; +import world.bentobox.level.objects.LevelsData; +import world.bentobox.level.placeholders.LevelPlaceholder; +import world.bentobox.level.placeholders.TopTenNamePlaceholder; +import world.bentobox.level.placeholders.TopTenPlaceholder; import world.bentobox.level.requests.LevelRequestHandler; /** @@ -114,39 +116,38 @@ public class Level extends Addon { // Start the top ten and register it for clicks topTen = new TopTen(this); registerListener(topTen); - // Register commands - // AcidIsland hook in - this.getPlugin().getAddonsManager().getAddonByName("AcidIsland").ifPresent(a -> { - CompositeCommand acidIslandCmd = getPlugin().getCommandsManager().getCommand(getConfig().getString("acidisland.user-command","ai")); - if (acidIslandCmd != null) { - new IslandLevelCommand(this, acidIslandCmd); - new IslandTopCommand(this, acidIslandCmd); - CompositeCommand acidCmd = getPlugin().getCommandsManager().getCommand(getConfig().getString("acidisland.admin-command","acid")); - new AdminLevelCommand(this, acidCmd); - new AdminTopCommand(this, acidCmd); - } - }); - // BSkyBlock hook in - this.getPlugin().getAddonsManager().getAddonByName("BSkyBlock").ifPresent(a -> { - CompositeCommand bsbIslandCmd = getPlugin().getCommandsManager().getCommand(getConfig().getString("bskyblock.user-command","island")); - if (bsbIslandCmd != null) { - new IslandLevelCommand(this, bsbIslandCmd); - new IslandTopCommand(this, bsbIslandCmd); - CompositeCommand bsbAdminCmd = getPlugin().getCommandsManager().getCommand(getConfig().getString("bskyblock.admin-command","bsbadmin")); - new AdminLevelCommand(this, bsbAdminCmd); - new AdminTopCommand(this, bsbAdminCmd); + // Register commands for AcidIsland and BSkyBlock + getPlugin().getAddonsManager().getGameModeAddons().stream() + .filter(gm -> settings.getGameModes().contains(gm.getDescription().getName())) + .forEach(gm -> { + log("Level hooking into " + gm.getDescription().getName()); + gm.getAdminCommand().ifPresent(adminCommand -> { + new AdminLevelCommand(this, adminCommand); + new AdminTopCommand(this, adminCommand); + }); + gm.getPlayerCommand().ifPresent(playerCmd -> { + new IslandLevelCommand(this, playerCmd); + new IslandTopCommand(this, playerCmd); + }); + // Register placeholders + if (getPlugin().getPlaceholdersManager() != null) { + getPlugin().getPlaceholdersManager().registerPlaceholder(this, gm.getDescription().getName().toLowerCase() + "-island-level", new LevelPlaceholder(this, gm)); + // Top Ten + for (int i = 1; i < 11; i++) { + 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)); + } } }); // Register new island listener - registerListener(new NewIslandListener(this)); + registerListener(new IslandTeamListeners(this)); registerListener(new JoinLeaveListener(this)); // Register request handlers registerRequestHandler(new LevelRequestHandler(this)); // Done - } /** @@ -164,6 +165,10 @@ public class Level extends Addon { * @param level - level */ public void setIslandLevel(World world, UUID targetPlayer, long level) { + if (world == null || targetPlayer == null) { + this.logError("Level: request to store a null " + world + " " + targetPlayer); + return; + } LevelsData ld = getLevelsData(targetPlayer); if (ld == null) { ld = new LevelsData(targetPlayer, level, world); @@ -173,25 +178,38 @@ public class Level extends Addon { // Add to cache levelsCache.put(targetPlayer, ld); topTen.addEntry(world, targetPlayer, getIslandLevel(world, targetPlayer)); + handler.saveObject(ld); } /** - * Sets the initial island level + * Zeros the initial island level * @param island - island * @param level - initial calculated island level */ public void setInitialIslandLevel(Island island, long level) { - setIslandLevel(island.getWorld(), island.getOwner(), level); - levelsCache.get(island.getOwner()).setInitialIslandLevel(level); + if (island.getWorld() == null || island.getOwner() == null) { + this.logError("Level: request to store a null (initial) " + island.getWorld() + " " + island.getOwner()); + return; + } + setIslandLevel(island.getWorld(), island.getOwner(), 0L); + levelsCache.get(island.getOwner()).setInitialLevel(island.getWorld(), level); } - + /** + * Get the initial island level + * @param island - island + * @return level or 0 by default + */ + public long getInitialIslandLevel(Island island) { + return levelsCache.containsKey(island.getOwner()) ? levelsCache.get(island.getOwner()).getInitialLevel(island.getWorld()) : 0L; + } + public Database getHandler() { return handler; } public void uncachePlayer(UUID uniqueId) { - if (levelsCache.containsKey(uniqueId)) { + if (levelsCache.containsKey(uniqueId) && levelsCache.get(uniqueId) != null) { handler.saveObject(levelsCache.get(uniqueId)); } levelsCache.remove(uniqueId); diff --git a/src/main/java/world/bentobox/level/TopTen.java b/src/main/java/world/bentobox/level/TopTen.java index 12e1f64..24b1576 100644 --- a/src/main/java/world/bentobox/level/TopTen.java +++ b/src/main/java/world/bentobox/level/TopTen.java @@ -14,12 +14,12 @@ import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.event.Listener; -import world.bentobox.level.objects.TopTenData; import world.bentobox.bentobox.api.panels.PanelItem; import world.bentobox.bentobox.api.panels.builders.PanelBuilder; import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.Database; +import world.bentobox.level.objects.TopTenData; /** * Handles all Top Ten List functions diff --git a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java index b6bc97e..2c6fe65 100644 --- a/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java +++ b/src/main/java/world/bentobox/level/calculators/CalcIslandLevel.java @@ -7,6 +7,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.ChunkSnapshot; @@ -62,6 +63,9 @@ public class CalcIslandLevel { // Results go here result = new Results(); + // Set the initial island handicap + result.initialLevel = addon.getInitialIslandLevel(island); + // Get chunks to scan chunksToScan = getChunksToScan(island); @@ -147,11 +151,7 @@ public class CalcIslandLevel { /** * Checks if a block has been limited or not and whether a block has any value or not -<<<<<<< HEAD * @param md Material -======= - * @param md - Material to check ->>>>>>> branch 'develop' of https://github.com/BentoBoxWorld/addon-level.git * @return value of the block if can be counted */ private int limitCount(Material md) { @@ -175,11 +175,7 @@ public class CalcIslandLevel { /** * Get value of a material * World blocks trump regular block values -<<<<<<< HEAD - * @param md Material -======= * @param md - Material to check ->>>>>>> branch 'develop' of https://github.com/BentoBoxWorld/addon-level.git * @return value of a material */ private int getValue(Material md) { @@ -192,11 +188,7 @@ public class CalcIslandLevel { /** * Get a set of all the chunks in island * @param island - island -<<<<<<< HEAD - * @return - set of all the chunks in the island to scan -======= * @return - set of pairs of x,z coordinates to check ->>>>>>> branch 'develop' of https://github.com/BentoBoxWorld/addon-level.git */ private Set> getChunksToScan(Island island) { Set> chunkSnapshot = new HashSet<>(); @@ -214,12 +206,39 @@ public class CalcIslandLevel { task.cancel(); // Finalize calculations result.rawBlockCount += (long)(result.underWaterBlockCount * addon.getSettings().getUnderWaterMultiplier()); + // Set the death penalty - result.deathHandicap = addon.getPlayers().getDeaths(world, island.getOwner()); - // Set final score - result.level = (result.rawBlockCount / addon.getSettings().getLevelCost()) - result.deathHandicap - island.getLevelHandicap(); + if (this.addon.getSettings().isSumTeamDeaths()) + { + for (UUID uuid : this.island.getMemberSet()) + { + this.result.deathHandicap += this.addon.getPlayers().getDeaths(this.world, uuid); + } + } + else + { + this.result.deathHandicap = + this.addon.getPlayers().getDeaths(this.world, this.island.getOwner()); + } + + // Just lazy check for min death count. + this.result.deathHandicap = Math.min(this.result.deathHandicap, this.addon.getSettings().getMaxDeaths()); + + long blockAndDeathPoints = this.result.rawBlockCount; + + if (this.addon.getSettings().getDeathPenalty() > 0) + { + // Proper death penalty calculation. + blockAndDeathPoints -= this.result.deathHandicap * this.addon.getSettings().getDeathPenalty(); + } + + this.result.level = blockAndDeathPoints / this.addon.getSettings().getLevelCost() - this.island.getLevelHandicap() - result.initialLevel; + + // Calculate how many points are required to get to the next level - result.pointsToNextLevel = addon.getSettings().getLevelCost() - (result.rawBlockCount % addon.getSettings().getLevelCost()); + this.result.pointsToNextLevel = this.addon.getSettings().getLevelCost() - + (blockAndDeathPoints % this.addon.getSettings().getLevelCost()); + // Report result.report = getReport(); // All done. @@ -237,6 +256,7 @@ public class CalcIslandLevel { reportLines.add("Total block value count = " + String.format("%,d",result.rawBlockCount)); 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(LINE_BREAK); int total = 0; @@ -319,6 +339,8 @@ public class CalcIslandLevel { private long level = 0; private int deathHandicap = 0; private long pointsToNextLevel = 0; + private long initialLevel = 0; + /** * @return the deathHandicap */ @@ -332,6 +354,13 @@ public class CalcIslandLevel { public List getReport() { return report; } + /** + * Set level + * @param level - level + */ + public void setLevel(int level) { + this.level = level; + } /** * @return the level */ @@ -345,6 +374,14 @@ public class CalcIslandLevel { return pointsToNextLevel; } + public long getInitialLevel() { + return initialLevel; + } + + public void setInitialLevel(long initialLevel) { + this.initialLevel = initialLevel; + } + /* (non-Javadoc) * @see java.lang.Object#toString() */ @@ -353,7 +390,7 @@ public class CalcIslandLevel { return "Results [report=" + report + ", mdCount=" + mdCount + ", uwCount=" + uwCount + ", ncCount=" + ncCount + ", ofCount=" + ofCount + ", rawBlockCount=" + rawBlockCount + ", underWaterBlockCount=" + underWaterBlockCount + ", level=" + level + ", deathHandicap=" + deathHandicap - + ", pointsToNextLevel=" + pointsToNextLevel + "]"; + + ", pointsToNextLevel=" + pointsToNextLevel + ", initialLevel=" + initialLevel + "]"; } } diff --git a/src/main/java/world/bentobox/level/calculators/PlayerLevel.java b/src/main/java/world/bentobox/level/calculators/PlayerLevel.java index 70f501d..dee9e5a 100644 --- a/src/main/java/world/bentobox/level/calculators/PlayerLevel.java +++ b/src/main/java/world/bentobox/level/calculators/PlayerLevel.java @@ -56,6 +56,7 @@ public class PlayerLevel { // Fire post calculation event IslandLevelCalculatedEvent ilce = new IslandLevelCalculatedEvent(targetPlayer, island, calc.getResult()); addon.getServer().getPluginManager().callEvent(ilce); + // This exposes these values to plugins via the event Map keyValues = new HashMap<>(); keyValues.put("eventName", "IslandLevelCalculatedEvent"); keyValues.put("targetPlayer", targetPlayer); @@ -63,6 +64,7 @@ public class PlayerLevel { keyValues.put("level", calc.getResult().getLevel()); keyValues.put("pointsToNextLevel", calc.getResult().getPointsToNextLevel()); keyValues.put("deathHandicap", calc.getResult().getDeathHandicap()); + keyValues.put("initialLevel", calc.getResult().getInitialLevel()); addon.getServer().getPluginManager().callEvent(new AddonEvent().builder().addon(addon).keyValues(keyValues).build()); Results results = ilce.getResults(); // Save the results diff --git a/src/main/java/world/bentobox/level/commands/AdminLevel.java b/src/main/java/world/bentobox/level/commands/AdminLevel.java deleted file mode 100644 index c4b252e..0000000 --- a/src/main/java/world/bentobox/level/commands/AdminLevel.java +++ /dev/null @@ -1,51 +0,0 @@ -package world.bentobox.level.commands; - -import java.util.List; -import java.util.UUID; - -import world.bentobox.level.Level; -import world.bentobox.bentobox.api.commands.CompositeCommand; -import world.bentobox.bentobox.api.user.User; - -/** - * @deprecated Renamed and moved to {@link world.bentobox.level.commands.admin.AdminLevelCommand}. - */ -@Deprecated -public class AdminLevel extends CompositeCommand { - - private final Level levelPlugin; - - public AdminLevel(Level levelPlugin, CompositeCommand parent) { - super(parent, "level"); - this.levelPlugin = levelPlugin; - } - - @Override - public boolean execute(User user, String label, List args) { - if (args.size() == 1) { - // Asking for another player's level? - // Convert name to a UUID - final UUID playerUUID = getPlugin().getPlayers().getUUID(args.get(0)); - if (playerUUID == null) { - user.sendMessage("general.errors.unknown-player"); - return true; - } else { - levelPlugin.calculateIslandLevel(getWorld(), user, playerUUID); - } - return true; - } else { - showHelp(this, user); - return false; - } - } - - @Override - public void setup() { - this.setPermission("admin.level"); - this.setOnlyPlayer(false); - this.setParametersHelp("admin.level.parameters"); - this.setDescription("admin.level.description"); - - } - -} diff --git a/src/main/java/world/bentobox/level/commands/AdminTop.java b/src/main/java/world/bentobox/level/commands/AdminTop.java deleted file mode 100644 index 3a39b4a..0000000 --- a/src/main/java/world/bentobox/level/commands/AdminTop.java +++ /dev/null @@ -1,73 +0,0 @@ -package world.bentobox.level.commands; - -import java.util.List; -import java.util.Map.Entry; -import java.util.UUID; - -import org.bukkit.World; - -import world.bentobox.level.Level; -import world.bentobox.bentobox.api.commands.CompositeCommand; -import world.bentobox.bentobox.api.user.User; -import world.bentobox.bentobox.database.objects.Island; - -/** - * @deprecated Renamed and moved to {@link world.bentobox.level.commands.admin.AdminTopCommand}. - */ -@Deprecated -public class AdminTop extends CompositeCommand { - - private final Level levelPlugin; - - public AdminTop(Level levelPlugin, CompositeCommand parent) { - super(parent, "top", "topten"); - this.levelPlugin = levelPlugin; - } - - @Override - public boolean execute(User user, String label, List args) { - // Get world - World world; - if (args.isEmpty()) { - if (getPlugin().getIWM().getOverWorlds().size() == 1) { - world = getPlugin().getIWM().getOverWorlds().get(0); - } else { - showHelp(this, user); - return false; - } - } else { - if (getPlugin().getIWM().isOverWorld(args.get(0))) { - world = getPlugin().getIWM().getIslandWorld(args.get(0)); - } else { - user.sendMessage("commands.admin.top.unknown-world"); - return false; - } - - } - int rank = 0; - for (Entry topTen : levelPlugin.getTopTen().getTopTenList(world).getTopTen().entrySet()) { - Island island = getPlugin().getIslands().getIsland(world, topTen.getKey()); - if (island != null) { - rank++; - String item = user.getTranslation("admin.topten", - "[rank]", - "[name]", - "[level]", - String.valueOf(rank), - this.getPlugin().getPlayers().getUser(island.getOwner()).getName(), - String.valueOf(topTen.getValue())); - user.sendRawMessage(item); - } - } - - return true; - } - - @Override - public void setup() { - this.setPermission("admin.top"); - this.setOnlyPlayer(false); - this.setDescription("admin.top.description"); - } - -} diff --git a/src/main/java/world/bentobox/level/commands/IslandLevel.java b/src/main/java/world/bentobox/level/commands/IslandLevel.java deleted file mode 100644 index 8ca414c..0000000 --- a/src/main/java/world/bentobox/level/commands/IslandLevel.java +++ /dev/null @@ -1,54 +0,0 @@ -package world.bentobox.level.commands; - -import java.util.List; -import java.util.UUID; - -import world.bentobox.level.Level; -import world.bentobox.bentobox.api.commands.CompositeCommand; -import world.bentobox.bentobox.api.user.User; - -/** - * @deprecated Renamed and moved to {@link world.bentobox.level.commands.island.IslandLevelCommand}. - */ -@Deprecated -public class IslandLevel extends CompositeCommand { - - private final Level levelPlugin; - - public IslandLevel(Level levelPlugin, CompositeCommand parent) { - super(parent, "level"); - this.levelPlugin = levelPlugin; - } - - @Override - public boolean execute(User user, String label, List args) { - if (!args.isEmpty()) { - // Asking for another player's level? - // Convert name to a UUID - final UUID playerUUID = getPlugin().getPlayers().getUUID(args.get(0)); - if (playerUUID == null) { - user.sendMessage("general.errors.unknown-player"); - return true; - } else if (user.getUniqueId().equals(playerUUID) ) { - // Self level request - levelPlugin.calculateIslandLevel(getWorld(), user, user.getUniqueId()); - } else { - user.sendMessage("island.level.island-level-is", "[level]", String.valueOf(levelPlugin.getIslandLevel(getWorld(), playerUUID))); - return true; - } - } else { - // Self level request - levelPlugin.calculateIslandLevel(getWorld(), user, user.getUniqueId()); - } - return false; - } - - @Override - public void setup() { - this.setPermission("island.level"); - this.setParametersHelp("island.level.parameters"); - this.setDescription("island.level.description"); - this.setOnlyPlayer(true); - } - -} diff --git a/src/main/java/world/bentobox/level/commands/IslandTop.java b/src/main/java/world/bentobox/level/commands/IslandTop.java deleted file mode 100644 index eba1397..0000000 --- a/src/main/java/world/bentobox/level/commands/IslandTop.java +++ /dev/null @@ -1,34 +0,0 @@ -package world.bentobox.level.commands; - -import java.util.List; - -import world.bentobox.level.Level; -import world.bentobox.bentobox.api.commands.CompositeCommand; -import world.bentobox.bentobox.api.user.User; - -/** - * @deprecated Renamed and moved to {@link world.bentobox.level.commands.island.IslandTopCommand}. - */ -@Deprecated -public class IslandTop extends CompositeCommand { - - private final Level plugin; - - public IslandTop(Level plugin, CompositeCommand parent) { - super(parent, "top", "topten"); - this.plugin = plugin; - } - - @Override - public void setup() { - setPermission("island.top"); - setDescription("island.top.description"); - setOnlyPlayer(true); - } - - @Override - public boolean execute(User user, String label, List list) { - plugin.getTopTen().getGUI(getWorld(), user, getPermissionPrefix()); - return true; - } -} diff --git a/src/main/java/world/bentobox/level/commands/admin/AdminLevelCommand.java b/src/main/java/world/bentobox/level/commands/admin/AdminLevelCommand.java index f0fcee2..a532acf 100644 --- a/src/main/java/world/bentobox/level/commands/admin/AdminLevelCommand.java +++ b/src/main/java/world/bentobox/level/commands/admin/AdminLevelCommand.java @@ -1,12 +1,15 @@ package world.bentobox.level.commands.admin; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.user.User; +import world.bentobox.bentobox.util.Util; import world.bentobox.level.Level; -import java.util.List; -import java.util.UUID; - public class AdminLevelCommand extends CompositeCommand { private final Level levelPlugin; @@ -42,4 +45,15 @@ public class AdminLevelCommand extends CompositeCommand { return false; } } + + @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)); + } } 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 3277841..30598e7 100644 --- a/src/main/java/world/bentobox/level/commands/admin/AdminTopCommand.java +++ b/src/main/java/world/bentobox/level/commands/admin/AdminTopCommand.java @@ -1,15 +1,14 @@ package world.bentobox.level.commands.admin; -import org.bukkit.World; -import world.bentobox.bentobox.api.commands.CompositeCommand; -import world.bentobox.bentobox.api.user.User; -import world.bentobox.bentobox.database.objects.Island; -import world.bentobox.level.Level; - import java.util.List; import java.util.Map; import java.util.UUID; +import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.user.User; +import world.bentobox.bentobox.database.objects.Island; +import world.bentobox.level.Level; + public class AdminTopCommand extends CompositeCommand { private final Level levelPlugin; @@ -28,27 +27,9 @@ public class AdminTopCommand extends CompositeCommand { @Override public boolean execute(User user, String label, List args) { - // Get world - World world; - if (args.isEmpty()) { - if (getPlugin().getIWM().getOverWorlds().size() == 1) { - world = getPlugin().getIWM().getOverWorlds().get(0); - } else { - showHelp(this, user); - return false; - } - } else { - if (getPlugin().getIWM().isOverWorld(args.get(0))) { - world = getPlugin().getIWM().getIslandWorld(args.get(0)); - } else { - user.sendMessage("commands.admin.top.unknown-world"); - return false; - } - - } int rank = 0; - for (Map.Entry topTen : levelPlugin.getTopTen().getTopTenList(world).getTopTen().entrySet()) { - Island island = getPlugin().getIslands().getIsland(world, topTen.getKey()); + for (Map.Entry topTen : levelPlugin.getTopTen().getTopTenList(getWorld()).getTopTen().entrySet()) { + Island island = getPlugin().getIslands().getIsland(getWorld(), topTen.getKey()); if (island != null) { rank++; user.sendMessage("admin.top.display", diff --git a/src/main/java/world/bentobox/level/commands/island/IslandLevelCommand.java b/src/main/java/world/bentobox/level/commands/island/IslandLevelCommand.java index 84cfb3a..48314f9 100644 --- a/src/main/java/world/bentobox/level/commands/island/IslandLevelCommand.java +++ b/src/main/java/world/bentobox/level/commands/island/IslandLevelCommand.java @@ -1,12 +1,12 @@ package world.bentobox.level.commands.island; +import java.util.List; +import java.util.UUID; + import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.user.User; import world.bentobox.level.Level; -import java.util.List; -import java.util.UUID; - public class IslandLevelCommand extends CompositeCommand { private final Level levelPlugin; @@ -34,17 +34,39 @@ public class IslandLevelCommand extends CompositeCommand { user.sendMessage("general.errors.unknown-player"); return true; } else if (user.getUniqueId().equals(playerUUID) ) { - // Self level request - levelPlugin.calculateIslandLevel(getWorld(), user, user.getUniqueId()); + return this.calculateLevel(user); } else { user.sendMessage("island.level.island-level-is", "[level]", String.valueOf(levelPlugin.getIslandLevel(getWorld(), playerUUID))); return true; } } else { - // Self level request - levelPlugin.calculateIslandLevel(getWorld(), user, user.getUniqueId()); + return this.calculateLevel(user); } - return false; } + + /** + * This method calls island level calculation if it is allowed by cooldown. + * @param user User which island level must be calculated. + * @return True if le + */ + private boolean calculateLevel(User user) + { + int coolDown = this.levelPlugin.getSettings().getLevelWait(); + + if (coolDown > 0 && this.checkCooldown(user, null)) + { + return false; + } + + // Self level request + this.levelPlugin.calculateIslandLevel(getWorld(), user, user.getUniqueId()); + + if (coolDown > 0) + { + this.setCooldown(user.getUniqueId(), null, coolDown); + } + + return true; + } } diff --git a/src/main/java/world/bentobox/level/commands/island/IslandTopCommand.java b/src/main/java/world/bentobox/level/commands/island/IslandTopCommand.java index 1f8db3d..a80a3c1 100644 --- a/src/main/java/world/bentobox/level/commands/island/IslandTopCommand.java +++ b/src/main/java/world/bentobox/level/commands/island/IslandTopCommand.java @@ -1,11 +1,11 @@ package world.bentobox.level.commands.island; +import java.util.List; + import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.user.User; import world.bentobox.level.Level; -import java.util.List; - public class IslandTopCommand extends CompositeCommand { private final Level plugin; diff --git a/src/main/java/world/bentobox/level/config/Settings.java b/src/main/java/world/bentobox/level/config/Settings.java index c308317..e0f49dd 100644 --- a/src/main/java/world/bentobox/level/config/Settings.java +++ b/src/main/java/world/bentobox/level/config/Settings.java @@ -1,6 +1,8 @@ package world.bentobox.level.config; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.bukkit.Bukkit; @@ -23,11 +25,15 @@ public class Settings { private int maxDeaths; private boolean islandResetDeathReset; private boolean teamJoinDeathReset; + private List gameModes = new ArrayList<>(); public Settings(Level level) { level.saveDefaultConfig(); + // GameModes + gameModes = level.getConfig().getStringList("game-modes"); + setLevelWait(level.getConfig().getInt("levelwait", 60)); if (getLevelWait() < 0) { setLevelWait(0); @@ -167,7 +173,7 @@ public class Settings { /** * @return the levelWait */ - private int getLevelWait() { + public final int getLevelWait() { return levelWait; } /** @@ -221,4 +227,11 @@ public class Settings { return worldBlockValues; } + /** + * @return the gameModes + */ + public List getGameModes() { + return gameModes; + } + } diff --git a/src/main/java/world/bentobox/level/event/IslandLevelCalculatedEvent.java b/src/main/java/world/bentobox/level/event/IslandLevelCalculatedEvent.java index c6b100a..73a9ed8 100644 --- a/src/main/java/world/bentobox/level/event/IslandLevelCalculatedEvent.java +++ b/src/main/java/world/bentobox/level/event/IslandLevelCalculatedEvent.java @@ -2,9 +2,9 @@ package world.bentobox.level.event; import java.util.UUID; -import world.bentobox.level.calculators.CalcIslandLevel.Results; import world.bentobox.bentobox.api.events.IslandBaseEvent; import world.bentobox.bentobox.database.objects.Island; +import world.bentobox.level.calculators.CalcIslandLevel.Results; /** * This event is fired after the island level is calculated and before the results are saved. diff --git a/src/main/java/world/bentobox/level/listeners/IslandTeamListeners.java b/src/main/java/world/bentobox/level/listeners/IslandTeamListeners.java new file mode 100644 index 0000000..9d51f74 --- /dev/null +++ b/src/main/java/world/bentobox/level/listeners/IslandTeamListeners.java @@ -0,0 +1,102 @@ +package world.bentobox.level.listeners; + +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.event.EventHandler; +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.IslandRegisteredEvent; +import world.bentobox.bentobox.api.events.island.IslandEvent.IslandResettedEvent; +import world.bentobox.bentobox.api.events.island.IslandEvent.IslandUnregisteredEvent; +import world.bentobox.bentobox.api.events.team.TeamEvent.TeamJoinedEvent; +import world.bentobox.bentobox.api.events.team.TeamEvent.TeamKickEvent; +import world.bentobox.bentobox.api.events.team.TeamEvent.TeamLeaveEvent; +import world.bentobox.bentobox.api.events.team.TeamEvent.TeamSetownerEvent; +import world.bentobox.bentobox.database.objects.Island; +import world.bentobox.level.Level; +import world.bentobox.level.calculators.CalcIslandLevel; + +/** + * Listens for new islands or ownership changes and sets the level to zero automatically + * @author tastybento + * + */ +public class IslandTeamListeners implements Listener { + + private final Level addon; + private final Map cil; + + /** + * @param addon - addon + */ + public IslandTeamListeners(Level addon) { + this.addon = addon; + cil = new HashMap<>(); + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onNewIsland(IslandCreatedEvent e) { + if (e.getIsland().getOwner() != null && e.getIsland().getWorld() != null) { + cil.putIfAbsent(e.getIsland(), new CalcIslandLevel(addon, e.getIsland(), () -> zeroLevel(e.getIsland()))); + } + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onNewIsland(IslandResettedEvent e) { + if (e.getIsland().getOwner() != null && e.getIsland().getWorld() != null) { + cil.putIfAbsent(e.getIsland(), new CalcIslandLevel(addon, e.getIsland(), () -> zeroLevel(e.getIsland()))); + } + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onNewIslandOwner(TeamSetownerEvent e) { + // Remove player from the top ten and level + addon.setIslandLevel(e.getIsland().getWorld(), e.getIsland().getOwner(), 0); + addon.getTopTen().removeEntry(e.getIsland().getWorld(), e.getIsland().getOwner()); + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onIsland(TeamJoinedEvent e) { + // Remove player from the top ten and level + addon.setIslandLevel(e.getIsland().getWorld(), e.getPlayerUUID(), 0); + addon.getTopTen().removeEntry(e.getIsland().getWorld(), e.getPlayerUUID()); + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onIsland(IslandUnregisteredEvent e) { + // Remove player from the top ten and level + addon.setIslandLevel(e.getIsland().getWorld(), e.getPlayerUUID(), 0); + addon.getTopTen().removeEntry(e.getIsland().getWorld(), e.getPlayerUUID()); + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onIsland(IslandRegisteredEvent e) { + // Remove player from the top ten and level + addon.setIslandLevel(e.getIsland().getWorld(), e.getPlayerUUID(), 0); + addon.getTopTen().removeEntry(e.getIsland().getWorld(), e.getPlayerUUID()); + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onIsland(TeamLeaveEvent e) { + // Remove player from the top ten and level + addon.setIslandLevel(e.getIsland().getWorld(), e.getPlayerUUID(), 0); + addon.getTopTen().removeEntry(e.getIsland().getWorld(), e.getPlayerUUID()); + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onIsland(TeamKickEvent e) { + // Remove player from the top ten and level + addon.setIslandLevel(e.getIsland().getWorld(), e.getPlayerUUID(), 0); + addon.getTopTen().removeEntry(e.getIsland().getWorld(), e.getPlayerUUID()); + } + + private void zeroLevel(Island island) { + if (cil.containsKey(island)) { + addon.setInitialIslandLevel(island, cil.get(island).getResult().getLevel()); + cil.remove(island); + } + } +} diff --git a/src/main/java/world/bentobox/level/listeners/NewIslandListener.java b/src/main/java/world/bentobox/level/listeners/NewIslandListener.java deleted file mode 100644 index 9b9e463..0000000 --- a/src/main/java/world/bentobox/level/listeners/NewIslandListener.java +++ /dev/null @@ -1,50 +0,0 @@ -package world.bentobox.level.listeners; - -import java.util.HashMap; -import java.util.Map; - -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; - -import world.bentobox.level.Level; -import world.bentobox.level.calculators.CalcIslandLevel; -import world.bentobox.bentobox.api.events.island.IslandEvent.IslandCreatedEvent; -import world.bentobox.bentobox.api.events.island.IslandEvent.IslandResettedEvent; -import world.bentobox.bentobox.database.objects.Island; - -/** - * Listens for new islands and sets the level to zero automatically - * @author tastybento - * - */ -public class NewIslandListener implements Listener { - - private final Level addon; - private final Map cil; - - /** - * @param addon - addon - */ - public NewIslandListener(Level addon) { - this.addon = addon; - cil = new HashMap<>(); - } - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onNewIsland(IslandCreatedEvent e) { - cil.putIfAbsent(e.getIsland(), new CalcIslandLevel(addon, e.getIsland(), () -> zeroLevel(e.getIsland()))); - } - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onNewIsland(IslandResettedEvent e) { - cil.putIfAbsent(e.getIsland(), new CalcIslandLevel(addon, e.getIsland(), () -> zeroLevel(e.getIsland()))); - } - - private void zeroLevel(Island island) { - if (cil.containsKey(island)) { - addon.setInitialIslandLevel(island, cil.get(island).getResult().getLevel()); - cil.remove(island); - } - } -} diff --git a/src/main/java/world/bentobox/level/objects/LevelsData.java b/src/main/java/world/bentobox/level/objects/LevelsData.java index a45c15f..45c4876 100644 --- a/src/main/java/world/bentobox/level/objects/LevelsData.java +++ b/src/main/java/world/bentobox/level/objects/LevelsData.java @@ -16,11 +16,16 @@ public class LevelsData implements DataObject { @Expose private String uniqueId = ""; - // Map - world name, level + /** + * Map of world name and island level + */ @Expose private Map levels = new HashMap<>(); + /** + * Map of world name to island initial level + */ @Expose - private long initialIslandLevel = 0; + private Map initialLevel = new HashMap<>(); public LevelsData() {} // For Bean loading @@ -54,10 +59,10 @@ public class LevelsData implements DataObject { /** * Get the island level for this world * @param world - world - * @return island level, less the initialIslandLevel + * @return island level */ public Long getLevel(World world) { - return world == null ? -initialIslandLevel : levels.getOrDefault(world.getName(), 0L) - initialIslandLevel; + return world == null ? 0L : levels.getOrDefault(world.getName(), 0L); } /** @@ -79,16 +84,34 @@ public class LevelsData implements DataObject { } /** - * @return the initialIslandLevel + * Set the initial level of the island for this world + * @param world - world + * @param level - level */ - public long getInitialIslandLevel() { - return initialIslandLevel; + public void setInitialLevel(World world, long level) { + this.initialLevel.put(world.getName(), level); } /** - * @param initialIslandLevel the initialIslandLevel to set + * @return the initialLevel */ - public void setInitialIslandLevel(long initialIslandLevel) { - this.initialIslandLevel = initialIslandLevel; + public Map getInitialLevel() { + return initialLevel; + } + + /** + * @param initialLevel the initialLevel to set + */ + public void setInitialLevel(Map initialLevel) { + this.initialLevel = initialLevel; + } + + /** + * Get the initial island level for this world + * @param world - world + * @return initial island level or 0 by default + */ + public long getInitialLevel(World world) { + return initialLevel.getOrDefault(world.getName(), 0L); } } diff --git a/src/main/java/world/bentobox/level/placeholders/LevelPlaceholder.java b/src/main/java/world/bentobox/level/placeholders/LevelPlaceholder.java new file mode 100644 index 0000000..da61bf0 --- /dev/null +++ b/src/main/java/world/bentobox/level/placeholders/LevelPlaceholder.java @@ -0,0 +1,38 @@ +/** + * + */ +package world.bentobox.level.placeholders; + +import world.bentobox.bentobox.api.addons.GameModeAddon; +import world.bentobox.bentobox.api.placeholders.PlaceholderReplacer; +import world.bentobox.bentobox.api.user.User; +import world.bentobox.level.Level; + +/** + * @author tastybento + * + */ +public class LevelPlaceholder implements PlaceholderReplacer { + + private Level addon; + private GameModeAddon gm; + + /** + * Provides placeholder support + * @param addon - Level addon + * @param gm - Game mode + */ + public LevelPlaceholder(Level addon, GameModeAddon gm) { + this.addon = addon; + this.gm = gm; + } + + /* (non-Javadoc) + * @see world.bentobox.bentobox.api.placeholders.PlaceholderReplacer#onReplace(world.bentobox.bentobox.api.user.User) + */ + @Override + public String onReplace(User user) { + return String.valueOf(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 new file mode 100644 index 0000000..593b18d --- /dev/null +++ b/src/main/java/world/bentobox/level/placeholders/TopTenNamePlaceholder.java @@ -0,0 +1,39 @@ +/** + * + */ +package world.bentobox.level.placeholders; + +import java.util.Collection; +import java.util.UUID; + +import world.bentobox.bentobox.api.addons.GameModeAddon; +import world.bentobox.bentobox.api.placeholders.PlaceholderReplacer; +import world.bentobox.bentobox.api.user.User; +import world.bentobox.level.Level; + +/** + * @author tastybento + * + */ +public class TopTenNamePlaceholder implements PlaceholderReplacer { + + private final Level level; + private final GameModeAddon gm; + private final int i; + + public TopTenNamePlaceholder(Level level, GameModeAddon gm, int i) { + this.level = level; + this.gm = gm; + this.i = i - 1; + } + + /* (non-Javadoc) + * @see world.bentobox.bentobox.api.placeholders.PlaceholderReplacer#onReplace(world.bentobox.bentobox.api.user.User) + */ + @Override + public String onReplace(User user) { + 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 new file mode 100644 index 0000000..27849e4 --- /dev/null +++ b/src/main/java/world/bentobox/level/placeholders/TopTenPlaceholder.java @@ -0,0 +1,39 @@ +/** + * + */ +package world.bentobox.level.placeholders; + +import java.util.Collection; + +import world.bentobox.bentobox.api.addons.GameModeAddon; +import world.bentobox.bentobox.api.placeholders.PlaceholderReplacer; +import world.bentobox.bentobox.api.user.User; +import world.bentobox.level.Level; + +/** + * Provides the level values to placeholders + * @author tastybento + * + */ +public class TopTenPlaceholder implements PlaceholderReplacer { + + private final Level level; + private final GameModeAddon gm; + private final int i; + + public TopTenPlaceholder(Level level, GameModeAddon gm, int i) { + this.level = level; + this.gm = gm; + this.i = i - 1; + } + + /* (non-Javadoc) + * @see world.bentobox.bentobox.api.placeholders.PlaceholderReplacer#onReplace(world.bentobox.bentobox.api.user.User) + */ + @Override + public String onReplace(User user) { + Collection values = level.getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().values(); + return values.size() < i ? "" : values.stream().skip(i).findFirst().map(String::valueOf).orElse(""); + } + +} diff --git a/src/main/java/world/bentobox/level/requests/LevelRequestHandler.java b/src/main/java/world/bentobox/level/requests/LevelRequestHandler.java index 7626050..747bda0 100644 --- a/src/main/java/world/bentobox/level/requests/LevelRequestHandler.java +++ b/src/main/java/world/bentobox/level/requests/LevelRequestHandler.java @@ -1,12 +1,13 @@ package world.bentobox.level.requests; -import org.bukkit.Bukkit; -import world.bentobox.bentobox.api.addons.request.AddonRequestHandler; -import world.bentobox.level.Level; - import java.util.Map; import java.util.UUID; +import org.bukkit.Bukkit; + +import world.bentobox.bentobox.api.addons.request.AddonRequestHandler; +import world.bentobox.level.Level; + public class LevelRequestHandler extends AddonRequestHandler { private Level addon; diff --git a/src/main/resources/addon.yml b/src/main/resources/addon.yml index 5706751..936c21f 100755 --- a/src/main/resources/addon.yml +++ b/src/main/resources/addon.yml @@ -22,6 +22,7 @@ permissions: bskyblock.admin.topten: description: Player can use admin top ten command default: true + acidisland.intopten: description: Player is in the top ten. default: true @@ -35,5 +36,37 @@ permissions: description: Player can use admin level command default: true acidisland.admin.topten: + description: Player can use admin top ten command + default: true + + caveblock.intopten: + description: Player is in the top ten. + default: true + caveblock.island.level: + description: Player can use level command + default: true + caveblock.island.top: + description: Player can use top ten command + default: true + caveblock.admin.level: + description: Player can use admin level command + default: true + caveblock.admin.topten: + description: Player can use admin top ten command + default: true + + skygird.intopten: + description: Player is in the top ten. + default: true + skygird.island.level: + description: Player can use level command + default: true + skygird.island.top: + description: Player can use top ten command + default: true + skygird.admin.level: + description: Player can use admin level command + default: true + skygird.admin.topten: description: Player can use admin top ten command default: true \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 842ada4..2f8e1e1 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,14 +1,13 @@ # Config file for Level add-on for BSkyBlock or AcidIsland -# Command hook-in configuration. -# Level will try to hook into these commands when it starts -# If you have changed the default AcidIsland or BSkyBlock commands, change them here -acidisland: - admin-command: acid - user-command: ai -bskyblock: - admin-command: bsbadmin - user-command: island +# GameModes +# Level will hook into these game modes. Don't forget to set any world-specific +# block values below! +game-modes: +- AcidIsland +- BSkyBlock +- CaveBlock +#- SkyGrid # This file lists the values for various blocks that are used to calculate the # island level. Level = total of all blocks in island boundary / 100. diff --git a/src/test/java/world/bentobox/level/LevelPresenterTest.java b/src/test/java/world/bentobox/level/LevelPresenterTest.java index 28679a1..51293e5 100644 --- a/src/test/java/world/bentobox/level/LevelPresenterTest.java +++ b/src/test/java/world/bentobox/level/LevelPresenterTest.java @@ -15,11 +15,11 @@ import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; -import world.bentobox.level.calculators.PlayerLevel; import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.managers.IslandWorldManager; import world.bentobox.bentobox.managers.IslandsManager; +import world.bentobox.level.calculators.PlayerLevel; /** * @author tastybento