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