mirror of
https://github.com/BentoBoxWorld/Limits.git
synced 2024-11-23 02:55:50 +01:00
Added /(admincmd) limitscalc <player> (#14)
* Added /(admincmd) limitscalc <player> * Remove blocks attached to block and redstone torch fix * Removed unnecesary method * Made /(admin) limits calc <player> a subcommand + fix redstone displaying on GUI * Correct player has island check
This commit is contained in:
parent
f4740869da
commit
8248d62a98
@ -26,6 +26,7 @@ public class AdminCommand extends CompositeCommand {
|
||||
public AdminCommand(Limits addon, CompositeCommand parent) {
|
||||
super(parent, "limits");
|
||||
this.addon = addon;
|
||||
new CalcCommand(addon, this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@ -35,8 +36,8 @@ public class AdminCommand extends CompositeCommand {
|
||||
public void setup() {
|
||||
this.setPermission("limits.admin.limits");
|
||||
this.setOnlyPlayer(true);
|
||||
this.setParametersHelp("admin.limits.parameters");
|
||||
this.setDescription("admin.limits.description");
|
||||
this.setParametersHelp("admin.limits.main.parameters");
|
||||
this.setDescription("admin.limits.main.description");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -0,0 +1,81 @@
|
||||
package bentobox.addon.limits.commands;
|
||||
|
||||
import bentobox.addon.limits.Limits;
|
||||
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;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author YellowZaki
|
||||
*/
|
||||
public class CalcCommand extends CompositeCommand {
|
||||
|
||||
private final Limits addon;
|
||||
|
||||
/**
|
||||
* Admin command
|
||||
*
|
||||
* @param addon - addon
|
||||
*/
|
||||
public CalcCommand(Limits addon, CompositeCommand parent) {
|
||||
super(parent, "calc");
|
||||
this.addon = addon;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see world.bentobox.bentobox.api.commands.BentoBoxCommand#setup()
|
||||
*/
|
||||
@Override
|
||||
public void setup() {
|
||||
this.setPermission("limits.admin.limits.calc");
|
||||
this.setOnlyPlayer(false);
|
||||
this.setParametersHelp("admin.limits.calc.parameters");
|
||||
this.setDescription("admin.limits.calc.description");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see world.bentobox.bentobox.api.commands.BentoBoxCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)
|
||||
*/
|
||||
@Override
|
||||
public boolean execute(User user, String label, List<String> args) {
|
||||
if (args.size() == 1) {
|
||||
final UUID playerUUID = getPlugin().getPlayers().getUUID(args.get(0));
|
||||
if (playerUUID == null) {
|
||||
user.sendMessage("general.errors.unknown-player", args.get(0));
|
||||
return true;
|
||||
} else {
|
||||
//Calculate
|
||||
calcLimits(playerUUID, user);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
showHelp(this, user);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void calcLimits(UUID targetPlayer, User sender) {
|
||||
if (addon.getIslands().getIsland(getWorld(), targetPlayer) != null) {
|
||||
new LimitsCalc(getWorld(), getPlugin(), targetPlayer, addon, sender);
|
||||
} else {
|
||||
sender.sendMessage("general.errors.player-has-no-island");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<List<String>> tabComplete(User user, String alias, List<String> 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<String> options = new ArrayList<>(Util.getOnlinePlayerList(user));
|
||||
return Optional.of(Util.tabLimit(options, lastArg));
|
||||
}
|
||||
|
||||
}
|
@ -53,7 +53,12 @@ class LimitPanel {
|
||||
for (Entry<Material, Integer> en : matLimits.entrySet()) {
|
||||
PanelItemBuilder pib = new PanelItemBuilder();
|
||||
pib.name(Util.prettifyText(en.getKey().toString()));
|
||||
if (en.getKey() == Material.REDSTONE_WIRE) {
|
||||
pib.icon(Material.REDSTONE);
|
||||
}
|
||||
else {
|
||||
pib.icon(en.getKey());
|
||||
}
|
||||
int count = ibc == null ? 0 : ibc.getBlockCount().getOrDefault(en.getKey(), 0);
|
||||
String color = count >= en.getValue() ? user.getTranslation("island.limits.max-color") : user.getTranslation("island.limits.regular-color");
|
||||
pib.description(color
|
||||
|
143
src/main/java/bentobox/addon/limits/commands/LimitsCalc.java
Normal file
143
src/main/java/bentobox/addon/limits/commands/LimitsCalc.java
Normal file
@ -0,0 +1,143 @@
|
||||
package bentobox.addon.limits.commands;
|
||||
|
||||
import bentobox.addon.limits.Limits;
|
||||
import bentobox.addon.limits.listeners.BlockLimitsListener;
|
||||
import bentobox.addon.limits.objects.IslandBlockCount;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.ChunkSnapshot;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
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;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author YellowZaki
|
||||
*/
|
||||
public class LimitsCalc {
|
||||
|
||||
private boolean checking;
|
||||
private Limits addon;
|
||||
private BentoBox instance;
|
||||
private World world;
|
||||
private Island island;
|
||||
private BlockLimitsListener bll;
|
||||
private IslandBlockCount ibc;
|
||||
private Map<Material, Integer> blockCount;
|
||||
private BukkitTask task;
|
||||
private User sender;
|
||||
|
||||
|
||||
LimitsCalc(World world, BentoBox instance, UUID targetPlayer, Limits addon, User sender) {
|
||||
this.checking = true;
|
||||
this.addon = addon;
|
||||
this.instance = instance;
|
||||
this.world = world;
|
||||
this.island = instance.getIslands().getIsland(world, targetPlayer);
|
||||
this.bll = addon.getBlockLimitListener();
|
||||
this.ibc = bll.getIsland(island.getUniqueId());
|
||||
blockCount = new HashMap<>();
|
||||
this.sender = sender;
|
||||
Set<Pair<Integer, Integer>> chunksToScan = getChunksToScan(island);
|
||||
this.task = addon.getServer().getScheduler().runTaskTimer(addon.getPlugin(), () -> {
|
||||
Set<ChunkSnapshot> chunkSnapshot = new HashSet<>();
|
||||
if (checking) {
|
||||
Iterator<Pair<Integer, Integer>> it = chunksToScan.iterator();
|
||||
if (!it.hasNext()) {
|
||||
// Nothing left
|
||||
tidyUp();
|
||||
return;
|
||||
}
|
||||
// Add chunk snapshots to the list
|
||||
while (it.hasNext() && chunkSnapshot.size() < 200) {
|
||||
Pair<Integer, Integer> 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);
|
||||
}
|
||||
|
||||
private void checkChunksAsync(final Set<ChunkSnapshot> 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;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
for (int y = 0; y < island.getCenter().getWorld().getMaxHeight(); y++) {
|
||||
Material blockData = chunk.getBlockType(x, y, z);
|
||||
// Air is free
|
||||
if (!blockData.equals(Material.AIR)) {
|
||||
checkBlock(blockData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkBlock(Material md) {
|
||||
md = bll.fixMaterial(md);
|
||||
// md is limited
|
||||
if (bll.getMaterialLimits(world, island.getUniqueId()).containsKey(md)) {
|
||||
if (!blockCount.containsKey(md)) {
|
||||
blockCount.put(md, 1);
|
||||
} else {
|
||||
blockCount.put(md, blockCount.get(md) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
// Cancel
|
||||
task.cancel();
|
||||
ibc.setBlockCount(blockCount);
|
||||
bll.setIsland(island.getUniqueId(), ibc);
|
||||
sender.sendMessage("admin.limits.calc.finished");
|
||||
}
|
||||
|
||||
}
|
@ -32,6 +32,7 @@ import org.bukkit.event.block.BlockFromToEvent;
|
||||
|
||||
import bentobox.addon.limits.Limits;
|
||||
import bentobox.addon.limits.objects.IslandBlockCount;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import world.bentobox.bentobox.api.events.island.IslandEvent.IslandDeleteEvent;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
@ -107,6 +108,7 @@ public class BlockLimitsListener implements Listener {
|
||||
|
||||
/**
|
||||
* Loads limit map from configuration section
|
||||
*
|
||||
* @param cs - configuration section
|
||||
* @return limit map
|
||||
*/
|
||||
@ -124,6 +126,7 @@ public class BlockLimitsListener implements Listener {
|
||||
return mats;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save the count database completely
|
||||
*/
|
||||
@ -140,6 +143,22 @@ public class BlockLimitsListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onBlock(BlockBreakEvent e) {
|
||||
notify(e, User.getInstance(e.getPlayer()), process(e.getBlock(), false), e.getBlock().getType());
|
||||
// Player breaks a block and there was a redstone dust/repeater/... above
|
||||
if (e.getBlock().getRelative(BlockFace.UP).getType() == Material.REDSTONE_WIRE || e.getBlock().getRelative(BlockFace.UP).getType() == Material.REPEATER || e.getBlock().getRelative(BlockFace.UP).getType() == Material.COMPARATOR || e.getBlock().getRelative(BlockFace.UP).getType() == Material.REDSTONE_TORCH) {
|
||||
process(e.getBlock().getRelative(BlockFace.UP), false);
|
||||
}
|
||||
if (e.getBlock().getRelative(BlockFace.EAST).getType() == Material.REDSTONE_WALL_TORCH) {
|
||||
process(e.getBlock().getRelative(BlockFace.EAST), false);
|
||||
}
|
||||
if (e.getBlock().getRelative(BlockFace.WEST).getType() == Material.REDSTONE_WALL_TORCH) {
|
||||
process(e.getBlock().getRelative(BlockFace.WEST), false);
|
||||
}
|
||||
if (e.getBlock().getRelative(BlockFace.SOUTH).getType() == Material.REDSTONE_WALL_TORCH) {
|
||||
process(e.getBlock().getRelative(BlockFace.SOUTH), false);
|
||||
}
|
||||
if (e.getBlock().getRelative(BlockFace.NORTH).getType() == Material.REDSTONE_WALL_TORCH) {
|
||||
process(e.getBlock().getRelative(BlockFace.NORTH), false);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
@ -216,19 +235,38 @@ public class BlockLimitsListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onBlock(BlockFromToEvent e) {
|
||||
if (e.getBlock().isLiquid()) {
|
||||
if (e.getToBlock().getType() == Material.REDSTONE_WIRE || e.getToBlock().getType() == Material.REPEATER || e.getToBlock().getType() == Material.COMPARATOR || e.getToBlock().getType() == Material.REDSTONE_TORCH || e.getToBlock().getType() == Material.REDSTONE_WALL_TORCH) {
|
||||
process(e.getToBlock(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int process(Block b, boolean add) {
|
||||
return process(b, add, b.getType());
|
||||
}
|
||||
|
||||
// It wouldn't make sense to count REDSTONE_WALL_TORCH and REDSTONE_TORCH as separed limits.
|
||||
public Material fixMaterial(Material b) {
|
||||
if (b == Material.REDSTONE_WALL_TORCH) {
|
||||
return Material.REDSTONE_TORCH;
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a block can be
|
||||
*
|
||||
* @param b - block
|
||||
* @param add - true to add a block, false to remove
|
||||
* @param changeTo - material this block will become
|
||||
* @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())) {
|
||||
if (DO_NOT_COUNT.contains(fixMaterial(b.getType())) || !addon.inGameModeWorld(b.getWorld())) {
|
||||
return -1;
|
||||
}
|
||||
// Check if on island
|
||||
@ -243,24 +281,24 @@ public class BlockLimitsListener implements Listener {
|
||||
saveMap.putIfAbsent(id, 0);
|
||||
if (add) {
|
||||
// Check limit
|
||||
int limit = checkLimit(b.getWorld(), b.getType(), id);
|
||||
int limit = checkLimit(b.getWorld(), fixMaterial(b.getType()), id);
|
||||
if (limit > -1) {
|
||||
return limit;
|
||||
}
|
||||
islandCountMap.get(id).add(b.getType());
|
||||
islandCountMap.get(id).add(fixMaterial(b.getType()));
|
||||
saveMap.merge(id, 1, Integer::sum);
|
||||
} else {
|
||||
if (islandCountMap.containsKey(id)) {
|
||||
// Check for changes
|
||||
if (!changeTo.equals(b.getType()) && changeTo.isBlock() && !DO_NOT_COUNT.contains(changeTo)) {
|
||||
if (!fixMaterial(changeTo).equals(fixMaterial(b.getType())) && fixMaterial(changeTo).isBlock() && !DO_NOT_COUNT.contains(fixMaterial(changeTo))) {
|
||||
// Check limit
|
||||
int limit = checkLimit(b.getWorld(), changeTo, id);
|
||||
int limit = checkLimit(b.getWorld(), fixMaterial(changeTo), id);
|
||||
if (limit > -1) {
|
||||
return limit;
|
||||
}
|
||||
islandCountMap.get(id).add(changeTo);
|
||||
islandCountMap.get(id).add(fixMaterial(changeTo));
|
||||
}
|
||||
islandCountMap.get(id).remove(b.getType());
|
||||
islandCountMap.get(id).remove(fixMaterial(b.getType()));
|
||||
saveMap.merge(id, 1, Integer::sum);
|
||||
}
|
||||
}
|
||||
@ -274,6 +312,7 @@ public class BlockLimitsListener implements Listener {
|
||||
|
||||
/**
|
||||
* Check if this material is at its limit for world on this island
|
||||
*
|
||||
* @param w - world
|
||||
* @param m - material
|
||||
* @param id - island id
|
||||
@ -300,6 +339,7 @@ public class BlockLimitsListener implements Listener {
|
||||
|
||||
/**
|
||||
* Gets an aggregate map of the limits for this island
|
||||
*
|
||||
* @param w - world
|
||||
* @param id - island id
|
||||
* @return map of limits for materials
|
||||
@ -322,6 +362,7 @@ public class BlockLimitsListener implements Listener {
|
||||
|
||||
/**
|
||||
* Removes island from the database
|
||||
*
|
||||
* @param e - island delete event
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
@ -333,9 +374,9 @@ public class BlockLimitsListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the island block count values
|
||||
*
|
||||
* @param islandId - island unique id
|
||||
* @param ibc - island block count
|
||||
*/
|
||||
@ -346,6 +387,7 @@ public class BlockLimitsListener implements Listener {
|
||||
|
||||
/**
|
||||
* Get the island block count
|
||||
*
|
||||
* @param islandId - island unique id
|
||||
* @return island block count or null if there is none yet
|
||||
*/
|
||||
|
@ -9,8 +9,13 @@ limits:
|
||||
|
||||
admin:
|
||||
limits:
|
||||
main:
|
||||
parameters: "<player>"
|
||||
description: "show the island limits for player"
|
||||
calc:
|
||||
parameters: "<player>"
|
||||
description: "recalculate the island limits for player"
|
||||
finished: "&aIsland recalc finished sucessfully!"
|
||||
|
||||
island:
|
||||
limits:
|
||||
|
Loading…
Reference in New Issue
Block a user