2019-12-16 16:47:51 +01:00
|
|
|
package world.bentobox.limits.listeners;
|
2019-02-07 08:20:45 +01:00
|
|
|
|
2022-07-05 19:35:00 +02:00
|
|
|
import java.util.*;
|
2019-02-07 08:20:45 +01:00
|
|
|
|
|
|
|
import org.bukkit.Bukkit;
|
|
|
|
import org.bukkit.Material;
|
|
|
|
import org.bukkit.World;
|
|
|
|
import org.bukkit.block.Block;
|
2019-03-09 09:03:09 +01:00
|
|
|
import org.bukkit.block.BlockFace;
|
2020-10-28 14:25:36 +01:00
|
|
|
import org.bukkit.block.data.BlockData;
|
2020-10-28 14:25:23 +01:00
|
|
|
import org.bukkit.block.data.type.TechnicalPiston;
|
2019-02-07 08:20:45 +01:00
|
|
|
import org.bukkit.configuration.ConfigurationSection;
|
|
|
|
import org.bukkit.event.Cancellable;
|
2019-11-26 03:07:40 +01:00
|
|
|
import org.bukkit.event.Event;
|
2019-02-07 08:20:45 +01:00
|
|
|
import org.bukkit.event.EventHandler;
|
|
|
|
import org.bukkit.event.EventPriority;
|
|
|
|
import org.bukkit.event.Listener;
|
2022-07-05 19:35:00 +02:00
|
|
|
import org.bukkit.event.block.*;
|
2019-02-07 08:20:45 +01:00
|
|
|
import org.bukkit.event.entity.EntityChangeBlockEvent;
|
|
|
|
import org.bukkit.event.entity.EntityExplodeEvent;
|
2019-11-26 03:07:40 +01:00
|
|
|
import org.bukkit.event.player.PlayerInteractEvent;
|
2022-01-02 21:45:16 +01:00
|
|
|
import org.eclipse.jdt.annotation.NonNull;
|
2020-01-11 18:38:45 +01:00
|
|
|
import org.eclipse.jdt.annotation.Nullable;
|
2019-02-07 08:20:45 +01:00
|
|
|
|
2020-12-27 20:11:54 +01:00
|
|
|
import world.bentobox.bentobox.api.events.island.IslandDeleteEvent;
|
2019-02-07 08:20:45 +01:00
|
|
|
import world.bentobox.bentobox.api.localization.TextVariables;
|
|
|
|
import world.bentobox.bentobox.api.user.User;
|
|
|
|
import world.bentobox.bentobox.database.Database;
|
2022-01-02 21:45:16 +01:00
|
|
|
import world.bentobox.bentobox.database.objects.Island;
|
2019-02-07 08:20:45 +01:00
|
|
|
import world.bentobox.bentobox.util.Util;
|
2019-12-16 16:47:51 +01:00
|
|
|
import world.bentobox.limits.Limits;
|
|
|
|
import world.bentobox.limits.objects.IslandBlockCount;
|
2019-02-07 08:20:45 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @author tastybento
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public class BlockLimitsListener implements Listener {
|
|
|
|
|
2019-02-09 19:07:16 +01:00
|
|
|
/**
|
|
|
|
* Blocks that are not counted
|
|
|
|
*/
|
2019-02-09 19:30:02 +01:00
|
|
|
private static final List<Material> DO_NOT_COUNT = Arrays.asList(Material.LAVA, Material.WATER, Material.AIR, Material.FIRE, Material.END_PORTAL, Material.NETHER_PORTAL);
|
2019-10-05 22:05:39 +02:00
|
|
|
private static final List<Material> STACKABLE;
|
|
|
|
|
|
|
|
static {
|
|
|
|
List<Material> stackable = new ArrayList<>();
|
|
|
|
stackable.add(Material.SUGAR_CANE);
|
|
|
|
Optional.ofNullable(Material.getMaterial("BAMBOO")).ifPresent(stackable::add);
|
|
|
|
STACKABLE = Collections.unmodifiableList(stackable);
|
|
|
|
}
|
|
|
|
|
2019-02-07 08:20:45 +01:00
|
|
|
/**
|
|
|
|
* Save every 10 blocks of change
|
|
|
|
*/
|
|
|
|
private static final Integer CHANGE_LIMIT = 9;
|
2019-02-09 19:30:02 +01:00
|
|
|
private final Limits addon;
|
|
|
|
private final Map<String, IslandBlockCount> islandCountMap = new HashMap<>();
|
|
|
|
private final Map<String, Integer> saveMap = new HashMap<>();
|
|
|
|
private final Database<IslandBlockCount> handler;
|
|
|
|
private final Map<World, Map<Material, Integer>> worldLimitMap = new HashMap<>();
|
2019-11-08 21:35:47 +01:00
|
|
|
private Map<Material, Integer> defaultLimitMap = new EnumMap<>(Material.class);
|
2019-02-07 08:20:45 +01:00
|
|
|
|
|
|
|
public BlockLimitsListener(Limits addon) {
|
|
|
|
this.addon = addon;
|
|
|
|
handler = new Database<>(addon, IslandBlockCount.class);
|
2019-02-09 07:35:29 +01:00
|
|
|
List<String> toBeDeleted = new ArrayList<>();
|
|
|
|
handler.loadObjects().forEach(ibc -> {
|
|
|
|
// Clean up
|
|
|
|
if (addon.isCoveredGameMode(ibc.getGameMode())) {
|
2021-07-29 10:38:45 +02:00
|
|
|
ibc.getBlockCounts().keySet().removeIf(DO_NOT_COUNT::contains);
|
2019-02-09 07:35:29 +01:00
|
|
|
// Store
|
2019-02-09 19:07:16 +01:00
|
|
|
islandCountMap.put(ibc.getUniqueId(), ibc);
|
2019-02-09 07:35:29 +01:00
|
|
|
} else {
|
|
|
|
toBeDeleted.add(ibc.getUniqueId());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
toBeDeleted.forEach(handler::deleteID);
|
2019-02-07 08:20:45 +01:00
|
|
|
loadAllLimits();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Loads the default and world-specific limits
|
|
|
|
*/
|
|
|
|
private void loadAllLimits() {
|
|
|
|
// Load the default limits
|
|
|
|
addon.log("Loading default limits");
|
|
|
|
if (addon.getConfig().isConfigurationSection("blocklimits")) {
|
|
|
|
ConfigurationSection limitConfig = addon.getConfig().getConfigurationSection("blocklimits");
|
2019-11-17 01:23:37 +01:00
|
|
|
defaultLimitMap = loadLimits(Objects.requireNonNull(limitConfig));
|
2019-02-07 08:20:45 +01:00
|
|
|
}
|
2019-02-08 04:39:27 +01:00
|
|
|
|
2019-02-07 08:20:45 +01:00
|
|
|
// Load specific worlds
|
|
|
|
if (addon.getConfig().isConfigurationSection("worlds")) {
|
|
|
|
ConfigurationSection worlds = addon.getConfig().getConfigurationSection("worlds");
|
2019-11-17 01:23:37 +01:00
|
|
|
for (String worldName : Objects.requireNonNull(worlds).getKeys(false)) {
|
2019-02-07 08:20:45 +01:00
|
|
|
World world = Bukkit.getWorld(worldName);
|
2019-02-09 07:35:29 +01:00
|
|
|
if (world != null && addon.inGameModeWorld(world)) {
|
2019-02-07 08:20:45 +01:00
|
|
|
addon.log("Loading limits for " + world.getName());
|
2019-02-09 19:07:16 +01:00
|
|
|
worldLimitMap.putIfAbsent(world, new HashMap<>());
|
2019-02-07 08:20:45 +01:00
|
|
|
ConfigurationSection matsConfig = worlds.getConfigurationSection(worldName);
|
2019-11-17 01:23:37 +01:00
|
|
|
worldLimitMap.put(world, loadLimits(Objects.requireNonNull(matsConfig)));
|
2019-02-07 08:20:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Loads limit map from configuration section
|
2019-02-26 16:35:28 +01:00
|
|
|
*
|
2019-02-07 08:20:45 +01:00
|
|
|
* @param cs - configuration section
|
|
|
|
* @return limit map
|
|
|
|
*/
|
|
|
|
private Map<Material, Integer> loadLimits(ConfigurationSection cs) {
|
2019-11-08 21:35:47 +01:00
|
|
|
Map<Material, Integer> mats = new EnumMap<>(Material.class);
|
2019-02-07 08:20:45 +01:00
|
|
|
for (String material : cs.getKeys(false)) {
|
|
|
|
Material mat = Material.getMaterial(material);
|
2019-02-09 07:35:29 +01:00
|
|
|
if (mat != null && mat.isBlock() && !DO_NOT_COUNT.contains(mat)) {
|
2019-02-07 08:20:45 +01:00
|
|
|
mats.put(mat, cs.getInt(material));
|
|
|
|
addon.log("Limit " + mat + " to " + cs.getInt(material));
|
|
|
|
} else {
|
|
|
|
addon.logError("Material " + material + " is not a valid block. Skipping...");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return mats;
|
|
|
|
}
|
|
|
|
|
2019-02-26 16:35:28 +01:00
|
|
|
|
2019-02-07 08:20:45 +01:00
|
|
|
/**
|
|
|
|
* Save the count database completely
|
|
|
|
*/
|
|
|
|
public void save() {
|
2021-01-22 20:56:42 +01:00
|
|
|
islandCountMap.values().stream().filter(IslandBlockCount::isChanged).forEach(handler::saveObjectAsync);
|
2019-02-07 08:20:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Player-related events
|
2019-11-09 23:46:30 +01:00
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
2019-02-07 08:20:45 +01:00
|
|
|
public void onBlock(BlockPlaceEvent e) {
|
|
|
|
notify(e, User.getInstance(e.getPlayer()), process(e.getBlock(), true), e.getBlock().getType());
|
|
|
|
}
|
|
|
|
|
2019-11-09 23:46:30 +01:00
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
2019-02-07 08:20:45 +01:00
|
|
|
public void onBlock(BlockBreakEvent e) {
|
2019-11-26 03:07:40 +01:00
|
|
|
handleBreak(e, e.getBlock());
|
2019-05-18 18:40:58 +02:00
|
|
|
}
|
|
|
|
|
2019-11-26 03:07:40 +01:00
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
|
|
|
public void onTurtleEggBreak(PlayerInteractEvent e) {
|
2021-12-22 23:37:10 +01:00
|
|
|
if (e.getAction().equals(Action.PHYSICAL) && e.getClickedBlock() != null && e.getClickedBlock().getType().equals(Material.TURTLE_EGG)) {
|
2019-11-26 03:07:40 +01:00
|
|
|
handleBreak(e, e.getClickedBlock());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void handleBreak(Event e, Block b) {
|
2021-02-22 04:02:50 +01:00
|
|
|
if (!addon.inGameModeWorld(b.getWorld())) {
|
|
|
|
return;
|
|
|
|
}
|
2019-09-11 04:01:39 +02:00
|
|
|
Material mat = b.getType();
|
|
|
|
// Check for stackable plants
|
|
|
|
if (STACKABLE.contains(b.getType())) {
|
|
|
|
// Check for blocks above
|
|
|
|
Block block = b;
|
|
|
|
while(block.getRelative(BlockFace.UP).getType().equals(mat) && block.getY() < b.getWorld().getMaxHeight()) {
|
|
|
|
block = block.getRelative(BlockFace.UP);
|
2020-10-28 14:25:36 +01:00
|
|
|
process(block, false);
|
2019-09-11 04:01:39 +02:00
|
|
|
}
|
|
|
|
}
|
2020-10-28 14:25:36 +01:00
|
|
|
process(b, false);
|
2019-02-26 16:35:28 +01:00
|
|
|
// Player breaks a block and there was a redstone dust/repeater/... above
|
2019-05-18 18:40:58 +02:00
|
|
|
if (b.getRelative(BlockFace.UP).getType() == Material.REDSTONE_WIRE || b.getRelative(BlockFace.UP).getType() == Material.REPEATER || b.getRelative(BlockFace.UP).getType() == Material.COMPARATOR || b.getRelative(BlockFace.UP).getType() == Material.REDSTONE_TORCH) {
|
|
|
|
process(b.getRelative(BlockFace.UP), false);
|
2019-02-26 16:35:28 +01:00
|
|
|
}
|
2019-05-18 18:40:58 +02:00
|
|
|
if (b.getRelative(BlockFace.EAST).getType() == Material.REDSTONE_WALL_TORCH) {
|
|
|
|
process(b.getRelative(BlockFace.EAST), false);
|
2019-02-26 16:35:28 +01:00
|
|
|
}
|
2019-05-18 18:40:58 +02:00
|
|
|
if (b.getRelative(BlockFace.WEST).getType() == Material.REDSTONE_WALL_TORCH) {
|
|
|
|
process(b.getRelative(BlockFace.WEST), false);
|
2019-02-26 16:35:28 +01:00
|
|
|
}
|
2019-05-18 18:40:58 +02:00
|
|
|
if (b.getRelative(BlockFace.SOUTH).getType() == Material.REDSTONE_WALL_TORCH) {
|
|
|
|
process(b.getRelative(BlockFace.SOUTH), false);
|
2019-02-26 16:35:28 +01:00
|
|
|
}
|
2019-05-18 18:40:58 +02:00
|
|
|
if (b.getRelative(BlockFace.NORTH).getType() == Material.REDSTONE_WALL_TORCH) {
|
|
|
|
process(b.getRelative(BlockFace.NORTH), false);
|
2019-02-26 16:35:28 +01:00
|
|
|
}
|
2019-02-07 08:20:45 +01:00
|
|
|
}
|
|
|
|
|
2019-08-17 04:55:58 +02:00
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
2019-02-07 08:20:45 +01:00
|
|
|
public void onBlock(BlockMultiPlaceEvent e) {
|
|
|
|
notify(e, User.getInstance(e.getPlayer()), process(e.getBlock(), true), e.getBlock().getType());
|
|
|
|
}
|
|
|
|
|
2022-01-03 01:31:02 +01:00
|
|
|
/**
|
|
|
|
* Cancel the event and notify the user of failure
|
|
|
|
* @param e event
|
|
|
|
* @param user user
|
|
|
|
* @param limit maximum limit allowed
|
|
|
|
* @param m material
|
|
|
|
*/
|
2019-02-07 08:20:45 +01:00
|
|
|
private void notify(Cancellable e, User user, int limit, Material m) {
|
|
|
|
if (limit > -1) {
|
2020-03-28 19:15:29 +01:00
|
|
|
user.notify("block-limits.hit-limit",
|
2019-02-07 08:20:45 +01:00
|
|
|
"[material]", Util.prettifyText(m.toString()),
|
|
|
|
TextVariables.NUMBER, String.valueOf(limit));
|
|
|
|
e.setCancelled(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Non-player events
|
2019-08-17 04:55:58 +02:00
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
2019-02-07 08:20:45 +01:00
|
|
|
public void onBlock(BlockBurnEvent e) {
|
|
|
|
process(e.getBlock(), false);
|
|
|
|
}
|
|
|
|
|
2019-08-17 04:55:58 +02:00
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
2019-02-07 08:20:45 +01:00
|
|
|
public void onBlock(BlockExplodeEvent e) {
|
|
|
|
e.blockList().forEach(b -> process(b, false));
|
|
|
|
}
|
|
|
|
|
2019-08-17 04:55:58 +02:00
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
2019-02-07 08:20:45 +01:00
|
|
|
public void onBlock(BlockFadeEvent e) {
|
|
|
|
process(e.getBlock(), false);
|
|
|
|
}
|
|
|
|
|
2019-08-17 04:55:58 +02:00
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
2019-02-07 08:20:45 +01:00
|
|
|
public void onBlock(BlockFormEvent e) {
|
|
|
|
process(e.getBlock(), true);
|
|
|
|
}
|
|
|
|
|
2019-08-17 04:55:58 +02:00
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
2019-02-07 08:20:45 +01:00
|
|
|
public void onBlock(BlockSpreadEvent e) {
|
|
|
|
process(e.getBlock(), true);
|
|
|
|
}
|
|
|
|
|
2019-08-17 04:55:58 +02:00
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
2019-02-07 08:20:45 +01:00
|
|
|
public void onBlock(EntityBlockFormEvent e) {
|
|
|
|
process(e.getBlock(), true);
|
|
|
|
}
|
|
|
|
|
2022-07-05 19:35:00 +02:00
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
|
|
|
public void onBlock(BlockGrowEvent e) {
|
|
|
|
if (process(e.getNewState().getBlock(), true) > -1) {
|
|
|
|
e.setCancelled(true);
|
|
|
|
e.getBlock().getWorld().getBlockAt(e.getBlock().getLocation()).setBlockData(e.getBlock().getBlockData());
|
|
|
|
} else {
|
|
|
|
process(e.getBlock(), false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-17 04:55:58 +02:00
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
2019-02-07 08:20:45 +01:00
|
|
|
public void onBlock(LeavesDecayEvent e) {
|
|
|
|
process(e.getBlock(), false);
|
|
|
|
}
|
|
|
|
|
2019-08-17 04:55:58 +02:00
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
2019-02-07 08:20:45 +01:00
|
|
|
public void onBlock(EntityExplodeEvent e) {
|
|
|
|
e.blockList().forEach(b -> process(b, false));
|
|
|
|
}
|
|
|
|
|
2019-08-17 04:55:58 +02:00
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
2019-02-07 08:20:45 +01:00
|
|
|
public void onBlock(EntityChangeBlockEvent e) {
|
|
|
|
process(e.getBlock(), false);
|
2019-11-26 03:07:40 +01:00
|
|
|
if (e.getBlock().getType().equals(Material.FARMLAND)) {
|
|
|
|
process(e.getBlock().getRelative(BlockFace.UP), false);
|
|
|
|
}
|
2019-02-07 08:20:45 +01:00
|
|
|
}
|
|
|
|
|
2019-08-17 04:55:58 +02:00
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
2019-02-26 16:35:28 +01:00
|
|
|
public void onBlock(BlockFromToEvent e) {
|
2019-11-09 23:46:30 +01:00
|
|
|
if (e.getBlock().isLiquid()
|
|
|
|
&& (e.getToBlock().getType() == Material.REDSTONE_WIRE
|
|
|
|
|| e.getToBlock().getType() == Material.REPEATER
|
|
|
|
|| e.getToBlock().getType() == Material.COMPARATOR
|
|
|
|
|| e.getToBlock().getType() == Material.REDSTONE_TORCH
|
2019-11-08 21:35:47 +01:00
|
|
|
|| e.getToBlock().getType() == Material.REDSTONE_WALL_TORCH)) {
|
2019-11-09 23:46:30 +01:00
|
|
|
process(e.getToBlock(), false);
|
2019-02-26 16:35:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-27 00:52:56 +01:00
|
|
|
/**
|
|
|
|
* Return equivalents. Maps things like wall materials to their non-wall equivalents
|
|
|
|
* @param b block data
|
|
|
|
* @return material that matches the block data
|
|
|
|
*/
|
2020-10-28 14:25:36 +01:00
|
|
|
public Material fixMaterial(BlockData b) {
|
|
|
|
Material mat = b.getMaterial();
|
2020-12-27 20:11:54 +01:00
|
|
|
|
2020-10-28 14:25:23 +01:00
|
|
|
if (mat == Material.REDSTONE_WALL_TORCH) {
|
2019-02-26 16:35:28 +01:00
|
|
|
return Material.REDSTONE_TORCH;
|
2020-10-28 14:25:23 +01:00
|
|
|
} else if (mat == Material.WALL_TORCH) {
|
2019-09-11 04:01:39 +02:00
|
|
|
return Material.TORCH;
|
2020-10-28 14:25:23 +01:00
|
|
|
} else if (mat == Material.ZOMBIE_WALL_HEAD) {
|
2019-09-11 04:01:39 +02:00
|
|
|
return Material.ZOMBIE_HEAD;
|
2020-10-28 14:25:23 +01:00
|
|
|
} else if (mat == Material.CREEPER_WALL_HEAD) {
|
2019-09-11 04:01:39 +02:00
|
|
|
return Material.CREEPER_HEAD;
|
2020-10-28 14:25:23 +01:00
|
|
|
} else if (mat == Material.PLAYER_WALL_HEAD) {
|
2019-09-11 04:01:39 +02:00
|
|
|
return Material.PLAYER_HEAD;
|
2020-10-28 14:25:23 +01:00
|
|
|
} else if (mat == Material.DRAGON_WALL_HEAD) {
|
2019-09-11 04:01:39 +02:00
|
|
|
return Material.DRAGON_HEAD;
|
2021-12-22 23:37:10 +01:00
|
|
|
} else if (mat == Material.BAMBOO_SAPLING) {
|
|
|
|
return Material.BAMBOO;
|
2020-10-28 14:25:23 +01:00
|
|
|
} else if (mat == Material.PISTON_HEAD || mat == Material.MOVING_PISTON) {
|
2020-10-28 14:25:36 +01:00
|
|
|
TechnicalPiston tp = (TechnicalPiston) b;
|
2020-10-28 14:25:23 +01:00
|
|
|
if (tp.getType() == TechnicalPiston.Type.NORMAL) {
|
|
|
|
return Material.PISTON;
|
|
|
|
} else {
|
|
|
|
return Material.STICKY_PISTON;
|
|
|
|
}
|
2019-02-26 16:35:28 +01:00
|
|
|
}
|
2020-10-28 14:25:23 +01:00
|
|
|
return mat;
|
2020-12-27 20:11:54 +01:00
|
|
|
}
|
|
|
|
|
2019-02-07 08:20:45 +01:00
|
|
|
/**
|
|
|
|
* Check if a block can be
|
2019-02-26 16:35:28 +01:00
|
|
|
*
|
2019-02-07 08:20:45 +01:00
|
|
|
* @param b - block
|
|
|
|
* @param add - true to add a block, false to remove
|
|
|
|
* @return limit amount if over limit, or -1 if no limitation
|
|
|
|
*/
|
2020-10-28 14:25:36 +01:00
|
|
|
private int process(Block b, boolean add) {
|
|
|
|
if (DO_NOT_COUNT.contains(fixMaterial(b.getBlockData())) || !addon.inGameModeWorld(b.getWorld())) {
|
2019-02-09 07:35:29 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2019-02-07 08:20:45 +01:00
|
|
|
// Check if on island
|
|
|
|
return addon.getIslands().getIslandAt(b.getLocation()).map(i -> {
|
|
|
|
String id = i.getUniqueId();
|
2019-02-09 20:13:20 +01:00
|
|
|
String gameMode = addon.getGameModeName(b.getWorld());
|
2019-02-09 07:35:29 +01:00
|
|
|
if (gameMode.isEmpty()) {
|
|
|
|
// Invalid world
|
|
|
|
return -1;
|
|
|
|
}
|
2021-10-17 23:48:35 +02:00
|
|
|
// Ignore the center block - usually bedrock, but for AOneBlock it's the magic block
|
|
|
|
if (addon.getConfig().getBoolean("ignore-center-block", true) && i.getCenter().equals(b.getLocation())) {
|
|
|
|
return -1;
|
|
|
|
}
|
2019-02-09 19:07:16 +01:00
|
|
|
islandCountMap.putIfAbsent(id, new IslandBlockCount(id, gameMode));
|
2019-02-07 08:20:45 +01:00
|
|
|
if (add) {
|
|
|
|
// Check limit
|
2020-10-28 14:25:36 +01:00
|
|
|
int limit = checkLimit(b.getWorld(), fixMaterial(b.getBlockData()), id);
|
2019-02-07 08:20:45 +01:00
|
|
|
if (limit > -1) {
|
|
|
|
return limit;
|
|
|
|
}
|
2020-10-28 14:25:36 +01:00
|
|
|
islandCountMap.get(id).add(fixMaterial(b.getBlockData()));
|
2019-02-07 08:20:45 +01:00
|
|
|
} else {
|
2019-02-09 19:07:16 +01:00
|
|
|
if (islandCountMap.containsKey(id)) {
|
2020-10-28 14:25:36 +01:00
|
|
|
islandCountMap.get(id).remove(fixMaterial(b.getBlockData()));
|
2019-02-07 08:20:45 +01:00
|
|
|
}
|
|
|
|
}
|
2020-09-20 18:07:35 +02:00
|
|
|
updateSaveMap(id);
|
2019-02-07 08:20:45 +01:00
|
|
|
return -1;
|
|
|
|
}).orElse(-1);
|
|
|
|
}
|
|
|
|
|
2020-09-20 18:07:35 +02:00
|
|
|
/**
|
|
|
|
* Removed a block from any island limit count
|
|
|
|
* @param b - block to remove
|
|
|
|
*/
|
|
|
|
public void removeBlock(Block b) {
|
|
|
|
// Get island
|
|
|
|
addon.getIslands().getIslandAt(b.getLocation()).ifPresent(i -> {
|
|
|
|
String id = i.getUniqueId();
|
|
|
|
String gameMode = addon.getGameModeName(b.getWorld());
|
|
|
|
if (gameMode.isEmpty()) {
|
|
|
|
// Invalid world
|
|
|
|
return;
|
|
|
|
}
|
2020-10-28 14:25:36 +01:00
|
|
|
islandCountMap.computeIfAbsent(id, k -> new IslandBlockCount(id, gameMode)).remove(fixMaterial(b.getBlockData()));
|
2020-09-20 18:07:35 +02:00
|
|
|
updateSaveMap(id);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
private void updateSaveMap(String id) {
|
|
|
|
saveMap.putIfAbsent(id, 0);
|
|
|
|
if (saveMap.merge(id, 1, Integer::sum) > CHANGE_LIMIT) {
|
|
|
|
handler.saveObjectAsync(islandCountMap.get(id));
|
|
|
|
saveMap.remove(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-02-07 08:20:45 +01:00
|
|
|
/**
|
|
|
|
* Check if this material is at its limit for world on this island
|
2019-02-26 16:35:28 +01:00
|
|
|
*
|
2019-02-07 08:20:45 +01:00
|
|
|
* @param w - world
|
|
|
|
* @param m - material
|
|
|
|
* @param id - island id
|
2019-02-09 19:07:16 +01:00
|
|
|
* @return limit amount if at limit or -1 if no limit
|
2019-02-07 08:20:45 +01:00
|
|
|
*/
|
2019-02-09 19:30:02 +01:00
|
|
|
private int checkLimit(World w, Material m, String id) {
|
2019-02-09 07:35:29 +01:00
|
|
|
// Check island limits
|
2022-01-03 01:31:02 +01:00
|
|
|
IslandBlockCount ibc = islandCountMap.get(id);
|
|
|
|
if (ibc.isBlockLimited(m)) {
|
|
|
|
return ibc.isAtLimit(m) ? ibc.getBlockLimit(m) + ibc.getBlockLimitOffset(m) : -1;
|
2019-02-09 07:35:29 +01:00
|
|
|
}
|
|
|
|
// Check specific world limits
|
2019-02-09 19:07:16 +01:00
|
|
|
if (worldLimitMap.containsKey(w) && worldLimitMap.get(w).containsKey(m)) {
|
2019-02-07 08:20:45 +01:00
|
|
|
// Material is overridden in world
|
2022-01-03 01:31:02 +01:00
|
|
|
return ibc.isAtLimit(m, worldLimitMap.get(w).get(m)) ? worldLimitMap.get(w).get(m) + ibc.getBlockLimitOffset(m) : -1;
|
2019-02-07 08:20:45 +01:00
|
|
|
}
|
|
|
|
// Check default limit map
|
2022-01-03 01:31:02 +01:00
|
|
|
if (defaultLimitMap.containsKey(m) && ibc.isAtLimit(m, defaultLimitMap.get(m))) {
|
|
|
|
return defaultLimitMap.get(m) + ibc.getBlockLimitOffset(m);
|
2019-02-07 08:20:45 +01:00
|
|
|
}
|
|
|
|
// No limit
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-02-09 19:07:16 +01:00
|
|
|
/**
|
|
|
|
* Gets an aggregate map of the limits for this island
|
2019-02-26 16:35:28 +01:00
|
|
|
*
|
2019-02-09 19:07:16 +01:00
|
|
|
* @param w - world
|
|
|
|
* @param id - island id
|
|
|
|
* @return map of limits for materials
|
|
|
|
*/
|
|
|
|
public Map<Material, Integer> getMaterialLimits(World w, String id) {
|
|
|
|
// Merge limits
|
2019-11-08 21:35:47 +01:00
|
|
|
Map<Material, Integer> result = new EnumMap<>(Material.class);
|
2019-02-09 19:07:16 +01:00
|
|
|
// Default
|
2021-12-22 23:37:10 +01:00
|
|
|
result.putAll(defaultLimitMap);
|
2019-02-09 19:07:16 +01:00
|
|
|
// World
|
|
|
|
if (worldLimitMap.containsKey(w)) {
|
2021-12-22 23:37:10 +01:00
|
|
|
result.putAll(worldLimitMap.get(w));
|
2019-02-09 19:07:16 +01:00
|
|
|
}
|
|
|
|
// Island
|
|
|
|
if (islandCountMap.containsKey(id)) {
|
2022-03-27 13:45:43 +02:00
|
|
|
IslandBlockCount islandBlockCount = islandCountMap.get(id);
|
|
|
|
result.putAll(islandBlockCount.getBlockLimits());
|
|
|
|
|
|
|
|
// Add offsets to the every limit.
|
|
|
|
islandBlockCount.getBlockLimitsOffset().forEach((material, offset) ->
|
|
|
|
result.put(material, result.getOrDefault(material, 0) + offset));
|
2019-02-09 19:07:16 +01:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-02-07 08:20:45 +01:00
|
|
|
/**
|
|
|
|
* Removes island from the database
|
2019-02-26 16:35:28 +01:00
|
|
|
*
|
2019-02-07 08:20:45 +01:00
|
|
|
* @param e - island delete event
|
|
|
|
*/
|
2019-08-17 04:55:58 +02:00
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
2019-02-09 03:34:23 +01:00
|
|
|
public void onIslandDelete(IslandDeleteEvent e) {
|
2019-02-09 19:07:16 +01:00
|
|
|
islandCountMap.remove(e.getIsland().getUniqueId());
|
2019-02-07 08:20:45 +01:00
|
|
|
saveMap.remove(e.getIsland().getUniqueId());
|
2019-02-09 03:34:23 +01:00
|
|
|
if (handler.objectExists(e.getIsland().getUniqueId())) {
|
|
|
|
handler.deleteID(e.getIsland().getUniqueId());
|
|
|
|
}
|
2019-02-07 08:20:45 +01:00
|
|
|
}
|
|
|
|
|
2019-02-09 07:35:29 +01:00
|
|
|
/**
|
|
|
|
* Set the island block count values
|
2019-02-26 16:35:28 +01:00
|
|
|
*
|
2019-02-09 07:35:29 +01:00
|
|
|
* @param islandId - island unique id
|
|
|
|
* @param ibc - island block count
|
|
|
|
*/
|
|
|
|
public void setIsland(String islandId, IslandBlockCount ibc) {
|
2019-02-09 19:07:16 +01:00
|
|
|
islandCountMap.put(islandId, ibc);
|
2020-06-03 02:54:54 +02:00
|
|
|
handler.saveObjectAsync(ibc);
|
2019-02-09 07:35:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the island block count
|
2019-02-26 16:35:28 +01:00
|
|
|
*
|
2019-02-09 07:35:29 +01:00
|
|
|
* @param islandId - island unique id
|
|
|
|
* @return island block count or null if there is none yet
|
|
|
|
*/
|
2020-01-11 18:38:45 +01:00
|
|
|
@Nullable
|
2019-02-09 07:35:29 +01:00
|
|
|
public IslandBlockCount getIsland(String islandId) {
|
2019-02-09 19:07:16 +01:00
|
|
|
return islandCountMap.get(islandId);
|
2019-02-09 07:35:29 +01:00
|
|
|
}
|
|
|
|
|
2022-01-02 21:45:16 +01:00
|
|
|
/**
|
|
|
|
* Get the island block count for island and make one if it does not exist
|
|
|
|
* @param island island
|
|
|
|
* @return island block count
|
|
|
|
*/
|
|
|
|
@NonNull
|
|
|
|
public IslandBlockCount getIsland(Island island) {
|
|
|
|
return islandCountMap.computeIfAbsent(island.getUniqueId(), k -> new IslandBlockCount(k, island.getGameMode()));
|
|
|
|
}
|
|
|
|
|
2019-02-07 08:20:45 +01:00
|
|
|
}
|