diff --git a/src/main/java/com/intellectualcrafters/plot/PS.java b/src/main/java/com/intellectualcrafters/plot/PS.java index f14f890f1..3e969f115 100644 --- a/src/main/java/com/intellectualcrafters/plot/PS.java +++ b/src/main/java/com/intellectualcrafters/plot/PS.java @@ -1119,6 +1119,7 @@ public class PS { FlagManager.addFlag(new AbstractFlag("place", new FlagValue.PlotBlockListValue())); FlagManager.addFlag(new AbstractFlag("break", new FlagValue.PlotBlockListValue())); FlagManager.addFlag(new AbstractFlag("use", new FlagValue.PlotBlockListValue())); + FlagManager.addFlag(new AbstractFlag("blocked-cmds", new FlagValue.StringListValue())); FlagManager.addFlag(new AbstractFlag("gamemode") { public String parseValueRaw(final String value) { diff --git a/src/main/java/com/intellectualcrafters/plot/config/C.java b/src/main/java/com/intellectualcrafters/plot/config/C.java index 43c07a10a..096fd1670 100644 --- a/src/main/java/com/intellectualcrafters/plot/config/C.java +++ b/src/main/java/com/intellectualcrafters/plot/config/C.java @@ -104,6 +104,9 @@ public enum C { WORLDEDIT_BYPASS("$2&oTo bypass your restrictions use $4/plot wea", "WorldEdit Masks"), WORLDEDIT_UNMASKED("$1Your WorldEdit is now unrestricted.", "WorldEdit Masks"), WORLDEDIT_RESTRICTED("$1Your WorldEdit is now restricted.", "WorldEdit Masks"), + + GAMEMODE_WAS_BYPASSED("$1You bypassed the gamemode ($2{gamemode}$1) $1set for this plot", "Gamemode"), + HEIGHT_LIMIT("$1This plot world has a height limit of $2{limit}", "Height Limit"), /* * Records */ @@ -159,6 +162,8 @@ public enum C { */ TOGGLE_ENABLED("$2Enabled setting: %s", "Toggle"), TOGGLE_DISABLED("$2Disabled setting: %s", "Toggle"), + + COMMAND_BLOCKED("$2That command is not allowed in this plot", "Blocked Command"), /* * Ratings */ diff --git a/src/main/java/com/intellectualcrafters/plot/flag/FlagValue.java b/src/main/java/com/intellectualcrafters/plot/flag/FlagValue.java index cd857da41..e52682ab5 100644 --- a/src/main/java/com/intellectualcrafters/plot/flag/FlagValue.java +++ b/src/main/java/com/intellectualcrafters/plot/flag/FlagValue.java @@ -1,6 +1,7 @@ package com.intellectualcrafters.plot.flag; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -398,7 +399,48 @@ public abstract class FlagValue { } } } - + + @SuppressWarnings("ALL") + public static class StringListValue extends FlagValue> implements ListValue { + + @Override + public String toString(final Object t) { + return StringUtils.join((List) t, ","); + } + + @Override + public List getValue(final Object t) { + return (List) t; + } + + @Override + public List parse(final String t) { + return Arrays.asList(t.split(",")); + } + + @Override + public String getDescription() { + return "Flag value must be a string list"; + } + + @Override + public void add(final Object t, final String value) { + try { + ((List) t).addAll(parse(value)); + } catch (final Exception ignored) {} + } + + @Override + public void remove(final Object t, final String value) { + try { + for (final String item : parse(value)) { + ((List) t).remove(item); + } + } catch (final Exception e) { + } + } + } + public static class DoubleListValue extends FlagValue> implements ListValue { @SuppressWarnings("unchecked") @Override diff --git a/src/main/java/com/intellectualcrafters/plot/listeners/PlayerEvents.java b/src/main/java/com/intellectualcrafters/plot/listeners/PlayerEvents.java index 64dd40956..f208b4da4 100644 --- a/src/main/java/com/intellectualcrafters/plot/listeners/PlayerEvents.java +++ b/src/main/java/com/intellectualcrafters/plot/listeners/PlayerEvents.java @@ -1,13 +1,9 @@ package com.intellectualcrafters.plot.listeners; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.UUID; +import java.util.*; +import java.util.regex.Pattern; +import com.intellectualcrafters.plot.util.*; import org.apache.commons.lang.StringUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -76,6 +72,7 @@ import org.bukkit.event.vehicle.VehicleCreateEvent; import org.bukkit.event.vehicle.VehicleDestroyEvent; import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.StructureGrowEvent; +import org.bukkit.help.HelpTopic; import org.bukkit.inventory.ItemStack; import org.bukkit.projectiles.BlockProjectileSource; import org.bukkit.projectiles.ProjectileSource; @@ -99,15 +96,11 @@ import com.intellectualcrafters.plot.object.PlotManager; import com.intellectualcrafters.plot.object.PlotPlayer; import com.intellectualcrafters.plot.object.PlotWorld; import com.intellectualcrafters.plot.object.StringWrapper; -import com.intellectualcrafters.plot.util.ChunkManager; -import com.intellectualcrafters.plot.util.EventUtil; -import com.intellectualcrafters.plot.util.ExpireManager; -import com.intellectualcrafters.plot.util.MainUtil; -import com.intellectualcrafters.plot.util.Permissions; -import com.intellectualcrafters.plot.util.TaskManager; import com.intellectualcrafters.plot.util.bukkit.BukkitUtil; import com.intellectualcrafters.plot.util.bukkit.UUIDHandler; +import javax.annotation.RegEx; + /** * Player Events involving plots * @@ -289,17 +282,87 @@ public class PlayerEvents extends com.intellectualcrafters.plot.listeners.PlotLi final String message = event.getMessage().toLowerCase().replaceAll("/", ""); String[] split = message.split(" "); PluginCommand cmd = Bukkit.getServer().getPluginCommand(split[0]); - if (cmd != null) { + if (cmd == null) { + if (split[0].equals("plotme") || split[0].equals("ap")) { + final Player player = event.getPlayer(); + if (Settings.USE_PLOTME_ALIAS) { + player.performCommand("plots " + StringUtils.join(Arrays.copyOfRange(split, 1, split.length), " ")); + } else { + MainUtil.sendMessage(BukkitUtil.getPlayer(player), C.NOT_USING_PLOTME); + } + event.setCancelled(true); + } + } + + Player player = event.getPlayer(); + PlotPlayer pp = BukkitUtil.getPlayer(player); + + if (!PS.get().isPlotWorld(BukkitUtil.getWorld(player))) { return; } - if (split[0].equals("plotme") || split[0].equals("ap") || split[0].equals("plotz")) { - final Player player = event.getPlayer(); - if (Settings.USE_PLOTME_ALIAS) { - player.performCommand("plots " + StringUtils.join(Arrays.copyOfRange(split, 1, split.length), " ")); - } else { - MainUtil.sendMessage(BukkitUtil.getPlayer(player), C.NOT_USING_PLOTME); + + final Plot plot = MainUtil.getPlot(BukkitUtil.getLocation(player)); + if (plot == null) { + return; + } + + Flag flag; + if (!player.hasPermission("plots.admin.interact.blockedcommands") && (flag = FlagManager.getPlotFlag(plot, "blocked-cmds")) != null) { + List v = (List) flag.getValue(); + + String msg = event.getMessage().toLowerCase().replaceFirst("/", ""); + + String[] parts = msg.split(" "); + String c = parts[0]; + if (parts[0].contains(":")) { + c = parts[0].split(":")[1]; + msg = msg.replace(parts[0].split(":")[0] + ":", ""); + } + + String l = c; + + List aliases = new ArrayList<>(); + + for (HelpTopic cmdLabel : Bukkit.getServer().getHelpMap().getHelpTopics()) { + if (c.equals(cmdLabel.getName())) { + break; + } + PluginCommand p; + String label = cmdLabel.getName().replaceFirst("/", ""); + if (aliases.contains(label)) { + continue; + } + if ((p = Bukkit.getPluginCommand(label)) != null) { + for (String a : p.getAliases()) { + if (aliases.contains(a)) + continue; + aliases.add(a); + a = a.replaceFirst("/", ""); + if (!a.equals(label) && a.equals(c)) { + c = label; + break; + } + } + } + } + + if (!l.equals(c)) { + msg = msg.replace(l, c); + } + + for (String s : v) { + Pattern pattern; + if (!RegExUtil.compiledPatterns.containsKey(s)) { + RegExUtil.compiledPatterns.put(s, ((pattern = Pattern.compile(s)))); + } else { + pattern = RegExUtil.compiledPatterns.get(s); + } + if (pattern.matcher(msg).matches()) { + MainUtil.sendMessage(pp, C.COMMAND_BLOCKED); + event.setCancelled(true); + return; + } } - event.setCancelled(true); } } @@ -1858,6 +1921,12 @@ public class PlayerEvents extends com.intellectualcrafters.plot.listeners.PlotLi Block block = event.getBlockPlaced(); sendBlockChange(block.getLocation(), block.getType(), block.getData()); } + int temporary; + if (!player.hasPermission("plots.admin.build.heightlimit") && loc.getY() >= (temporary = PS.get().getPlotWorld(world).MAX_BUILD_HEIGHT)) { + event.setCancelled(true); + MainUtil.sendMessage(pp, C.HEIGHT_LIMIT.s().replace("{limit}", "" + temporary)); + return; + } return; } else if (!Permissions.hasPermission(pp, "plots.admin.build.road")) { diff --git a/src/main/java/com/intellectualcrafters/plot/listeners/PlotListener.java b/src/main/java/com/intellectualcrafters/plot/listeners/PlotListener.java index 1d7041b7c..e419dba38 100644 --- a/src/main/java/com/intellectualcrafters/plot/listeners/PlotListener.java +++ b/src/main/java/com/intellectualcrafters/plot/listeners/PlotListener.java @@ -133,7 +133,15 @@ public class PlotListener extends APlotListener { final Flag gamemodeFlag = flags.get("gamemode"); if (gamemodeFlag != null) { - player.setGameMode(getGameMode(gamemodeFlag.getValueString())); + if (!player.hasPermission("plots.gamemode.bypass")) { + player.setGameMode(getGameMode(gamemodeFlag.getValueString())); + } else { + MainUtil.sendMessage( + pp, + C.GAMEMODE_WAS_BYPASSED.s().replace("{plot}", plot.getId().toString()).replace("{gamemode}", gamemodeFlag.getValueString()), + true + ); + } } final Flag flyFlag = flags.get("fly"); if (flyFlag != null) { diff --git a/src/main/java/com/intellectualcrafters/plot/object/PlotWorld.java b/src/main/java/com/intellectualcrafters/plot/object/PlotWorld.java index c542fc78b..e2ca93094 100644 --- a/src/main/java/com/intellectualcrafters/plot/object/PlotWorld.java +++ b/src/main/java/com/intellectualcrafters/plot/object/PlotWorld.java @@ -60,6 +60,7 @@ public abstract class PlotWorld { public final static boolean SPAWN_BREEDING_DEFAULT = false; public final static boolean WORLD_BORDER_DEFAULT = false; public final static int MAX_PLOT_MEMBERS_DEFAULT = 128; + public final static int MAX_BUILD_HEIGHT_DEFAULT = 256; // are plot clusters enabled // require claim in cluster // TODO make this configurable @@ -94,6 +95,7 @@ public abstract class PlotWorld { public int TERRAIN = 0; public boolean HOME_ALLOW_NONMEMBER; public PlotLoc DEFAULT_HOME; + public int MAX_BUILD_HEIGHT; public PlotWorld(final String worldname) { this.worldname = worldname; @@ -149,6 +151,7 @@ public abstract class PlotWorld { this.SELL_PRICE = config.getDouble("economy.prices.sell"); this.PLOT_CHAT = config.getBoolean("chat.enabled"); this.WORLD_BORDER = config.getBoolean("world.border"); + this.MAX_BUILD_HEIGHT = config.getInt("world.max_height"); this.HOME_ALLOW_NONMEMBER = config.getBoolean("home.allow-nonmembers"); String homeDefault = config.getString("home.default"); @@ -229,7 +232,8 @@ public abstract class PlotWorld { options.put("limits.max-members", PlotWorld.MAX_PLOT_MEMBERS_DEFAULT); options.put("home.default", "side"); options.put("home.allow-nonmembers", false); - + options.put("world.max_height", PlotWorld.MAX_BUILD_HEIGHT_DEFAULT); + if (Settings.ENABLE_CLUSTERS && (this.TYPE != 0)) { options.put("generator.terrain", this.TERRAIN); options.put("generator.type", this.TYPE); diff --git a/src/main/java/com/intellectualcrafters/plot/util/RegExUtil.java b/src/main/java/com/intellectualcrafters/plot/util/RegExUtil.java new file mode 100644 index 000000000..230099a92 --- /dev/null +++ b/src/main/java/com/intellectualcrafters/plot/util/RegExUtil.java @@ -0,0 +1,15 @@ +package com.intellectualcrafters.plot.util; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +public class RegExUtil { + + public static Map compiledPatterns; + + static { + compiledPatterns = new HashMap<>(); + } + +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 9cee46022..dafe6edc9 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -123,4 +123,6 @@ permissions: plots.undeny: true plots.kick: true plots.worldedit.bypass: - default: false \ No newline at end of file + default: false + plots.gamemode.bypass: + default: op \ No newline at end of file