diff --git a/PlotSquared/pom.xml b/PlotSquared/pom.xml index 2e2e4be89..515148488 100644 --- a/PlotSquared/pom.xml +++ b/PlotSquared/pom.xml @@ -8,7 +8,7 @@ UTF-8 PlotSquared - 2.9.15 + 2.9.16 PlotSquared jar @@ -16,23 +16,20 @@ src/main/java - . true + + skyblock.template + town.template + ${basedir}/src/main/resources/ + + + false - - plugin.yml - - - LICENSE - - - town.template - - - skyblock.template - - + skyblock.template + town.template + + ${basedir}/src/main/resources/ diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/BukkitMain.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/BukkitMain.java index 2731a76f9..94e0171db 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/BukkitMain.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/BukkitMain.java @@ -39,6 +39,7 @@ import com.intellectualcrafters.plot.listeners.PlotPlusListener; import com.intellectualcrafters.plot.listeners.TNTListener; import com.intellectualcrafters.plot.listeners.WorldEvents; import com.intellectualcrafters.plot.listeners.worldedit.WEListener; +import com.intellectualcrafters.plot.listeners.worldedit.WESubscriber; import com.intellectualcrafters.plot.object.PlotPlayer; import com.intellectualcrafters.plot.titles.AbstractTitle; import com.intellectualcrafters.plot.titles.DefaultTitle; @@ -261,9 +262,8 @@ public class BukkitMain extends JavaPlugin implements Listener, IPlotMain { log("&cPlease use WorldEdit 6+ for masking support"); log("&c - http://builds.enginehub.org/job/worldedit"); } else { - WEListener weClass = new WEListener(); - WorldEdit.getInstance().getEventBus().register(weClass); - getServer().getPluginManager().registerEvents(weClass, this); + getServer().getPluginManager().registerEvents(new WEListener(), this); + WorldEdit.getInstance().getEventBus().register(new WESubscriber()); MainCommand.subCommands.add(new WE_Anywhere()); } } diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/PlotSquared.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/PlotSquared.java index 0d7ad5464..0205052d4 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/PlotSquared.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/PlotSquared.java @@ -795,89 +795,156 @@ public class PlotSquared { config.set("version", VERSION); final Map options = new HashMap<>(); - options.put("teleport.delay", 0); - options.put("auto_update", false); + // Command confirmation options.put("confirmation.clear", Settings.CONFIRM_CLEAR); options.put("confirmation.delete", Settings.CONFIRM_DELETE); options.put("confirmation.unlink", Settings.CONFIRM_UNLINK); + + // Protection options.put("protection.tnt-listener.enabled", Settings.TNT_LISTENER); options.put("protection.piston.falling-blocks", Settings.PISTON_FALLING_BLOCK_CHECK); + + // Clusters options.put("clusters.enabled", Settings.ENABLE_CLUSTERS); - options.put("clear.fastmode", Settings.ENABLE_CLUSTERS); + + // PlotMe options.put("plotme-alias", Settings.USE_PLOTME_ALIAS); options.put("plotme-convert.enabled", Settings.CONVERT_PLOTME); options.put("plotme-convert.cache-uuids", Settings.CACHE_PLOTME); - options.put("claim.max-auto-area", Settings.MAX_AUTO_SIZE); + + // UUID options.put("UUID.offline", Settings.OFFLINE_MODE); options.put("UUID.force-lowercase", Settings.UUID_LOWERCASE); + options.put("uuid.read-from-disk", Settings.UUID_FROM_DISK); + + // Mob stuff options.put("kill_road_mobs", Settings.KILL_ROAD_MOBS_DEFAULT); options.put("mob_pathfinding", Settings.MOB_PATHFINDING_DEFAULT); - options.put("console.color", Settings.CONSOLE_COLOR); - options.put("metrics", true); - options.put("debug", true); + + // Clearing + Expiry options.put("clear.auto.enabled", false); options.put("clear.auto.days", 365); options.put("clear.check-disk", Settings.AUTO_CLEAR_CHECK_DISK); options.put("clear.on.ban", false); - options.put("max_plots", Settings.MAX_PLOTS); + options.put("clear.fastmode", Settings.ENABLE_CLUSTERS); + + // Schematics options.put("schematics.save_path", Settings.SCHEMATIC_SAVE_PATH); + + // Caching options.put("cache.permissions", Settings.PERMISSION_CACHING); + + // Titles options.put("titles", Settings.TITLES); + + // Teleportation options.put("teleport.on_login", Settings.TELEPORT_ON_LOGIN); + options.put("teleport.delay", 0); + + // WorldEdit options.put("worldedit.require-selection-in-mask", Settings.REQUIRE_SELECTION); + options.put("worldedit.max-volume", Settings.WE_MAX_VOLUME); + options.put("worldedit.max-iterations", Settings.WE_MAX_ITERATIONS); + + // Chunk processor options.put("chunk-processor.enabled", Settings.CHUNK_PROCESSOR); options.put("chunk-processor.max-blockstates", Settings.CHUNK_PROCESSOR_MAX_BLOCKSTATES); options.put("chunk-processor.max-entities", Settings.CHUNK_PROCESSOR_MAX_ENTITIES); + + // Comments options.put("comments.notifications.interval", Settings.COMMENT_NOTIFICATION_INTERVAL); + + // Plot limits options.put("global_limit", Settings.GLOBAL_LIMIT); + options.put("max_plots", Settings.MAX_PLOTS); + options.put("claim.max-auto-area", Settings.MAX_AUTO_SIZE); + + // Misc + options.put("console.color", Settings.CONSOLE_COLOR); + options.put("metrics", true); + options.put("debug", true); + options.put("auto_update", false); + for (final Entry node : options.entrySet()) { if (!config.contains(node.getKey())) { config.set(node.getKey(), node.getValue()); } } - Settings.ENABLE_CLUSTERS = config.getBoolean("clusters.enabled"); - Settings.DEBUG = config.getBoolean("debug"); - if (Settings.DEBUG) { - log(C.PREFIX.s() + "&6Debug Mode Enabled (Default). Edit the config to turn this off."); - } - Settings.COMMENT_NOTIFICATION_INTERVAL = config.getInt("comments.notifications.interval"); + // Command confirmation + Settings.CONFIRM_CLEAR = config.getBoolean("confirmation.clear"); + Settings.CONFIRM_DELETE = config.getBoolean("confirmation.delete"); + Settings.CONFIRM_UNLINK = config.getBoolean("confirmation.unlink"); + + // Protection + Settings.TNT_LISTENER = config.getBoolean("protection.tnt-listener.enabled"); + Settings.PISTON_FALLING_BLOCK_CHECK = config.getBoolean("protection.piston.falling-blocks"); + + // Clusters + Settings.ENABLE_CLUSTERS = config.getBoolean("clusters.enabled"); + + // PlotMe + Settings.USE_PLOTME_ALIAS = config.getBoolean("plotme-alias"); + Settings.CONVERT_PLOTME = config.getBoolean("plotme-convert.enabled"); + Settings.CACHE_PLOTME = config.getBoolean("plotme-convert.cache-uuids"); + + // UUID + Settings.OFFLINE_MODE = config.getBoolean("UUID.offline"); + Settings.UUID_LOWERCASE = config.getBoolean("UUID.force-lowercase"); + Settings.UUID_FROM_DISK = config.getBoolean("uuid.read-from-disk"); + + // Mob stuff + Settings.KILL_ROAD_MOBS = config.getBoolean("kill_road_mobs"); + Settings.MOB_PATHFINDING = config.getBoolean("mob_pathf" + "inding"); + + // Clearing + Expiry + Settings.FAST_CLEAR = config.getBoolean("clear.fastmode"); + Settings.AUTO_CLEAR_DAYS = config.getInt("clear.auto.days"); + Settings.AUTO_CLEAR_CHECK_DISK = config.getBoolean("clear.check-disk"); + Settings.AUTO_CLEAR = config.getBoolean("clear.auto.enabled"); + + // Schematics + Settings.SCHEMATIC_SAVE_PATH = config.getString("schematics.save_path"); + + // Caching + Settings.PERMISSION_CACHING = config.getBoolean("cache.permissions"); + + // Titles + Settings.TITLES = config.getBoolean("titles"); + + // Teleportation + Settings.TELEPORT_DELAY = config.getInt("teleport.delay"); + Settings.TELEPORT_ON_LOGIN = config.getBoolean("teleport.on_login"); + + // WorldEdit + Settings.REQUIRE_SELECTION = config.getBoolean("worldedit.require-selection-in-mask"); + Settings.WE_MAX_VOLUME = config.getLong("worldedit.max-volume"); + Settings.WE_MAX_ITERATIONS = config.getLong("worldedit.max-iterations"); + + // Chunk processor Settings.CHUNK_PROCESSOR = config.getBoolean("chunk-processor.enabled"); Settings.CHUNK_PROCESSOR_MAX_BLOCKSTATES = config.getInt("chunk-processor.max-blockstates"); Settings.CHUNK_PROCESSOR_MAX_ENTITIES= config.getInt("chunk-processor.max-entities"); - Settings.TNT_LISTENER = config.getBoolean("protection.tnt-listener.enabled"); - Settings.PISTON_FALLING_BLOCK_CHECK = config.getBoolean("protection.piston.falling-blocks"); - Settings.PERMISSION_CACHING = config.getBoolean("cache.permissions"); - Settings.CONFIRM_CLEAR = config.getBoolean("confirmation.clear"); - Settings.CONFIRM_DELETE = config.getBoolean("confirmation.delete"); - Settings.CONFIRM_UNLINK = config.getBoolean("confirmation.unlink"); - Settings.FAST_CLEAR = config.getBoolean("clear.fastmode"); - Settings.TELEPORT_DELAY = config.getInt("teleport.delay"); - Settings.CONSOLE_COLOR = config.getBoolean("console.color"); - Settings.TELEPORT_ON_LOGIN = config.getBoolean("teleport.on_login"); - Settings.USE_PLOTME_ALIAS = config.getBoolean("plotme-alias"); - Settings.CONVERT_PLOTME = config.getBoolean("plotme-convert.enabled"); - Settings.CACHE_PLOTME = config.getBoolean("plotme-convert.cache-uuids"); - Settings.KILL_ROAD_MOBS = config.getBoolean("kill_road_mobs"); - Settings.MOB_PATHFINDING = config.getBoolean("mob_pathf" + "inding"); - Settings.METRICS = config.getBoolean("metrics"); - Settings.AUTO_CLEAR_DAYS = config.getInt("clear.auto.days"); - Settings.AUTO_CLEAR_CHECK_DISK = config.getBoolean("clear.check-disk"); + // Comments + Settings.COMMENT_NOTIFICATION_INTERVAL = config.getInt("comments.notifications.interval"); + + // Plot limits Settings.MAX_AUTO_SIZE = config.getInt("claim.max-auto-area"); - Settings.AUTO_CLEAR = config.getBoolean("clear.auto.enabled"); - Settings.TITLES = config.getBoolean("titles"); Settings.MAX_PLOTS = config.getInt("max_plots"); if (Settings.MAX_PLOTS > 32767) { log("&c`max_plots` Is set too high! This is a per player setting and does not need to be very large."); Settings.MAX_PLOTS = 32767; } - Settings.SCHEMATIC_SAVE_PATH = config.getString("schematics.save_path"); - Settings.OFFLINE_MODE = config.getBoolean("UUID.offline"); - Settings.UUID_LOWERCASE = config.getBoolean("UUID.force-lowercase"); - Settings.UUID_FROM_DISK = config.getBoolean("uuid.read-from-disk"); - Settings.REQUIRE_SELECTION = config.getBoolean("worldedit.require-selection-in-mask"); Settings.GLOBAL_LIMIT = config.getBoolean("global_limit"); + + // Misc + Settings.DEBUG = config.getBoolean("debug"); + if (Settings.DEBUG) { + log(C.PREFIX.s() + "&6Debug Mode Enabled (Default). Edit the config to turn this off."); + } + Settings.CONSOLE_COLOR = config.getBoolean("console.color"); + Settings.METRICS = config.getBoolean("metrics"); } public static void setupConfigs() { diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/WE_Anywhere.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/WE_Anywhere.java index fd57d2203..06ba35ccf 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/WE_Anywhere.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/commands/WE_Anywhere.java @@ -23,6 +23,8 @@ package com.intellectualcrafters.plot.commands; import com.intellectualcrafters.plot.PlotSquared; import com.intellectualcrafters.plot.config.C; import com.intellectualcrafters.plot.listeners.worldedit.WEListener; +import com.intellectualcrafters.plot.listeners.worldedit.WEManager; +import com.intellectualcrafters.plot.listeners.worldedit.WESubscriber; import com.intellectualcrafters.plot.object.PlotPlayer; import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.Permissions; @@ -39,12 +41,12 @@ public class WE_Anywhere extends SubCommand { return false; } if (Permissions.hasPermission(plr, "plots.worldedit.bypass")) { - if (WEListener.bypass.contains(plr.getName())) { - WEListener.bypass.remove(plr.getName()); + if (WEManager.bypass.contains(plr.getName())) { + WEManager.bypass.remove(plr.getName()); MainUtil.sendMessage(plr, C.WORLDEDIT_RESTRICTED); } else { - WEListener.bypass.add(plr.getName()); + WEManager.bypass.add(plr.getName()); MainUtil.sendMessage(plr, C.WORLDEDIT_UNMASKED); } } diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/config/C.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/config/C.java index 37d8226ef..1666968da 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/config/C.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/config/C.java @@ -86,6 +86,10 @@ public enum C { * WorldEdit masks */ REQUIRE_SELECTION_IN_MASK("$2%s of your selection is not within your plot mask. You can only make edits within your plot."), + WORLDEDIT_VOLUME("$2You cannot select a volume of %current%. The maximum volume you can modify is %max%."), + WORLDEDIT_ITERATIONS("$2You cannot iterate %current% times. The maximum number of iterations allowed is %max%."), + WORLDEDIT_UNSAFE("$2Access to that command has been blocked"), + WORLDEDIT_BYPASS("$2&oTo bypass your restrictions use $3/plot wea"), WORLDEDIT_UNMASKED("$1Your WorldEdit is now unrestricted."), WORLDEDIT_RESTRICTED("$1Your WorldEdit is now restricted."), /* diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/config/Settings.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/config/Settings.java index 57395be97..e12d5a8e4 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/config/Settings.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/config/Settings.java @@ -32,7 +32,6 @@ public class Settings { /** * Default UUID_FECTHING: false */ - public static boolean UUID_FECTHING = false; public static boolean PERMISSION_CACHING = false; public static boolean UUID_FROM_DISK = false; /** @@ -67,6 +66,8 @@ public class Settings { * Default worldedit-require-selection-in-mask: false */ public static boolean REQUIRE_SELECTION = true; + public static long WE_MAX_VOLUME = 500000; + public static long WE_MAX_ITERATIONS = 1000; /** * Default kill road mobs: true */ diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/ChunkListener.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/ChunkListener.java index c8976b10f..e337aa9f5 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/ChunkListener.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/ChunkListener.java @@ -3,10 +3,15 @@ package com.intellectualcrafters.plot.listeners; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.BlockState; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Item; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.ItemSpawnEvent; import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.ChunkUnloadEvent; @@ -27,6 +32,39 @@ public class ChunkListener implements Listener { public void onChunkLoad(ChunkLoadEvent event) { processChunk(event.getChunk(), false); } + + private int count = 0; + private Chunk lastChunk = null; + + @EventHandler + public void onItemSpawn(ItemSpawnEvent event) { + count++; + if (count < Settings.CHUNK_PROCESSOR_MAX_ENTITIES) { + lastChunk = null; + return; + } + Item entity = event.getEntity(); + Chunk chunk = entity.getLocation().getChunk(); + if (chunk == lastChunk) { + event.getEntity().remove(); + event.setCancelled(true); + return; + } + if (!PlotSquared.isPlotWorld(chunk.getWorld().getName())) { + return; + } + Entity[] entities = chunk.getEntities(); + if (entities.length > Settings.CHUNK_PROCESSOR_MAX_ENTITIES) { + PlotSquared.log("[PlotSquared] &cDetected unsafe entity creation (" + (chunk.getX() << 4) + "," + (chunk.getX() << 4) + "). Mitigating threat."); + event.getEntity().remove(); + event.setCancelled(true); + lastChunk = chunk; + } + else { + count = 0; + lastChunk = null; + } + } public void cleanChunk(final Chunk chunk) { TaskManager.index.increment(); @@ -37,7 +75,7 @@ public class ChunkListener implements Listener { if (!chunk.isLoaded()) { Bukkit.getScheduler().cancelTask(TaskManager.tasks.get(currentIndex)); TaskManager.tasks.remove(currentIndex); - PlotSquared.log("&aSuccessfully processed and unloaded chunk!"); + PlotSquared.log("[PlotSquared] &aSuccessfully processed and unloaded chunk!"); chunk.unload(true, true); return; } @@ -45,7 +83,7 @@ public class ChunkListener implements Listener { if (tiles.length == 0) { Bukkit.getScheduler().cancelTask(TaskManager.tasks.get(currentIndex)); TaskManager.tasks.remove(currentIndex); - PlotSquared.log("&aSuccessfully processed and unloaded chunk!"); + PlotSquared.log("[PlotSquared] &aSuccessfully processed and unloaded chunk!"); chunk.unload(true, true); return; } @@ -55,7 +93,7 @@ public class ChunkListener implements Listener { if (i >= tiles.length) { Bukkit.getScheduler().cancelTask(TaskManager.tasks.get(currentIndex)); TaskManager.tasks.remove(currentIndex); - PlotSquared.log("&aSuccessfully processed and unloaded chunk!"); + PlotSquared.log("[PlotSquared] &aSuccessfully processed and unloaded chunk!"); chunk.unload(true, true); return; } @@ -77,11 +115,11 @@ public class ChunkListener implements Listener { for (Entity ent : entities) { ent.remove(); } - PlotSquared.log("&aPlotSquared detected unsafe chunk and processed: " + (chunk.getX() << 4) + "," + (chunk.getX() << 4)); + PlotSquared.log("[PlotSquared] &a detected unsafe chunk and processed: " + (chunk.getX() << 4) + "," + (chunk.getX() << 4)); } if (tiles.length > Settings.CHUNK_PROCESSOR_MAX_BLOCKSTATES) { if (unload) { - PlotSquared.log("&cPlotSquared detected unsafe chunk: " + (chunk.getX() << 4) + "," + (chunk.getX() << 4)); + PlotSquared.log("[PlotSquared] &c detected unsafe chunk: " + (chunk.getX() << 4) + "," + (chunk.getX() << 4)); cleanChunk(chunk); return true; } diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/PlayerEvents.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/PlayerEvents.java index d0e380d0c..8e168fca0 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/PlayerEvents.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/PlayerEvents.java @@ -85,6 +85,7 @@ import com.intellectualcrafters.plot.database.DBFunc; import com.intellectualcrafters.plot.flag.Flag; import com.intellectualcrafters.plot.flag.FlagManager; import com.intellectualcrafters.plot.listeners.worldedit.WEListener; +import com.intellectualcrafters.plot.listeners.worldedit.WEManager; import com.intellectualcrafters.plot.object.BukkitPlayer; import com.intellectualcrafters.plot.object.Location; import com.intellectualcrafters.plot.object.Plot; @@ -460,7 +461,9 @@ public class PlayerEvents extends com.intellectualcrafters.plot.listeners.PlotLi @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public static void onWorldChanged(final PlayerChangedWorldEvent event) { final PlotPlayer player = BukkitUtil.getPlayer(event.getPlayer()); - WEListener.bypass.remove(player.getName()); + if (PlotSquared.worldEdit != null) { + WEManager.bypass.remove(player.getName()); + } ((BukkitPlayer) player).hasPerm = new HashSet<>(); ((BukkitPlayer) player).noPerm = new HashSet<>(); } @@ -1043,7 +1046,9 @@ public class PlayerEvents extends com.intellectualcrafters.plot.listeners.PlotLi public static void onLeave(final PlayerQuitEvent event) { PlotPlayer pp = BukkitUtil.getPlayer(event.getPlayer()); EventUtil.unregisterPlayer(pp); - WEListener.bypass.remove(pp.getName()); + if (PlotSquared.worldEdit != null) { + WEManager.bypass.remove(pp.getName()); + } if (Settings.DELETE_PLOTS_ON_BAN && event.getPlayer().isBanned()) { final Collection plots = PlotSquared.getPlots(pp.getName()).values(); for (final Plot plot : plots) { diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/ProcessedWEExtent.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/ProcessedWEExtent.java index fc23006c6..91f834c88 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/ProcessedWEExtent.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/ProcessedWEExtent.java @@ -76,7 +76,7 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { } } } - if (WEListener.maskContains(mask, location.getBlockX(), location.getBlockZ())) { + if (WEManager.maskContains(mask, location.getBlockX(), location.getBlockZ())) { return super.setBlock(location, block); } return false; @@ -92,7 +92,7 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { Eblocked = true; PlotSquared.log("&cPlotSquared detected unsafe WorldEdit: " + (location.getBlockX()) + "," + (location.getBlockZ())); } - if (WEListener.maskContains(mask, location.getBlockX(), location.getBlockZ())) { + if (WEManager.maskContains(mask, location.getBlockX(), location.getBlockZ())) { return super.createEntity(location, entity); } return null; @@ -100,7 +100,7 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { @Override public boolean setBiome(Vector2D position, BaseBiome biome) { - if (WEListener.maskContains(mask, position.getBlockX(), position.getBlockZ())) { + if (WEManager.maskContains(mask, position.getBlockX(), position.getBlockZ())) { return super.setBiome(position, biome); } return false; diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/WEExtent.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/WEExtent.java index 5bdc38187..1f3eb35c6 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/WEExtent.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/WEExtent.java @@ -24,7 +24,7 @@ public class WEExtent extends AbstractDelegateExtent { @Override public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException { - if (WEListener.maskContains(mask, location.getBlockX(), location.getBlockZ())) { + if (WEManager.maskContains(mask, location.getBlockX(), location.getBlockZ())) { return super.setBlock(location, block); } return false; @@ -32,7 +32,7 @@ public class WEExtent extends AbstractDelegateExtent { @Override public Entity createEntity(Location location, BaseEntity entity) { - if (WEListener.maskContains(mask, location.getBlockX(), location.getBlockZ())) { + if (WEManager.maskContains(mask, location.getBlockX(), location.getBlockZ())) { return super.createEntity(location, entity); } return null; @@ -40,7 +40,7 @@ public class WEExtent extends AbstractDelegateExtent { @Override public boolean setBiome(Vector2D position, BaseBiome biome) { - if (WEListener.maskContains(mask, position.getBlockX(), position.getBlockZ())) { + if (WEManager.maskContains(mask, position.getBlockX(), position.getBlockZ())) { return super.setBiome(position, biome); } return false; diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/WEListener.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/WEListener.java index 0410d5f85..cf100dd69 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/WEListener.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/WEListener.java @@ -7,6 +7,7 @@ import java.util.Set; import java.util.UUID; import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -31,144 +32,250 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.bukkit.selections.Selection; import com.sk89q.worldedit.event.extent.EditSessionEvent; import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.NullExtent; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.eventbus.EventHandler.Priority; import com.sk89q.worldedit.util.eventbus.Subscribe; public class WEListener implements Listener { - public static HashSet bypass = new HashSet<>(); + public final HashSet rad1 = new HashSet<>(Arrays.asList("forestgen", "pumpkins", "drain", "fixwater", "fixlava", "replacenear", "snow", "thaw", "ex", "butcher", "size")); + public final HashSet rad2 = new HashSet<>(Arrays.asList("fill", "fillr", "removenear", "remove")); + public final HashSet rad2_1 = new HashSet<>(Arrays.asList("hcyl", "cyl")); + public final HashSet rad2_2 = new HashSet<>(Arrays.asList("sphere", "pyramid")); + public final HashSet rad2_3 = new HashSet<>(Arrays.asList("brush smooth")); + public final HashSet rad3_1 = new HashSet<>(Arrays.asList("brush gravity")); + public final HashSet rad3_2 = new HashSet<>(Arrays.asList("brush sphere", "brush cylinder")); - final List monitored = Arrays.asList(new String[] { "set", "replace", "overlay", "walls", "outline", "deform", "hollow", "smooth", "move", "stack", "naturalize", "paste", "count", "regen", "copy", "cut", "" }); - public final Set blockedcmds = new HashSet<>(Arrays.asList("/gmask", "//gmask", "/worldedit:gmask")); - public final Set restrictedcmds = new HashSet<>(Arrays.asList("/up", "//up", "/worldedit:up")); + public final HashSet region = new HashSet<>(Arrays.asList("move", "set", "replace", "overlay", "walls", "outline", "deform", "hollow", "smooth", "naturalize", "paste", "count", "distr", "regen", "copy", "cut", "green", "setbiome")); + public final HashSet regionExtend = new HashSet<>(Arrays.asList("stack")); + public final HashSet unregioned = new HashSet<>(Arrays.asList("paste", "redo", "undo", "rotate", "flip", "generate", "schematic", "schem")); + public final HashSet unsafe1 = new HashSet<>(Arrays.asList("cs", ".s", "gmask", "mask", "restore", "snapshot", "delchunks", "listchunks", "sel poly")); + public final HashSet unsafe2 = new HashSet<>(Arrays.asList("sel poly", "worldedit reload")); + public final HashSet restricted = new HashSet<>(Arrays.asList("up")); - @Subscribe(priority=Priority.VERY_EARLY) - public void onEditSession(EditSessionEvent event) { - String world = event.getWorld().getName(); - if (!PlotSquared.isPlotWorld(world)) { - return; - } - Actor actor = event.getActor(); - if (actor != null && actor.isPlayer()) { - String name = actor.getName(); - if (bypass.contains(name)) { - return; - } - - PlotPlayer player = UUIDHandler.getPlayer(actor.getName()); - HashSet mask = getMask(player); - if (mask.size() == 0) { - event.setExtent(new NullExtent()); - return; - } - try { - Region selection = WorldEdit.getInstance().getSession(player.getName()).getSelection(event.getWorld()); - Vector pos1 = selection.getMinimumPoint(); - Vector pos2 = selection.getMaximumPoint(); - RegionWrapper regionSelection = new RegionWrapper(Math.min(pos1.getBlockX(), pos2.getBlockX()), Math.max(pos1.getBlockX(), pos2.getBlockX()), Math.min(pos1.getBlockZ(), pos2.getBlockZ()), Math.max(pos1.getBlockZ(), pos2.getBlockZ())); - if (!regionContains(regionSelection, mask)) { - event.setExtent(new NullExtent()); - return; - } - } catch (IncompleteRegionException e) {} - if (Settings.CHUNK_PROCESSOR) { - event.setExtent(new ProcessedWEExtent(mask, event.getExtent())); - } - else { - event.setExtent(new WEExtent(mask, event.getExtent())); - } - } - } +// public final HashSet allowSingleSlash = new HashSet<>(Arrays.asList("sel", ".s", "cs", "restore", "brush", "fixwater", "fixlava", "up", "worldedit", "mask", "gmask", "snapshot", "schem", "schematic", "remove", "fill", "pumpkins", "forestgen", "removenear", "ex", "butcher", "size", "snow")); - public static boolean maskContains(HashSet mask, int x, int z) { - for (RegionWrapper region : mask) { - if ((x >= region.minX) && (x <= region.maxX) && (z >= region.minZ) && (z <= region.maxZ)) { + public boolean checkCommand(List list, String cmd) { + for (String identifier : list) { + if (("/" + identifier).equals(cmd) || ("//" + identifier).equals(cmd) || ("/worldedit:/" + identifier).equals(cmd) || ("/worldedit:" + identifier).equals(cmd)) { return true; } } return false; } - public static boolean intersects(RegionWrapper region1, RegionWrapper region2) { - if ((region1.minX <= region2.maxX) && (region1.maxX >= region2.minX) && (region1.minZ <= region2.maxZ) && (region1.maxZ >= region2.minZ)) { + public String reduceCmd(String cmd, boolean single) { + if (cmd.startsWith("/worldedit:/")) { + return cmd.substring(12); + } + if (cmd.startsWith("/worldedit:")) { + return cmd.substring(11); + } + if (cmd.startsWith("//")) { + return cmd.substring(2); + } + if (single && cmd.startsWith("/")) { + return cmd.substring(1); + } + return cmd; + } + + public int getInt(String s) { + try { + int max = 0; + String[] split = s.split(","); + for (String rad : split) { + int val = Integer.parseInt(rad); + if (val > max) { + max = val; + } + } + return max; + } + catch (NumberFormatException e) { + e.printStackTrace(); + return 0; + } + } + + public boolean checkVolume(PlotPlayer player, long volume, long max, Cancellable e) { + if (volume > max) { + MainUtil.sendMessage(player, C.WORLDEDIT_VOLUME.s().replaceAll("%current%", volume + "").replaceAll("%max%", max + "")); + e.setCancelled(true); + } + if (Permissions.hasPermission(player, "plots.worldedit.bypass")) { + MainUtil.sendMessage(player, C.WORLDEDIT_BYPASS); + } + return true; + } + + public boolean checkSelection(Player p, PlotPlayer pp, int modifier, long max, Cancellable e) { + final Selection selection = PlotSquared.worldEdit.getSelection(p); + if (selection == null) { return true; } - return false; - } - - public static boolean regionContains(RegionWrapper selection, HashSet mask) { - for (RegionWrapper region : mask) { - if (intersects(region, selection)) { + final BlockVector pos1 = selection.getNativeMinimumPoint().toBlockVector(); + final BlockVector pos2 = selection.getNativeMaximumPoint().toBlockVector(); + HashSet mask = WEManager.getMask(pp); + if (Settings.REQUIRE_SELECTION) { + String arg = null; + if (mask.size() == 0) { + arg = "pos1 + pos2"; + } + if (!WEManager.maskContains(mask, pos1.getBlockX(), pos1.getBlockZ())) { + arg = "pos1"; + } + if (!WEManager.maskContains(mask, pos2.getBlockX(), pos2.getBlockZ())) { + arg = "pos2"; + } + if (arg != null) { + e.setCancelled(true); + MainUtil.sendMessage(pp, C.REQUIRE_SELECTION_IN_MASK, arg); + if (Permissions.hasPermission(pp, "plots.worldedit.bypass")) { + MainUtil.sendMessage(pp, C.WORLDEDIT_BYPASS); + } return true; } } - return false; - } - - public HashSet getMask(PlotPlayer player) { - HashSet regions = new HashSet<>(); - UUID uuid = player.getUUID(); - for (Plot plot : PlotSquared.getPlots(player.getLocation().getWorld()).values()) { - if (!plot.settings.getMerged(0) && !plot.settings.getMerged(3)) { - if (plot.isOwner(uuid) || plot.helpers.contains(uuid)) { - Location pos1 = MainUtil.getPlotBottomLoc(plot.world, plot.id).add(1, 0, 1); - Location pos2 = MainUtil.getPlotTopLoc(plot.world, plot.id); - regions.add(new RegionWrapper(pos1.getX(), pos2.getX(), pos1.getZ(), pos2.getZ())); - } + RegionWrapper region = new RegionWrapper(pos1.getBlockX(), pos2.getBlockX(), pos1.getBlockZ(), pos2.getBlockZ()); + if (!WEManager.regionContains(region, mask)) { + MainUtil.sendMessage(pp, C.REQUIRE_SELECTION_IN_MASK, "pos1 + pos2"); + e.setCancelled(true); + if (Permissions.hasPermission(pp, "plots.worldedit.bypass")) { + MainUtil.sendMessage(pp, C.WORLDEDIT_BYPASS); } + return true; } - return regions; + long volume = Math.abs((pos1.getBlockX() - pos2.getBlockX()) * (pos1.getBlockY() - pos2.getBlockY()) * (pos1.getBlockZ() - pos2.getBlockZ())) * modifier; + return checkVolume(pp, volume, max, e); } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onPlayerCommand(final PlayerCommandPreprocessEvent e) { + public boolean onPlayerCommand(final PlayerCommandPreprocessEvent e) { final Player p = e.getPlayer(); final PlotPlayer pp = BukkitUtil.getPlayer(p); if (!PlotSquared.isPlotWorld(p.getWorld().getName()) || Permissions.hasPermission(pp, "plots.worldedit.bypass")) { - return; + return true; } String cmd = e.getMessage().toLowerCase(); - if (cmd.contains(" ")) { - cmd = cmd.substring(0, cmd.indexOf(" ")); + boolean single = true; + String[] split = cmd.split(" "); + + long maxVolume = Settings.WE_MAX_VOLUME; + long maxIterations = Settings.WE_MAX_ITERATIONS; + + if (WEManager.bypass.contains(pp.getName())) { + return true; } - if (this.restrictedcmds.contains(cmd)) { - final Plot plot = MainUtil.getPlot(pp.getLocation()); - if ((plot == null) || (!plot.isOwner(pp.getUUID()) && !plot.helpers.contains(DBFunc.everyone) && !plot.helpers.contains(pp.getUUID()))) { + if (split.length >= 2) { + String reduced = reduceCmd(split[0], single); + String reduced2 = reduceCmd(split[0] + " " + split[1], single); + if (rad1.contains(reduced)) { + long volume = getInt(split[1]) * 256; + return checkVolume(pp, volume, maxVolume, e); + } + if (rad2.contains(reduced)) { + if (split.length >= 3) { + long volume = getInt(split[2]) * 256; + return checkVolume(pp, volume, maxVolume, e); + } + return true; + } + if (rad2_1.contains(reduced)) { + if (split.length >= 4) { + long volume = getInt(split[2]) * getInt(split[3]); + return checkVolume(pp, volume, maxVolume, e); + } + return true; + } + if (rad2_2.contains(reduced)) { + if (split.length >= 3) { + long radius = getInt(split[2]); + long volume = radius * radius; + return checkVolume(pp, volume, maxVolume, e); + } + return true; + } + if (rad2_3.contains(reduced2)) { + if (split.length >= 3) { + if (split.length == 4) { + int iterations = getInt(split[3]); + if (iterations > maxIterations) { + MainUtil.sendMessage(pp, C.WORLDEDIT_ITERATIONS.s().replaceAll("%current%", iterations + "").replaceAll("%max%", maxIterations + "")); + e.setCancelled(true); + if (Permissions.hasPermission(pp, "plots.worldedit.bypass")) { + MainUtil.sendMessage(pp, C.WORLDEDIT_BYPASS); + } + return true; + } + } + long radius = getInt(split[2]); + long volume = radius * radius; + return checkVolume(pp, volume, maxVolume, e); + } + return true; + } + if (rad3_1.contains(reduced2)) { + if (split.length >= 3) { + int i = 2; + if (split[i].equalsIgnoreCase("-h")) { + i = 3; + } + long radius = getInt(split[i]); + long volume = radius * radius; + return checkVolume(pp, volume, maxVolume, e); + } + return true; + } + if (rad3_2.contains(reduced2)) { + if (split.length >= 4) { + int i = 3; + if (split[i].equalsIgnoreCase("-h")) { + i = 4; + } + long radius = getInt(split[i]); + long volume = radius * radius; + return checkVolume(pp, volume, maxVolume, e); + } + return true; + } + if (unsafe2.contains(reduced)) { + MainUtil.sendMessage(pp, C.WORLDEDIT_UNSAFE); e.setCancelled(true); + if (Permissions.hasPermission(pp, "plots.worldedit.bypass")) { + MainUtil.sendMessage(pp, C.WORLDEDIT_BYPASS); + } + return true; } - return; - } else if (this.blockedcmds.contains(cmd)) { + if (regionExtend.contains(reduced)) { + return checkSelection(p, pp, getInt(split[1]), maxVolume, e); + } + } + String reduced = reduceCmd(split[0], single); + if (unsafe1.contains(reduced)) { + MainUtil.sendMessage(pp, C.WORLDEDIT_UNSAFE); e.setCancelled(true); - return; - } - if (!Settings.REQUIRE_SELECTION) { - return; - } - for (final String c : this.monitored) { - if (cmd.equals("//" + c) || cmd.equals("/" + c) || cmd.equals("/worldedit:/" + c)) { - final Selection selection = PlotSquared.worldEdit.getSelection(p); - if (selection == null) { - return; - } - final BlockVector pos1 = selection.getNativeMinimumPoint().toBlockVector(); - final BlockVector pos2 = selection.getNativeMaximumPoint().toBlockVector(); - - HashSet mask = getMask(pp); - if (mask.size() == 0) { - MainUtil.sendMessage(pp, C.REQUIRE_SELECTION_IN_MASK, "Both points"); - return; - } - if (!maskContains(mask, pos1.getBlockX(), pos1.getBlockZ())) { - e.setCancelled(true); - MainUtil.sendMessage(pp, C.REQUIRE_SELECTION_IN_MASK, "Position 1"); - } - if (!maskContains(mask, pos2.getBlockX(), pos2.getBlockZ())) { - e.setCancelled(true); - MainUtil.sendMessage(pp, C.REQUIRE_SELECTION_IN_MASK, "Position 2"); - } + if (Permissions.hasPermission(pp, "plots.worldedit.bypass")) { + MainUtil.sendMessage(pp, C.WORLDEDIT_BYPASS); } } + if (restricted.contains(reduced)) { + Plot plot = MainUtil.getPlot(pp.getLocation()); + if (plot != null && plot.isAdded(pp.getUUID())) { + return true; + } + e.setCancelled(true); + MainUtil.sendMessage(pp, C.NO_PLOT_PERMS); + if (Permissions.hasPermission(pp, "plots.worldedit.bypass")) { + MainUtil.sendMessage(pp, C.WORLDEDIT_BYPASS); + } + return true; + } + if (region.contains(reduced)) { + return checkSelection(p, pp, 1, maxVolume, e); + } + return true; } } diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/WEManager.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/WEManager.java new file mode 100644 index 000000000..3ce548c36 --- /dev/null +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/WEManager.java @@ -0,0 +1,55 @@ +package com.intellectualcrafters.plot.listeners.worldedit; + +import java.util.HashSet; +import java.util.UUID; + +import com.intellectualcrafters.plot.PlotSquared; +import com.intellectualcrafters.plot.object.Location; +import com.intellectualcrafters.plot.object.Plot; +import com.intellectualcrafters.plot.object.PlotPlayer; +import com.intellectualcrafters.plot.object.RegionWrapper; +import com.intellectualcrafters.plot.util.MainUtil; + +public class WEManager { + public static HashSet bypass = new HashSet<>(); + + public static boolean maskContains(HashSet mask, int x, int z) { + for (RegionWrapper region : mask) { + if ((x >= region.minX) && (x <= region.maxX) && (z >= region.minZ) && (z <= region.maxZ)) { + return true; + } + } + return false; + } + + public static HashSet getMask(PlotPlayer player) { + HashSet regions = new HashSet<>(); + UUID uuid = player.getUUID(); + for (Plot plot : PlotSquared.getPlots(player.getLocation().getWorld()).values()) { + if (!plot.settings.getMerged(0) && !plot.settings.getMerged(3)) { + if (plot.isOwner(uuid) || plot.helpers.contains(uuid)) { + Location pos1 = MainUtil.getPlotBottomLoc(plot.world, plot.id).add(1, 0, 1); + Location pos2 = MainUtil.getPlotTopLoc(plot.world, plot.id); + regions.add(new RegionWrapper(pos1.getX(), pos2.getX(), pos1.getZ(), pos2.getZ())); + } + } + } + return regions; + } + + public static boolean intersects(RegionWrapper region1, RegionWrapper region2) { + if ((region1.minX <= region2.maxX) && (region1.maxX >= region2.minX) && (region1.minZ <= region2.maxZ) && (region1.maxZ >= region2.minZ)) { + return true; + } + return false; + } + + public static boolean regionContains(RegionWrapper selection, HashSet mask) { + for (RegionWrapper region : mask) { + if (intersects(region, selection)) { + return true; + } + } + return false; + } +} diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/WESubscriber.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/WESubscriber.java new file mode 100644 index 000000000..d8fc66a1a --- /dev/null +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/listeners/worldedit/WESubscriber.java @@ -0,0 +1,43 @@ +package com.intellectualcrafters.plot.listeners.worldedit; + +import java.util.HashSet; + +import com.intellectualcrafters.plot.PlotSquared; +import com.intellectualcrafters.plot.config.Settings; +import com.intellectualcrafters.plot.object.PlotPlayer; +import com.intellectualcrafters.plot.object.RegionWrapper; +import com.intellectualcrafters.plot.util.bukkit.UUIDHandler; +import com.sk89q.worldedit.event.extent.EditSessionEvent; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.util.eventbus.EventHandler.Priority; +import com.sk89q.worldedit.util.eventbus.Subscribe; + +public class WESubscriber { + @Subscribe(priority=Priority.VERY_EARLY) + public void onEditSession(EditSessionEvent event) { + String world = event.getWorld().getName(); + if (!PlotSquared.isPlotWorld(world)) { + return; + } + Actor actor = event.getActor(); + if (actor != null && actor.isPlayer()) { + String name = actor.getName(); + if (WEManager.bypass.contains(name)) { + return; + } + + PlotPlayer player = UUIDHandler.getPlayer(actor.getName()); + HashSet mask = WEManager.getMask(player); + if (mask.size() == 0) { + event.setExtent(new NullExtent()); + return; + } + if (Settings.CHUNK_PROCESSOR) { + event.setExtent(new ProcessedWEExtent(mask, event.getExtent())); + } + else { + event.setExtent(new WEExtent(mask, event.getExtent())); + } + } + } +}