diff --git a/pom.xml b/pom.xml
index bf1a939..d113aaa 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
world.bentobox
limits
- 0.0.3-SNAPSHOT
+ 0.1.0-SNAPSHOT
addon-limits
An add-on for BentoBox that limits blocks and entities on islands.
https://github.com/BentoBoxWorld/addon-level
diff --git a/src/main/java/bentobox/addon/limits/Limits.java b/src/main/java/bentobox/addon/limits/Limits.java
index b26c8c5..4d399c3 100644
--- a/src/main/java/bentobox/addon/limits/Limits.java
+++ b/src/main/java/bentobox/addon/limits/Limits.java
@@ -6,7 +6,7 @@ import java.util.stream.Collectors;
import org.bukkit.World;
import bentobox.addon.limits.listeners.BlockLimitsListener;
-import bentobox.addon.limits.listeners.EntityLimitsListener;
+import bentobox.addon.limits.listeners.JoinListener;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.addons.GameModeAddon;
@@ -19,15 +19,11 @@ import world.bentobox.bentobox.api.addons.GameModeAddon;
public class Limits extends Addon {
private Settings settings;
- private EntityLimitsListener listener;
- private List worlds;
+ private List gameModes;
private BlockLimitsListener blockLimitListener;
@Override
public void onDisable(){
- if (listener != null) {
- worlds.forEach(listener::disable);
- }
if (blockLimitListener != null) {
blockLimitListener.save();
}
@@ -40,16 +36,14 @@ public class Limits extends Addon {
// Load settings
settings = new Settings(this);
// Register worlds from GameModes
- worlds = getPlugin().getAddonsManager().getGameModeAddons().stream()
+ gameModes = getPlugin().getAddonsManager().getGameModeAddons().stream()
.filter(gm -> settings.getGameModes().contains(gm.getDescription().getName()))
- .map(GameModeAddon::getOverWorld)
.collect(Collectors.toList());
- worlds.forEach(w -> log("Limits will apply to " + w.getName()));
+ gameModes.forEach(w -> log("Limits will apply to " + w.getDescription().getName()));
// Register listener
- //listener = new EntityLimitsListener(this);
- //registerListener(listener);
blockLimitListener = new BlockLimitsListener(this);
registerListener(blockLimitListener);
+ registerListener(new JoinListener(this));
// Done
}
@@ -60,5 +54,44 @@ public class Limits extends Addon {
return settings;
}
+ /**
+ * @return the gameModes
+ */
+ public List getGameModes() {
+ return gameModes;
+ }
+ /**
+ * @return the blockLimitListener
+ */
+ public BlockLimitsListener getBlockLimitListener() {
+ return blockLimitListener;
+ }
+
+ /**
+ * Checks if this world is covered by the activated game modes
+ * @param world - world
+ * @return true or false
+ */
+ public boolean inGameModeWorld(World world) {
+ return gameModes.stream().anyMatch(gm -> gm.inWorld(world));
+ }
+
+ /**
+ * Get the name of the game mode for this world
+ * @param world - world
+ * @return game mode name or empty string if none
+ */
+ public String getGameMode(World world) {
+ return gameModes.stream().filter(gm -> gm.inWorld(world)).findFirst().map(gm -> gm.getDescription().getName()).orElse("");
+ }
+
+ /**
+ * Check if any of the game modes covered have this name
+ * @param gameMode - name of game mode
+ * @return true or false
+ */
+ public boolean isCoveredGameMode(String gameMode) {
+ return gameModes.stream().anyMatch(gm -> gm.getDescription().getName().equals(gameMode));
+ }
}
diff --git a/src/main/java/bentobox/addon/limits/Settings.java b/src/main/java/bentobox/addon/limits/Settings.java
index ba074d7..ca72557 100644
--- a/src/main/java/bentobox/addon/limits/Settings.java
+++ b/src/main/java/bentobox/addon/limits/Settings.java
@@ -17,7 +17,7 @@ public class Settings {
public Settings(Limits addon) {
// GameModes
- gameModes = addon.getConfig().getStringList("game-modes");
+ gameModes = addon.getConfig().getStringList("gamemodes");
ConfigurationSection el = addon.getConfig().getConfigurationSection("entitylimits");
if (el != null) {
diff --git a/src/main/java/bentobox/addon/limits/listeners/BlockLimitsListener.java b/src/main/java/bentobox/addon/limits/listeners/BlockLimitsListener.java
index 1451835..ecbbb44 100644
--- a/src/main/java/bentobox/addon/limits/listeners/BlockLimitsListener.java
+++ b/src/main/java/bentobox/addon/limits/listeners/BlockLimitsListener.java
@@ -3,7 +3,10 @@
*/
package bentobox.addon.limits.listeners;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import org.bukkit.Bukkit;
@@ -47,6 +50,7 @@ public class BlockLimitsListener implements Listener {
* Save every 10 blocks of change
*/
private static final Integer CHANGE_LIMIT = 9;
+ private static final List DO_NOT_COUNT = Arrays.asList(Material.LAVA, Material.WATER, Material.AIR, Material.FIRE, Material.END_PORTAL, Material.NETHER_PORTAL);
private Limits addon;
private Map countMap = new HashMap<>();
private Map saveMap = new HashMap<>();
@@ -57,7 +61,18 @@ public class BlockLimitsListener implements Listener {
public BlockLimitsListener(Limits addon) {
this.addon = addon;
handler = new Database<>(addon, IslandBlockCount.class);
- handler.loadObjects().forEach(ibc -> countMap.put(ibc.getUniqueId(), ibc));
+ List toBeDeleted = new ArrayList<>();
+ handler.loadObjects().forEach(ibc -> {
+ // Clean up
+ if (addon.isCoveredGameMode(ibc.getGameMode())) {
+ ibc.getBlockCount().keySet().removeIf(DO_NOT_COUNT::contains);
+ // Store
+ countMap.put(ibc.getUniqueId(), ibc);
+ } else {
+ toBeDeleted.add(ibc.getUniqueId());
+ }
+ });
+ toBeDeleted.forEach(handler::deleteID);
loadAllLimits();
}
@@ -73,12 +88,11 @@ public class BlockLimitsListener implements Listener {
}
// Load specific worlds
-
if (addon.getConfig().isConfigurationSection("worlds")) {
ConfigurationSection worlds = addon.getConfig().getConfigurationSection("worlds");
for (String worldName : worlds.getKeys(false)) {
World world = Bukkit.getWorld(worldName);
- if (world != null && addon.getPlugin().getIWM().inWorld(world)) {
+ if (world != null && addon.inGameModeWorld(world)) {
addon.log("Loading limits for " + world.getName());
limitMap.putIfAbsent(world, new HashMap<>());
ConfigurationSection matsConfig = worlds.getConfigurationSection(worldName);
@@ -98,7 +112,7 @@ public class BlockLimitsListener implements Listener {
Map mats = new HashMap<>();
for (String material : cs.getKeys(false)) {
Material mat = Material.getMaterial(material);
- if (mat != null && mat.isBlock()) {
+ if (mat != null && mat.isBlock() && !DO_NOT_COUNT.contains(mat)) {
mats.put(mat, cs.getInt(material));
addon.log("Limit " + mat + " to " + cs.getInt(material));
} else {
@@ -203,10 +217,18 @@ public class BlockLimitsListener implements Listener {
* @return limit amount if over limit, or -1 if no limitation
*/
private int process(Block b, boolean add, Material changeTo) {
+ if (DO_NOT_COUNT.contains(b.getType()) || !addon.inGameModeWorld(b.getWorld())) {
+ return -1;
+ }
// Check if on island
return addon.getIslands().getIslandAt(b.getLocation()).map(i -> {
String id = i.getUniqueId();
- countMap.putIfAbsent(id, new IslandBlockCount(id));
+ String gameMode = addon.getGameMode(b.getWorld());
+ if (gameMode.isEmpty()) {
+ // Invalid world
+ return -1;
+ }
+ countMap.putIfAbsent(id, new IslandBlockCount(id, gameMode));
saveMap.putIfAbsent(id, 0);
if (add) {
// Check limit
@@ -219,7 +241,7 @@ public class BlockLimitsListener implements Listener {
} else {
if (countMap.containsKey(id)) {
// Check for changes
- if (!changeTo.equals(b.getType()) && changeTo.isBlock()) {
+ if (!changeTo.equals(b.getType()) && changeTo.isBlock() && !DO_NOT_COUNT.contains(changeTo)) {
// Check limit
int limit = checkLimit(b.getWorld(), changeTo, id);
if (limit > -1) {
@@ -247,22 +269,18 @@ public class BlockLimitsListener implements Listener {
* @return limit amount if at limit
*/
private int checkLimit(World w, Material m, String id) {
- // Check specific world first
+ // Check island limits
+ IslandBlockCount island = countMap.get(id);
+ if (island.isBlockLimited(m)) {
+ return island.isAtLimit(m) ? island.getBlockLimit(m) : -1;
+ }
+ // Check specific world limits
if (limitMap.containsKey(w) && limitMap.get(w).containsKey(m)) {
// Material is overridden in world
- if (countMap.get(id).isAtLimit(m, limitMap.get(w).get(m))) {
- return limitMap.get(w).get(m);
- } else {
- // No limit
- return -1;
- }
+ return island.isAtLimit(m, limitMap.get(w).get(m)) ? limitMap.get(w).get(m) : -1;
}
// Check default limit map
- if (defaultLimitMap.containsKey(m)
- && countMap
- .get(id)
- .isAtLimit(m,
- defaultLimitMap.get(m))) {
+ if (defaultLimitMap.containsKey(m) && island.isAtLimit(m, defaultLimitMap.get(m))) {
return defaultLimitMap.get(m);
}
// No limit
@@ -282,4 +300,24 @@ public class BlockLimitsListener implements Listener {
}
}
+
+ /**
+ * Set the island block count values
+ * @param islandId - island unique id
+ * @param ibc - island block count
+ */
+ public void setIsland(String islandId, IslandBlockCount ibc) {
+ countMap.put(islandId, ibc);
+ handler.saveObject(ibc);
+ }
+
+ /**
+ * Get the island block count
+ * @param islandId - island unique id
+ * @return island block count or null if there is none yet
+ */
+ public IslandBlockCount getIsland(String islandId) {
+ return countMap.get(islandId);
+ }
+
}
diff --git a/src/main/java/bentobox/addon/limits/listeners/JoinListener.java b/src/main/java/bentobox/addon/limits/listeners/JoinListener.java
new file mode 100644
index 0000000..7c1efdc
--- /dev/null
+++ b/src/main/java/bentobox/addon/limits/listeners/JoinListener.java
@@ -0,0 +1,86 @@
+package bentobox.addon.limits.listeners;
+
+import java.util.Locale;
+
+import org.apache.commons.lang.math.NumberUtils;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.permissions.PermissionAttachmentInfo;
+
+import bentobox.addon.limits.Limits;
+import bentobox.addon.limits.objects.IslandBlockCount;
+
+/**
+ * Sets block limits based on player permission
+ * @author tastybento
+ *
+ */
+public class JoinListener implements Listener {
+
+ private Limits addon;
+
+ public JoinListener(Limits addon) {
+ this.addon = addon;
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
+ public void onPlayerJoin(PlayerJoinEvent e) {
+ // Check if player has any islands in the game modes
+ addon.getGameModes().forEach(gm -> {
+ if (addon.getIslands().hasIsland(gm.getOverWorld(), e.getPlayer().getUniqueId())) {
+ String islandId = addon.getIslands().getIsland(gm.getOverWorld(), e.getPlayer().getUniqueId()).getUniqueId();
+ checkPerms(e.getPlayer(), gm.getPermissionPrefix() + "island.limit.", islandId, gm.getDescription().getName());
+ }
+ });
+ }
+
+ private boolean checkPerms(Player player, String permissionPrefix, String islandId, String gameMode) {
+ IslandBlockCount ibc = addon.getBlockLimitListener().getIsland(islandId);
+ int limit = -1;
+ for (PermissionAttachmentInfo perms : player.getEffectivePermissions()) {
+ if (perms.getPermission().startsWith(permissionPrefix)) {
+ // Get the Material
+ String[] split = perms.getPermission().split("\\.");
+ if (split.length != 5) {
+ logError(player.getName(), perms.getPermission(), "format must be " + permissionPrefix + "MATERIAL.NUMBER");
+ return false;
+ }
+ Material m = Material.getMaterial(split[3].toUpperCase(Locale.ENGLISH));
+ if (m == null) {
+ logError(player.getName(), perms.getPermission(), split[3].toUpperCase(Locale.ENGLISH) + " is not a valid material");
+ return false;
+ }
+ // Get the max value should there be more than one
+ if (perms.getPermission().contains(permissionPrefix + ".*")) {
+ logError(player.getName(), perms.getPermission(), "wildcards are not allowed");
+ return false;
+ }
+ if (!NumberUtils.isDigits(split[4])) {
+ logError(player.getName(), perms.getPermission(), "the last part MUST be a number!");
+ } else {
+ limit = Math.max(limit, Integer.valueOf(split[4]));
+ // Set the limit
+ if (ibc == null) {
+ ibc = new IslandBlockCount(islandId, gameMode);
+ }
+ ibc.setBlockLimit(m, limit);
+ }
+ }
+ }
+ // If any changes have been made then store it
+ if (ibc != null) {
+ addon.getBlockLimitListener().setIsland(islandId, ibc);
+ }
+ return true;
+
+ }
+
+ private void logError(String name, String perm, String error) {
+ addon.logError("Player " + name + " has permission: '" + perm + " but " + error + " Ignoring...");
+ }
+
+}
diff --git a/src/main/java/bentobox/addon/limits/objects/IslandBlockCount.java b/src/main/java/bentobox/addon/limits/objects/IslandBlockCount.java
index 25e6f54..73ae1ba 100644
--- a/src/main/java/bentobox/addon/limits/objects/IslandBlockCount.java
+++ b/src/main/java/bentobox/addon/limits/objects/IslandBlockCount.java
@@ -21,14 +21,21 @@ public class IslandBlockCount implements DataObject {
@Expose
private String uniqueId = "";
+ @Expose
+ private String gameMode = "";
+
@Expose
private Map blockCount = new HashMap<>();
+ @Expose
+ private Map blockLimits = new HashMap<>();
+
// Required for YAML database
public IslandBlockCount() {}
- public IslandBlockCount(String uniqueId2) {
+ public IslandBlockCount(String uniqueId2, String gameMode2) {
this.uniqueId = uniqueId2;
+ this.gameMode = gameMode2;
}
/* (non-Javadoc)
@@ -87,4 +94,68 @@ public class IslandBlockCount implements DataObject {
public boolean isAtLimit(Material material, int limit) {
return blockCount.getOrDefault(material, 0) >= limit;
}
+
+ /**
+ * Check if no more of this material can be added to this island
+ * @param m - material
+ * @return true if no more material can be added
+ */
+ public boolean isAtLimit(Material m) {
+ // Check island limits first
+ return blockLimits.containsKey(m) ? blockCount.getOrDefault(m, 0) >= blockLimits.get(m) : false;
+ }
+
+ public boolean isBlockLimited(Material m) {
+ return blockLimits.containsKey(m);
+ }
+
+ /**
+ * @return the blockLimits
+ */
+ public Map getBlockLimits() {
+ return blockLimits;
+ }
+
+ /**
+ * @param blockLimits the blockLimits to set
+ */
+ public void setBlockLimits(Map blockLimits) {
+ this.blockLimits = blockLimits;
+ }
+
+ /**
+ * Get the block limit for this material for this island
+ * @param m - material
+ * @return limit or -1 for unlimited
+ */
+ public Integer getBlockLimit(Material m) {
+ return blockLimits.getOrDefault(m, -1);
+ }
+
+ /**
+ * Set the block limit for this material for this island
+ * @param m - material
+ * @param limit - maximum number allowed
+ */
+ public void setBlockLimit(Material m, int limit) {
+ blockLimits.put(m, limit);
+ }
+
+ /**
+ * @return the gameMode
+ */
+ public String getGameMode() {
+ return gameMode;
+ }
+
+ public boolean isGameMode(String gameMode) {
+ return this.gameMode.equals(gameMode);
+ }
+
+ /**
+ * @param gameMode the gameMode to set
+ */
+ public void setGameMode(String gameMode) {
+ this.gameMode = gameMode;
+ }
}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 7fa00c8..036b1c2 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -1,3 +1,9 @@
+# Game Modes
+gamemodes:
+- AcidIsland
+- BSkyBlock
+- CaveBock
+
# General block limiting
# Use this section to limit how many blocks can be added to an island.
# 0 means the item will be blocked from placement completely.