diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEvents.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEvents.java index 734816707..2ac326b93 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEvents.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEvents.java @@ -401,6 +401,7 @@ public class PlayerEvents extends PlotListener implements Listener { } if (!plot.getFlag(RedstoneFlag.class)) { event.setCancelled(true); + plot.debug("Prevented comparator update because redstone = false"); } return; } @@ -423,6 +424,7 @@ public class PlayerEvents extends PlotListener implements Listener { } if (plot.getFlag(DisablePhysicsFlag.class)) { event.setCancelled(true); + plot.debug("Prevented block physics because disable-physics = true"); } return; } @@ -460,6 +462,7 @@ public class PlayerEvents extends PlotListener implements Listener { Plot newPlot = area.getOwnedPlotAbs(location); if (!plot.equals(newPlot)) { event.setCancelled(true); + plot.debug("Prevented piston update because of invalid edge piston detection"); return; } } @@ -2959,6 +2962,8 @@ public class PlayerEvents extends PlotListener implements Listener { MainUtil.sendMessage(pp, Captions.NO_PERMISSION_EVENT, Captions.PERMISSION_ADMIN_BUILD_OTHER); event.setCancelled(true); + plot.debug(player.getName() + " could not place " + event.getBlock().getType() + + " because of the place flag"); return; } } else if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { @@ -2973,6 +2978,7 @@ public class PlayerEvents extends PlotListener implements Listener { Block block = event.getBlockPlaced(); if (block.getType().hasGravity()) { sendBlockChange(block.getLocation(), block.getBlockData()); + plot.debug(event.getBlock().getType() + " did not fall because of disable-physics = true"); } } } else if (!Permissions.hasPermission(pp, Captions.PERMISSION_ADMIN_BUILD_ROAD)) { @@ -2991,6 +2997,7 @@ public class PlayerEvents extends PlotListener implements Listener { return; } if (plot.getFlag(InvincibleFlag.class)) { + plot.debug(event.getEntity().getName() + " could not take damage because invincible = true"); event.setCancelled(true); } } @@ -3005,6 +3012,7 @@ public class PlayerEvents extends PlotListener implements Listener { UUID uuid = pp.getUUID(); if (!plot.isAdded(uuid)) { if (!plot.getFlag(ItemDropFlag.class)) { + plot.debug(player.getName() + " could not drop item because of item-drop = false"); event.setCancelled(true); } } @@ -3021,6 +3029,7 @@ public class PlayerEvents extends PlotListener implements Listener { } UUID uuid = pp.getUUID(); if (!plot.isAdded(uuid) && plot.getFlag(DropProtectionFlag.class)) { + plot.debug(player.getName() + " could not pick up item because of drop-protection = true"); event.setCancelled(true); } } @@ -3029,6 +3038,7 @@ public class PlayerEvents extends PlotListener implements Listener { @EventHandler public void onDeath(final PlayerDeathEvent event) { final Plot plot = BukkitUtil.getPlayer(event.getEntity()).getCurrentPlot(); if (plot != null && plot.getFlag(KeepInventoryFlag.class)) { + plot.debug(event.getEntity().getName() + " kept their inventory because of keep-inventory = true"); event.setKeepInventory(true); } } diff --git a/Core/src/main/java/com/plotsquared/core/command/SetCommand.java b/Core/src/main/java/com/plotsquared/core/command/SetCommand.java index c487fb0c0..aede7e779 100644 --- a/Core/src/main/java/com/plotsquared/core/command/SetCommand.java +++ b/Core/src/main/java/com/plotsquared/core/command/SetCommand.java @@ -52,7 +52,7 @@ public abstract class SetCommand extends SubCommand { return false; } } - if (!plot.isOwner(player.getUUID()) && !plot.getTrusted().contains(player.getUUID())) { + if (!plot.isOwner(player.getUUID())) { if (!Permissions.hasPermission(player, CaptionUtility .format(player, Captions.PERMISSION_ADMIN_COMMAND.getTranslated(), getFullId()))) { MainUtil.sendMessage(player, Captions.NO_PERMISSION, CaptionUtility diff --git a/Core/src/main/java/com/plotsquared/core/command/Toggle.java b/Core/src/main/java/com/plotsquared/core/command/Toggle.java index 8bb25014c..c0085fb6c 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Toggle.java +++ b/Core/src/main/java/com/plotsquared/core/command/Toggle.java @@ -47,7 +47,7 @@ public class Toggle extends Command { aliases = {"spy"}, permission = "plots.admin.command.chat", description = "Toggle plot chat spy") - public void chatspy(Command command, PlotPlayer player, String[] args, + public void chatspy(Command command, PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { if (toggle(player, "chatspy")) { @@ -61,7 +61,7 @@ public class Toggle extends Command { aliases = {"we", "wea"}, permission = "plots.worldedit.bypass", description = "Toggle worldedit area restrictions") - public void worldedit(Command command, PlotPlayer player, String[] args, + public void worldedit(Command command, PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { if (toggle(player, "worldedit")) { @@ -74,7 +74,7 @@ public class Toggle extends Command { @CommandDeclaration(command = "chat", permission = "plots.toggle.chat", description = "Toggle plot chat") - public void chat(Command command, PlotPlayer player, String[] args, + public void chat(Command command, PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { if (toggle(player, "chat")) { @@ -87,7 +87,7 @@ public class Toggle extends Command { @CommandDeclaration(command = "clear-confirmation", permission = "plots.admin.command.autoclear", description = "Toggle autoclear confirmation") - public void clearConfirmation(Command command, PlotPlayer player, String[] args, + public void clearConfirmation(Command command, PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { if (toggle(player, "ignoreExpireTask")) { @@ -100,7 +100,7 @@ public class Toggle extends Command { @CommandDeclaration(command = "titles", permission = "plots.toggle.titles", description = "Toggle plot title messages") - public void titles(Command command, PlotPlayer player, String[] args, + public void titles(Command command, PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { if (toggle(player, "disabletitles")) { @@ -113,7 +113,7 @@ public class Toggle extends Command { @CommandDeclaration(command = "time", permission = "plots.toggle.time", description = "Toggle plot time settings") - public void time(Command command, PlotPlayer player, String[] args, + public void time(Command command, PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { if (toggle(player, "disabletime")) { @@ -123,7 +123,21 @@ public class Toggle extends Command { } } - public boolean toggle(PlotPlayer player, String key) { + @CommandDeclaration(command = "debug", + permission = "plots.toggle.debug", + description = "Toggle plot debugging") + public void debug(Command command, PlotPlayer player, String[] args, + RunnableVal3 confirm, + RunnableVal2 whenDone) { + if (toggle(player, "debug")) { + MainUtil.sendMessage(player, Captions.TOGGLE_ENABLED, command.toString()); + } else { + MainUtil.sendMessage(player, Captions.TOGGLE_DISABLED, command.toString()); + } + player.refreshDebug(); + } + + public boolean toggle(PlotPlayer player, String key) { if (player.getAttribute(key)) { player.removeAttribute(key); return true; diff --git a/Core/src/main/java/com/plotsquared/core/configuration/Captions.java b/Core/src/main/java/com/plotsquared/core/configuration/Captions.java index 99123b334..03f08cda9 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Captions.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Captions.java @@ -190,6 +190,7 @@ public enum Captions implements Caption { PERMISSION_BACKUP_LOAD("plots.backup.load", "static.permissions"), PERMISSION_ADMIN_BACKUP_OTHER("plots.admin.backup.other", "static.permissions"), PERMISSION_ADMIN_ALLOW_UNSAFE("plots.admin.unsafe", "static.permissions"), + PERMISSION_ADMIN_DEBUG_OTHER("plots.admin.debug.other", "static.permissions"), // // EXPIRED_CONFIRM("$2Confirmation has expired, please run the command again!", "Confirm"), @@ -803,6 +804,10 @@ public enum Captions implements Caption { SINGLE_AREA_CREATED("$1The area was created successfully!", "Single"), // + // + PLOT_DEBUG("$1Plot Debug ($2%plot%$1): %message%", "Plot-Debug"), + // + /** * Legacy Configuration Conversion */ diff --git a/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java b/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java index 1a4e668c5..568498786 100644 --- a/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java +++ b/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java @@ -56,8 +56,11 @@ import lombok.NonNull; import org.jetbrains.annotations.NotNull; import java.nio.ByteBuffer; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -72,12 +75,17 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer public static final String META_LAST_PLOT = "lastplot"; public static final String META_LOCATION = "location"; + + // Used to track debug mode + private static final Set> debugModeEnabled = Collections.synchronizedSet(new HashSet<>()); + private static final Map converters = new HashMap<>(); private Map metaMap = new HashMap<>(); /** * The metadata map. */ private ConcurrentHashMap meta; + private int hash; public static PlotPlayer from(@NonNull final T object) { if (!converters.containsKey(object.getClass())) { @@ -93,6 +101,19 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer converters.put(clazz, converter); } + public static Collection> getDebugModePlayerInPlot(@NotNull final Plot plot) { + if (debugModeEnabled.isEmpty()) { + return Collections.emptyList(); + } + final Collection> players = new LinkedList<>(); + for (final PlotPlayer player : debugModeEnabled) { + if (player.getCurrentPlot().equals(plot)) { + players.add(player); + } + } + return players; + } + /** * Efficiently wrap a Player, or OfflinePlayer object to get a PlotPlayer (or fetch if it's already cached)
* - Accepts sponge/bukkit Player (online) @@ -519,6 +540,15 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer */ public abstract void kick(String message); + public void refreshDebug() { + final boolean debug = this.getAttribute("debug"); + if (debug && !debugModeEnabled.contains(this)) { + debugModeEnabled.add(this); + } else if (!debug) { + debugModeEnabled.remove(this); + } + } + /** * Called when this player quits. */ @@ -556,6 +586,8 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer } PlotSquared.imp().getPlayerManager().removePlayer(this); PlotSquared.get().IMP.unregister(this); + + debugModeEnabled.remove(this); } /** @@ -603,6 +635,10 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer return; } + if (PlotPlayer.this.getAttribute("debug")) { + debugModeEnabled.add(PlotPlayer.this); + } + if (!Settings.Teleport.ON_LOGIN) { return; } @@ -693,10 +729,27 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer public abstract void stopSpectating(); + public boolean hasDebugMode() { + return this.getAttribute("debug"); + } + + @Override public int hashCode() { + if (this.hash == 0 || this.hash == 485) { + this.hash = 485 + this.getUUID().hashCode(); + } + return this.hash; + } + + @Override public boolean equals(final Object obj) { + if (!(obj instanceof PlotPlayer)) { + return false; + } + final PlotPlayer other = (PlotPlayer) obj; + return this.getUUID().equals(other.getUUID()); + } + /** * The amount of money this Player has. - * - * @return */ public double getMoney() { return EconHandler.manager == null ? 0 : EconHandler.manager.getMoney(this); diff --git a/Core/src/main/java/com/plotsquared/core/plot/Plot.java b/Core/src/main/java/com/plotsquared/core/plot/Plot.java index 5def886a8..85410628c 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/Plot.java +++ b/Core/src/main/java/com/plotsquared/core/plot/Plot.java @@ -2924,6 +2924,21 @@ public class Plot { }, 1); } + public void debug(@NotNull final String message) { + final Collection> players = PlotPlayer.getDebugModePlayerInPlot(this); + if (players.isEmpty()) { + return; + } + final String string = Captions.PLOT_DEBUG.getTranslated().replace("%plot%", this.toString()) + .replace("%message%", message); + for (final PlotPlayer player : players) { + if (isOwner(player.getUUID()) || + Permissions.hasPermission(player, Captions.PERMISSION_ADMIN_DEBUG_OTHER)) { + player.sendMessage(string); + } + } + } + /** * Gets all the corners of the plot (supports non-rectangular shapes). * diff --git a/Core/src/main/java/com/plotsquared/core/util/EntityUtil.java b/Core/src/main/java/com/plotsquared/core/util/EntityUtil.java index 91eb4e99d..9bbc4e1aa 100644 --- a/Core/src/main/java/com/plotsquared/core/util/EntityUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/EntityUtil.java @@ -90,6 +90,7 @@ public final class EntityUtil { if (mobs[i] >= cap) { plot.setMeta("EntityCount", mobs); plot.setMeta("EntityCountTime", System.currentTimeMillis()); + plot.debug("Prevented spawning of mob because it would exceed " + flag.getName()); return true; } } diff --git a/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java b/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java index a5f8add50..4af113ca6 100644 --- a/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java @@ -49,7 +49,7 @@ public abstract class PlayerManager

, T> { * * @param plotPlayer Player to remove */ - public void removePlayer(@NotNull final PlotPlayer plotPlayer) { + public void removePlayer(@NotNull final PlotPlayer plotPlayer) { synchronized (playerLock) { this.playerMap.remove(plotPlayer.getUUID()); }