2019-12-16 16:47:51 +01:00
|
|
|
package world.bentobox.limits.commands;
|
2019-02-26 16:35:28 +01:00
|
|
|
|
2020-05-01 01:30:34 +02:00
|
|
|
import java.util.EnumMap;
|
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Objects;
|
|
|
|
import java.util.Set;
|
|
|
|
import java.util.UUID;
|
2019-11-17 01:23:37 +01:00
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
import java.util.stream.Collectors;
|
2019-03-13 03:22:41 +01:00
|
|
|
|
2019-11-17 01:23:37 +01:00
|
|
|
import org.bukkit.Bukkit;
|
2019-02-26 16:35:28 +01:00
|
|
|
import org.bukkit.ChunkSnapshot;
|
|
|
|
import org.bukkit.Material;
|
|
|
|
import org.bukkit.World;
|
2020-10-28 14:25:36 +01:00
|
|
|
import org.bukkit.block.data.BlockData;
|
2019-03-13 03:22:41 +01:00
|
|
|
|
2019-02-26 16:35:28 +01:00
|
|
|
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;
|
2019-11-17 01:23:37 +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.listeners.BlockLimitsListener;
|
|
|
|
import world.bentobox.limits.objects.IslandBlockCount;
|
2019-02-26 16:35:28 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
2019-11-17 01:23:37 +01:00
|
|
|
* @author YellowZaki, tastybento
|
2019-02-26 16:35:28 +01:00
|
|
|
*/
|
|
|
|
public class LimitsCalc {
|
|
|
|
|
2019-11-17 01:23:37 +01:00
|
|
|
private final Limits addon;
|
|
|
|
private final World world;
|
|
|
|
private final Island island;
|
|
|
|
private final BlockLimitsListener bll;
|
2019-02-26 16:35:28 +01:00
|
|
|
private IslandBlockCount ibc;
|
2019-11-17 01:23:37 +01:00
|
|
|
private final Map<Material, AtomicInteger> blockCount;
|
|
|
|
private final User sender;
|
|
|
|
private final Set<Pair<Integer, Integer>> chunksToScan;
|
|
|
|
private int count;
|
2020-05-06 01:56:22 +02:00
|
|
|
private int chunksToScanCount;
|
|
|
|
private BentoBox plugin;
|
2019-03-13 03:22:41 +01:00
|
|
|
|
2019-02-26 16:35:28 +01:00
|
|
|
|
2020-05-06 01:56:22 +02:00
|
|
|
/**
|
|
|
|
* Perform a count of all limited blocks or entities on an island
|
|
|
|
* @param world - game world to scan
|
|
|
|
* @param instance - BentoBox
|
|
|
|
* @param targetPlayer - target player's island
|
|
|
|
* @param addon - addon instance
|
|
|
|
* @param sender - requester of the count
|
|
|
|
*/
|
2019-02-26 16:35:28 +01:00
|
|
|
LimitsCalc(World world, BentoBox instance, UUID targetPlayer, Limits addon, User sender) {
|
2020-05-06 01:56:22 +02:00
|
|
|
this.plugin = instance;
|
2019-02-26 16:35:28 +01:00
|
|
|
this.addon = addon;
|
|
|
|
this.island = instance.getIslands().getIsland(world, targetPlayer);
|
|
|
|
this.bll = addon.getBlockLimitListener();
|
|
|
|
this.ibc = bll.getIsland(island.getUniqueId());
|
2019-11-08 21:35:47 +01:00
|
|
|
blockCount = new EnumMap<>(Material.class);
|
2019-02-26 16:35:28 +01:00
|
|
|
this.sender = sender;
|
2019-11-17 01:23:37 +01:00
|
|
|
this.world = world;
|
2019-02-26 16:35:28 +01:00
|
|
|
|
2019-11-17 01:23:37 +01:00
|
|
|
// Get chunks to scan
|
|
|
|
chunksToScan = getChunksToScan(island);
|
|
|
|
count = 0;
|
2020-05-06 01:56:22 +02:00
|
|
|
|
|
|
|
boolean isNether = plugin.getIWM().isNetherGenerate(world) && plugin.getIWM().isNetherIslands(world);
|
|
|
|
boolean isEnd = plugin.getIWM().isEndGenerate(world) && plugin.getIWM().isEndIslands(world);
|
|
|
|
// Calculate how many chunks need to be scanned
|
|
|
|
chunksToScanCount = chunksToScan.size() + (isNether ? chunksToScan.size():0) + (isEnd ? chunksToScan.size():0);
|
|
|
|
chunksToScan.forEach(c -> {
|
|
|
|
asyncScan(world, c);
|
|
|
|
if (isNether) asyncScan(plugin.getIWM().getNetherWorld(world), c);
|
|
|
|
if (isEnd) asyncScan(plugin.getIWM().getEndWorld(world), c);
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void asyncScan(World world2, Pair<Integer, Integer> c) {
|
|
|
|
Util.getChunkAtAsync(world2, c.x, c.z).thenAccept(ch -> {
|
2019-11-17 01:23:37 +01:00
|
|
|
ChunkSnapshot snapShot = ch.getChunkSnapshot();
|
|
|
|
Bukkit.getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> {
|
|
|
|
this.scanChunk(snapShot);
|
|
|
|
count++;
|
2020-05-06 01:56:22 +02:00
|
|
|
if (count == chunksToScanCount) {
|
2019-11-17 01:23:37 +01:00
|
|
|
this.tidyUp();
|
|
|
|
}
|
|
|
|
});
|
2020-05-06 01:56:22 +02:00
|
|
|
});
|
2019-02-26 16:35:28 +01:00
|
|
|
}
|
|
|
|
|
2020-05-06 01:56:22 +02:00
|
|
|
|
|
|
|
|
2019-02-26 16:35:28 +01:00
|
|
|
private void scanChunk(ChunkSnapshot chunk) {
|
|
|
|
for (int x = 0; x < 16; x++) {
|
|
|
|
// Check if the block coordinate is inside the protection zone and if not, don't count it
|
|
|
|
if (chunk.getX() * 16 + x < island.getMinProtectedX() || chunk.getX() * 16 + x >= island.getMinProtectedX() + island.getProtectionRange() * 2) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (int z = 0; z < 16; z++) {
|
|
|
|
// Check if the block coordinate is inside the protection zone and if not, don't count it
|
|
|
|
if (chunk.getZ() * 16 + z < island.getMinProtectedZ() || chunk.getZ() * 16 + z >= island.getMinProtectedZ() + island.getProtectionRange() * 2) {
|
|
|
|
continue;
|
|
|
|
}
|
2019-11-17 01:23:37 +01:00
|
|
|
for (int y = 0; y < Objects.requireNonNull(island.getCenter().getWorld()).getMaxHeight(); y++) {
|
2020-10-28 14:25:36 +01:00
|
|
|
BlockData blockData = chunk.getBlockData(x, y, z);
|
2019-02-26 16:35:28 +01:00
|
|
|
// Air is free
|
2020-10-28 14:25:36 +01:00
|
|
|
if (!blockData.getMaterial().equals(Material.AIR)) {
|
2019-02-26 16:35:28 +01:00
|
|
|
checkBlock(blockData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-28 14:25:36 +01:00
|
|
|
private void checkBlock(BlockData b) {
|
|
|
|
Material md = bll.fixMaterial(b);
|
2019-02-26 16:35:28 +01:00
|
|
|
// md is limited
|
|
|
|
if (bll.getMaterialLimits(world, island.getUniqueId()).containsKey(md)) {
|
|
|
|
if (!blockCount.containsKey(md)) {
|
2019-11-17 01:23:37 +01:00
|
|
|
blockCount.put(md, new AtomicInteger(1));
|
2019-02-26 16:35:28 +01:00
|
|
|
} else {
|
2019-11-17 01:23:37 +01:00
|
|
|
blockCount.get(md).getAndIncrement();
|
2019-02-26 16:35:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private Set<Pair<Integer, Integer>> getChunksToScan(Island island) {
|
|
|
|
Set<Pair<Integer, Integer>> chunkSnapshot = new HashSet<>();
|
|
|
|
for (int x = island.getMinProtectedX(); x < (island.getMinProtectedX() + island.getProtectionRange() * 2 + 16); x += 16) {
|
|
|
|
for (int z = island.getMinProtectedZ(); z < (island.getMinProtectedZ() + island.getProtectionRange() * 2 + 16); z += 16) {
|
|
|
|
Pair<Integer, Integer> pair = new Pair<>(world.getBlockAt(x, 0, z).getChunk().getX(), world.getBlockAt(x, 0, z).getChunk().getZ());
|
|
|
|
chunkSnapshot.add(pair);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return chunkSnapshot;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void tidyUp() {
|
2019-05-25 04:54:48 +02:00
|
|
|
if (ibc == null) {
|
|
|
|
ibc = new IslandBlockCount();
|
|
|
|
}
|
2019-11-17 01:23:37 +01:00
|
|
|
ibc.setBlockCount(blockCount.entrySet().stream()
|
|
|
|
.collect(Collectors.toMap(
|
|
|
|
Map.Entry::getKey,
|
|
|
|
entry -> entry.getValue().get())));
|
2019-02-26 16:35:28 +01:00
|
|
|
bll.setIsland(island.getUniqueId(), ibc);
|
2019-11-17 01:23:37 +01:00
|
|
|
Bukkit.getScheduler().runTask(addon.getPlugin(), () -> sender.sendMessage("admin.limits.calc.finished"));
|
2019-02-26 16:35:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|