diff --git a/pom.xml b/pom.xml index 937765d..312b6c4 100644 --- a/pom.xml +++ b/pom.xml @@ -46,13 +46,13 @@ 2.0.2 1.13.2-R0.1-SNAPSHOT - 1.6.0 + 1.9.0-SNAPSHOT ${build.version}-SNAPSHOT -LOCAL - 1.7.0 + 1.9.0 diff --git a/src/main/java/bentobox/addon/limits/commands/CalcCommand.java b/src/main/java/bentobox/addon/limits/commands/CalcCommand.java index 5e2b07e..1e6f9c5 100644 --- a/src/main/java/bentobox/addon/limits/commands/CalcCommand.java +++ b/src/main/java/bentobox/addon/limits/commands/CalcCommand.java @@ -24,7 +24,7 @@ public class CalcCommand extends CompositeCommand { * @param addon - addon */ public CalcCommand(Limits addon, CompositeCommand parent) { - super(parent, "calc"); + super(parent, "calc", "recount"); this.addon = addon; } @@ -60,7 +60,7 @@ public class CalcCommand extends CompositeCommand { } } - public void calcLimits(UUID targetPlayer, User sender) { + private void calcLimits(UUID targetPlayer, User sender) { if (addon.getIslands().getIsland(getWorld(), targetPlayer) != null) { new LimitsCalc(getWorld(), getPlugin(), targetPlayer, addon, sender); } else { diff --git a/src/main/java/bentobox/addon/limits/commands/LimitPanel.java b/src/main/java/bentobox/addon/limits/commands/LimitPanel.java index 15e39d0..ee85594 100644 --- a/src/main/java/bentobox/addon/limits/commands/LimitPanel.java +++ b/src/main/java/bentobox/addon/limits/commands/LimitPanel.java @@ -2,6 +2,7 @@ package bentobox.addon.limits.commands; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Optional; import java.util.UUID; @@ -58,8 +59,8 @@ public class LimitPanel { .put(Material.BEETROOTS, Material.BEETROOT) .put(Material.REDSTONE_WIRE, Material.REDSTONE); // Block to Material icons - Optional.ofNullable(Material.getMaterial("SWEET_BERRY_BUSH")).ifPresent(material -> builder.put(material, Material.getMaterial("SWEET_BERRIES"))); - Optional.ofNullable(Material.getMaterial("BAMBOO_SAPLING")).ifPresent(material -> builder.put(material, Material.getMaterial("BAMBOO"))); + Optional.ofNullable(Material.getMaterial("SWEET_BERRY_BUSH")).ifPresent(material -> builder.put(material, Objects.requireNonNull(Material.getMaterial("SWEET_BERRIES")))); + Optional.ofNullable(Material.getMaterial("BAMBOO_SAPLING")).ifPresent(material -> builder.put(material, Objects.requireNonNull(Material.getMaterial("BAMBOO")))); B2M = builder.build(); } @@ -105,7 +106,7 @@ public class LimitPanel { addon.getSettings().getLimits().forEach((k,v) -> { PanelItemBuilder pib = new PanelItemBuilder(); pib.name(Util.prettifyText(k.toString())); - Material m = Material.BARRIER; + Material m; try { if (E2M.containsKey(k)) { m = E2M.get(k); diff --git a/src/main/java/bentobox/addon/limits/commands/LimitsCalc.java b/src/main/java/bentobox/addon/limits/commands/LimitsCalc.java index 1a0d105..a652e28 100644 --- a/src/main/java/bentobox/addon/limits/commands/LimitsCalc.java +++ b/src/main/java/bentobox/addon/limits/commands/LimitsCalc.java @@ -1,16 +1,13 @@ package bentobox.addon.limits.commands; -import java.util.EnumMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.UUID; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; import org.bukkit.ChunkSnapshot; import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.scheduler.BukkitTask; import bentobox.addon.limits.Limits; import bentobox.addon.limits.listeners.BlockLimitsListener; @@ -19,71 +16,47 @@ import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.util.Pair; +import world.bentobox.bentobox.util.Util; /** * - * @author YellowZaki + * @author YellowZaki, tastybento */ public class LimitsCalc { - private boolean checking; - private Limits addon; - private World world; - private Island island; - private BlockLimitsListener bll; + private final Limits addon; + private final World world; + private final Island island; + private final BlockLimitsListener bll; private IslandBlockCount ibc; - private Map blockCount; - private BukkitTask task; - private User sender; + private final Map blockCount; + private final User sender; + private final Set> chunksToScan; + private int count; LimitsCalc(World world, BentoBox instance, UUID targetPlayer, Limits addon, User sender) { - this.checking = true; this.addon = addon; - this.world = world; this.island = instance.getIslands().getIsland(world, targetPlayer); this.bll = addon.getBlockLimitListener(); this.ibc = bll.getIsland(island.getUniqueId()); blockCount = new EnumMap<>(Material.class); this.sender = sender; - Set> chunksToScan = getChunksToScan(island); - this.task = addon.getServer().getScheduler().runTaskTimer(addon.getPlugin(), () -> { - Set chunkSnapshot = new HashSet<>(); - if (checking) { - Iterator> it = chunksToScan.iterator(); - if (!it.hasNext()) { - // Nothing left - tidyUp(); - return; - } - // Add chunk snapshots to the list - while (it.hasNext() && chunkSnapshot.size() < 200) { - Pair pair = it.next(); - if (!world.isChunkLoaded(pair.x, pair.z)) { - world.loadChunk(pair.x, pair.z); - chunkSnapshot.add(world.getChunkAt(pair.x, pair.z).getChunkSnapshot()); - world.unloadChunk(pair.x, pair.z); - } else { - chunkSnapshot.add(world.getChunkAt(pair.x, pair.z).getChunkSnapshot()); - } - it.remove(); - } - // Move to next step - checking = false; - checkChunksAsync(chunkSnapshot); - } - }, 0L, 1); - } + this.world = world; - private void checkChunksAsync(final Set chunkSnapshot) { - // Run async task to scan chunks - addon.getServer().getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> { - for (ChunkSnapshot chunk : chunkSnapshot) { - scanChunk(chunk); - } - // Nothing happened, change state - checking = true; - }); + // Get chunks to scan + chunksToScan = getChunksToScan(island); + count = 0; + chunksToScan.forEach(c -> Util.getChunkAtAsync(world, c.x, c.z).thenAccept(ch -> { + ChunkSnapshot snapShot = ch.getChunkSnapshot(); + Bukkit.getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> { + this.scanChunk(snapShot); + count++; + if (count == chunksToScan.size()) { + this.tidyUp(); + } + }); + })); } @@ -98,7 +71,7 @@ public class LimitsCalc { if (chunk.getZ() * 16 + z < island.getMinProtectedZ() || chunk.getZ() * 16 + z >= island.getMinProtectedZ() + island.getProtectionRange() * 2) { continue; } - for (int y = 0; y < island.getCenter().getWorld().getMaxHeight(); y++) { + for (int y = 0; y < Objects.requireNonNull(island.getCenter().getWorld()).getMaxHeight(); y++) { Material blockData = chunk.getBlockType(x, y, z); // Air is free if (!blockData.equals(Material.AIR)) { @@ -114,9 +87,9 @@ public class LimitsCalc { // md is limited if (bll.getMaterialLimits(world, island.getUniqueId()).containsKey(md)) { if (!blockCount.containsKey(md)) { - blockCount.put(md, 1); + blockCount.put(md, new AtomicInteger(1)); } else { - blockCount.put(md, blockCount.get(md) + 1); + blockCount.get(md).getAndIncrement(); } } } @@ -133,14 +106,15 @@ public class LimitsCalc { } private void tidyUp() { - // Cancel - task.cancel(); if (ibc == null) { ibc = new IslandBlockCount(); } - ibc.setBlockCount(blockCount); + ibc.setBlockCount(blockCount.entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + entry -> entry.getValue().get()))); bll.setIsland(island.getUniqueId(), ibc); - sender.sendMessage("admin.limits.calc.finished"); + Bukkit.getScheduler().runTask(addon.getPlugin(), () -> sender.sendMessage("admin.limits.calc.finished")); } } diff --git a/src/main/java/bentobox/addon/limits/listeners/BlockLimitsListener.java b/src/main/java/bentobox/addon/limits/listeners/BlockLimitsListener.java index 4bd1070..c0efac9 100644 --- a/src/main/java/bentobox/addon/limits/listeners/BlockLimitsListener.java +++ b/src/main/java/bentobox/addon/limits/listeners/BlockLimitsListener.java @@ -1,13 +1,6 @@ package bentobox.addon.limits.listeners; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -98,19 +91,19 @@ public class BlockLimitsListener implements Listener { addon.log("Loading default limits"); if (addon.getConfig().isConfigurationSection("blocklimits")) { ConfigurationSection limitConfig = addon.getConfig().getConfigurationSection("blocklimits"); - defaultLimitMap = loadLimits(limitConfig); + defaultLimitMap = loadLimits(Objects.requireNonNull(limitConfig)); } // Load specific worlds if (addon.getConfig().isConfigurationSection("worlds")) { ConfigurationSection worlds = addon.getConfig().getConfigurationSection("worlds"); - for (String worldName : worlds.getKeys(false)) { + for (String worldName : Objects.requireNonNull(worlds).getKeys(false)) { World world = Bukkit.getWorld(worldName); if (world != null && addon.inGameModeWorld(world)) { addon.log("Loading limits for " + world.getName()); worldLimitMap.putIfAbsent(world, new HashMap<>()); ConfigurationSection matsConfig = worlds.getConfigurationSection(worldName); - worldLimitMap.put(world, loadLimits(matsConfig)); + worldLimitMap.put(world, loadLimits(Objects.requireNonNull(matsConfig))); } } } @@ -156,7 +149,7 @@ public class BlockLimitsListener implements Listener { handleBreak(e, e.getPlayer(), e.getBlock()); } - void handleBreak(Cancellable e, Player player, Block b) { + private void handleBreak(Cancellable e, Player player, Block b) { Material mat = b.getType(); // Special handling for crops that can break in different ways if (mat.equals(Material.WHEAT_SEEDS)) { diff --git a/src/main/java/bentobox/addon/limits/listeners/EntityLimitListener.java b/src/main/java/bentobox/addon/limits/listeners/EntityLimitListener.java index 5d30557..23f872b 100644 --- a/src/main/java/bentobox/addon/limits/listeners/EntityLimitListener.java +++ b/src/main/java/bentobox/addon/limits/listeners/EntityLimitListener.java @@ -1,6 +1,9 @@ package bentobox.addon.limits.listeners; +import java.util.Objects; + import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -41,7 +44,7 @@ public class EntityLimitListener implements Listener { } if (addon.getSettings().getLimits().containsKey(e.getVehicle().getType())) { // If someone in that area has the bypass permission, allow the spawning - for (Entity entity : e.getVehicle().getLocation().getWorld().getNearbyEntities(e.getVehicle().getLocation(), 5, 5, 5)) { + for (Entity entity : Objects.requireNonNull(e.getVehicle().getLocation().getWorld()).getNearbyEntities(e.getVehicle().getLocation(), 5, 5, 5)) { if (entity instanceof Player) { Player player = (Player)entity; boolean bypass = (player.isOp() || player.hasPermission(addon.getPlugin().getIWM().getPermissionPrefix(e.getVehicle().getWorld()) + MOD_BYPASS)); @@ -103,7 +106,7 @@ public class EntityLimitListener implements Listener { private boolean checkByPass(Location l) { // If someone in that area has the bypass permission, allow the spawning - for (Entity entity : l.getWorld().getNearbyEntities(l, 5, 5, 5)) { + for (Entity entity : Objects.requireNonNull(l.getWorld()).getNearbyEntities(l, 5, 5, 5)) { if (entity instanceof Player) { Player player = (Player)entity; if (player.isOp() || player.hasPermission(addon.getPlugin().getIWM().getPermissionPrefix(l.getWorld()) + MOD_BYPASS)) { @@ -121,8 +124,9 @@ public class EntityLimitListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlock(HangingPlaceEvent e) { Player player = e.getPlayer(); + if (player == null) return; addon.getIslands().getIslandAt(e.getEntity().getLocation()).ifPresent(island -> { - boolean bypass = player.isOp() || player.hasPermission(addon.getPlugin().getIWM().getPermissionPrefix(e.getEntity().getWorld()) + MOD_BYPASS); + boolean bypass = Objects.requireNonNull(player).isOp() || player.hasPermission(addon.getPlugin().getIWM().getPermissionPrefix(e.getEntity().getWorld()) + MOD_BYPASS); // Check if entity can be hung if (!bypass && !island.isSpawn() && atLimit(island, e.getEntity())) { // Not allowed @@ -143,7 +147,9 @@ public class EntityLimitListener implements Listener { e.setCancelled(true); // If the reason is anything but because of a spawner then tell players within range if (!e.getSpawnReason().equals(SpawnReason.SPAWNER) && !e.getSpawnReason().equals(SpawnReason.NATURAL) && !e.getSpawnReason().equals(SpawnReason.INFECTION) && !e.getSpawnReason().equals(SpawnReason.NETHER_PORTAL) && !e.getSpawnReason().equals(SpawnReason.REINFORCEMENTS) && !e.getSpawnReason().equals(SpawnReason.SLIME_SPLIT)) { - for (Entity ent : e.getLocation().getWorld().getNearbyEntities(e.getLocation(), 5, 5, 5)) { + World w = e.getLocation().getWorld(); + if (w == null) return; + for (Entity ent : w.getNearbyEntities(e.getLocation(), 5, 5, 5)) { if (ent instanceof Player) { User.getInstance(ent).sendMessage("entity-limits.hit-limit", "[entity]", Util.prettifyText(e.getEntityType().toString()), diff --git a/src/main/java/bentobox/addon/limits/listeners/JoinListener.java b/src/main/java/bentobox/addon/limits/listeners/JoinListener.java index c6ca053..d2bea4b 100644 --- a/src/main/java/bentobox/addon/limits/listeners/JoinListener.java +++ b/src/main/java/bentobox/addon/limits/listeners/JoinListener.java @@ -1,6 +1,7 @@ package bentobox.addon.limits.listeners; import java.util.Locale; +import java.util.Objects; import java.util.UUID; import org.apache.commons.lang.math.NumberUtils; @@ -141,8 +142,8 @@ public class JoinListener implements Listener { // Set perm-based limits String prefix = addon.getGameModePermPrefix(world); String name = addon.getGameModeName(world); - if (!prefix.isEmpty() && !name.isEmpty()) { - checkPerms(owner.getPlayer(), prefix + "island.limit.", island.getUniqueId(), name); + if (!prefix.isEmpty() && !name.isEmpty() && owner.getPlayer() != null) { + checkPerms(Objects.requireNonNull(owner.getPlayer()), prefix + "island.limit.", island.getUniqueId(), name); } } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index b7d8d72..41cd928 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -27,7 +27,7 @@ worlds: HOPPER: 11 # Default entity limits within a player's island space (protected area and to island limit). -# A limit of 5 will allow up to 5 entites in over world, 5 in nether and 5 in the end. +# A limit of 5 will allow up to 5 entities in over world, 5 in nether and 5 in the end. # Affects all types of creature spawning. Also includes entities like MINECARTS. # Note: Only the first 49 limited blocks and entities are shown in the limits GUI. entitylimits: diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml index d8eaf98..211b49a 100755 --- a/src/main/resources/locales/en-US.yml +++ b/src/main/resources/locales/en-US.yml @@ -19,7 +19,7 @@ admin: calc: parameters: "" description: "recalculate the island limits for player" - finished: "&aIsland recalc finished sucessfully!" + finished: "&aIsland recalc finished successfully!" island: limits: diff --git a/src/test/java/bentobox/addon/limits/listeners/JoinListenerTest.java b/src/test/java/bentobox/addon/limits/listeners/JoinListenerTest.java index 1d1f45b..a52701b 100644 --- a/src/test/java/bentobox/addon/limits/listeners/JoinListenerTest.java +++ b/src/test/java/bentobox/addon/limits/listeners/JoinListenerTest.java @@ -1,6 +1,3 @@ -/** - * - */ package bentobox.addon.limits.listeners; import static org.mockito.Mockito.mock; @@ -10,6 +7,7 @@ import static org.mockito.Mockito.when; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.times; import java.util.Collections; @@ -24,7 +22,6 @@ import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.permissions.PermissionAttachmentInfo; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -70,11 +67,8 @@ public class JoinListenerTest { @Mock private Island island; - /** - * @throws java.lang.Exception - */ @Before - public void setUp() throws Exception { + public void setUp() { jl = new JoinListener(addon); // Setup addon when(addon.getGameModes()).thenReturn(Collections.singletonList(bskyblock)); @@ -111,13 +105,6 @@ public class JoinListenerTest { when(island.getOwner()).thenReturn(UUID.randomUUID()); } - /** - * @throws java.lang.Exception - */ - @After - public void tearDown() throws Exception { - } - /** * Test method for {@link bentobox.addon.limits.listeners.JoinListener#onNewIsland(world.bentobox.bentobox.api.events.island.IslandEvent)}. */ @@ -157,7 +144,7 @@ public class JoinListenerTest { IslandEvent e = new IslandEvent(island, null, false, null, IslandEvent.Reason.CREATED); jl.onNewIsland(e); verify(island).getWorld(); - verify(owner).getPlayer(); + verify(owner, times(2)).getPlayer(); } /**