diff --git a/pom.xml b/pom.xml
index 43016b8..0c51069 100644
--- a/pom.xml
+++ b/pom.xml
@@ -92,7 +92,7 @@
de.jaschastarke
plib
- 0.1-SNAPSHOT
+ 1.0-SNAPSHOT
@@ -162,17 +162,22 @@
AuthMe
MultiInv
Multiverse-Inventories
+ Vault
http://dev.bukkit.org/server-mods/limited-creative/
de.jaschastarke.minecraft.limitedcreative.Permissions:CONTAINER
- de.jaschastarke.minecraft.limitedcreative.inventories.InventoryPermissions
de.jaschastarke.minecraft.limitedcreative.SwitchGameModePermissions:ALL
+ de.jaschastarke.minecraft.limitedcreative.inventories.InventoryPermissions
+ de.jaschastarke.minecraft.limitedcreative.limits.NoLimitPermissions:PARENT
+ de.jaschastarke.minecraft.limitedcreative.cmdblocker.CmdBlockPermissions:CONTAINER
+ de.jaschastarke.minecraft.limitedcreative.regions.RegionPermissions:REGION
de.jaschastarke.minecraft.limitedcreative.MainCommand
+ de.jaschastarke.minecraft.limitedcreative.regions.RegionsCommand
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/ModCmdBlocker.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/ModCmdBlocker.java
index 06e5dcf..d6effac 100644
--- a/src/main/java/de/jaschastarke/minecraft/limitedcreative/ModCmdBlocker.java
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/ModCmdBlocker.java
@@ -1,11 +1,35 @@
package de.jaschastarke.minecraft.limitedcreative;
import de.jaschastarke.bukkit.lib.CoreModule;
+import de.jaschastarke.minecraft.limitedcreative.cmdblocker.CmdBlockerConfig;
+import de.jaschastarke.minecraft.limitedcreative.cmdblocker.CommandListener;
+import de.jaschastarke.modularize.IModule;
+import de.jaschastarke.modularize.ModuleEntry;
public class ModCmdBlocker extends CoreModule {
+ private CmdBlockerConfig config;
public ModCmdBlocker(LimitedCreative plugin) {
super(plugin);
}
+ @Override
+ public String getName() {
+ return "CmdBlocker";
+ }
+ @Override
+ public void initialize(ModuleEntry entry) {
+ super.initialize(entry);
+ listeners.addListener(new CommandListener(this));
+ config = new CmdBlockerConfig(this, entry);
+ plugin.getPluginConfig().registerSection(config);
+ }
+ @Override
+ public void onEnable() {
+ super.onEnable();
+ getLog().info(plugin.getLocale().trans("basic.loaded.module"));
+ }
+ public CmdBlockerConfig getConfig() {
+ return config;
+ }
}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/ModRegions.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/ModRegions.java
index 7091bf4..c983830 100644
--- a/src/main/java/de/jaschastarke/minecraft/limitedcreative/ModRegions.java
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/ModRegions.java
@@ -1,10 +1,84 @@
package de.jaschastarke.minecraft.limitedcreative;
+import java.io.File;
+
+import org.bukkit.entity.Player;
+
+import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
+
import de.jaschastarke.bukkit.lib.CoreModule;
+import de.jaschastarke.bukkit.lib.commands.AliasHelpedCommand;
+import de.jaschastarke.minecraft.limitedcreative.regions.Flags;
+import de.jaschastarke.minecraft.limitedcreative.regions.PlayerData;
+import de.jaschastarke.minecraft.limitedcreative.regions.RegionConfig;
+import de.jaschastarke.minecraft.limitedcreative.regions.RegionsCommand;
+import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.CustomRegionManager;
+import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.FlagList;
+import de.jaschastarke.modularize.IModule;
+import de.jaschastarke.modularize.ModuleEntry;
+import de.jaschastarke.modularize.ModuleEntry.ModuleState;
public class ModRegions extends CoreModule {
+ private CustomRegionManager mgr;
+ private WorldGuardPlugin wg;
+ private PlayerData pdata;
+ private FeatureBlockItemSpawn blockDrops = null;
+ private RegionConfig config;
+ private RegionsCommand command;
+
public ModRegions(LimitedCreative plugin) {
super(plugin);
}
+
+ @Override
+ public void initialize(ModuleEntry pEntry) {
+ super.initialize(pEntry);
+
+ blockDrops = plugin.getModule(FeatureBlockItemSpawn.class);
+ if (blockDrops == null)
+ blockDrops = plugin.addModule(new FeatureBlockItemSpawn(plugin)).getModule();
+
+ config = plugin.getPluginConfig().registerSection(new RegionConfig(this, entry));
+
+ command = new RegionsCommand(this);
+ plugin.getCommandHandler().registerCommand(command);
+ plugin.getMainCommand().registerCommand(new AliasHelpedCommand(command, "region"));
+
+ FlagList.addFlags(Flags.getList());
+
+ if (!config.getEnabled()) {
+ entry.initialState = ModuleState.DISABLED;
+ return;
+ }
+ }
+
+ @Override
+ public void onEnable() {
+ super.onEnable();
+
+ mgr = new CustomRegionManager(new File(plugin.getDataFolder(), "regions.yml"), this);
+ wg = (WorldGuardPlugin) plugin.getServer().getPluginManager().getPlugin("WorldGuard");
+ pdata = new PlayerData(this);
+ getLog().info(plugin.getLocale().trans("basic.loaded.module"));
+ }
+
+ public RegionConfig getConfig() {
+ return config;
+ }
+ public WorldGuardPlugin getWorldGuard() {
+ return wg;
+ }
+ public CustomRegionManager getRegionManager() {
+ return mgr;
+ }
+ public PlayerData getPlayerData() {
+ return pdata;
+ }
+ public PlayerData.Data getPlayerData(Player player) {
+ return pdata.getData(player);
+ }
+ public FeatureBlockItemSpawn getBlockSpawn() {
+ return blockDrops;
+ }
}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/CmdBlockList.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/CmdBlockList.java
new file mode 100644
index 0000000..1fb8c77
--- /dev/null
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/CmdBlockList.java
@@ -0,0 +1,44 @@
+package de.jaschastarke.minecraft.limitedcreative.cmdblocker;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import de.jaschastarke.bukkit.lib.configuration.ConfigurableList;
+import de.jaschastarke.bukkit.lib.configuration.IToGeneric;
+import de.jaschastarke.configuration.InvalidValueException;
+
+public class CmdBlockList extends ArrayList implements ConfigurableList, IToGeneric {
+ private static final long serialVersionUID = -125544131527849084L;
+
+ @Override
+ public void add(String cmd) throws InvalidValueException {
+ if (cmd.startsWith("^")) {
+ add(new RegexpBlockEntry(cmd));
+ } else {
+ add(new StringBlockEntry(cmd));
+ }
+ }
+
+ @Override
+ public boolean remove(String e) {
+ for (Iterator iterator = this.iterator(); iterator.hasNext();) {
+ ICmdBlockEntry entry = iterator.next();
+ if (entry.toString().equalsIgnoreCase(e)) {
+ iterator.remove();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public List toGeneric() {
+ List list = new ArrayList(size());
+ for (ICmdBlockEntry bl : this) {
+ list.add(bl.toString());
+ }
+ return list;
+ }
+
+}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/CmdBlockPermissions.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/CmdBlockPermissions.java
new file mode 100644
index 0000000..935f5eb
--- /dev/null
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/CmdBlockPermissions.java
@@ -0,0 +1,70 @@
+package de.jaschastarke.minecraft.limitedcreative.cmdblocker;
+
+import java.util.Collection;
+
+import org.bukkit.permissions.PermissionDefault;
+
+import de.jaschastarke.maven.ArchiveDocComments;
+import de.jaschastarke.minecraft.lib.permissions.BasicPermission;
+import de.jaschastarke.minecraft.lib.permissions.DynamicPermission;
+import de.jaschastarke.minecraft.lib.permissions.IAbstractPermission;
+import de.jaschastarke.minecraft.lib.permissions.IDynamicPermission;
+import de.jaschastarke.minecraft.lib.permissions.IPermission;
+import de.jaschastarke.minecraft.lib.permissions.SimplePermissionContainerNode;
+import de.jaschastarke.minecraft.limitedcreative.Permissions;
+
+@ArchiveDocComments
+public class CmdBlockPermissions extends SimplePermissionContainerNode {
+ public CmdBlockPermissions(IAbstractPermission parent, String name) {
+ super(parent, name);
+ }
+
+ public static final SimplePermissionContainerNode CONTAINER = new CmdBlockPermissions(Permissions.CONTAINER, "cmdblock");
+
+ /**
+ * Allows bypassing the "command block"-limitation. So no commands are blocked for this users.
+ */
+ public static final IPermission ALL = new BasicPermission(CONTAINER, "*", PermissionDefault.OP);
+
+
+ /**
+ * Allows to bypass specific blockings of commands as it tests against all partial permissions:
+ *
+ * Example:
+ * A Command "/execute a fuzzy command -n 256" is entered by the player which is blocked by the configuration the
+ * following Permissions are tested, and if one is present for the user, he is allowed to execute the command:
+ * - limitedcreative.cmdblock.*
+ * - limitedcreative.cmdblock.execute
+ * - limitedcreative.cmdblock.execute.a
+ * - limitedcreative.cmdblock.execute.a.fuzzy
+ * - limitedcreative.cmdblock.execute.a.fuzzy.command
+ * - limitedcreative.cmdblock.execute.a.fuzzy.command.-n
+ * - limitedcreative.cmdblock.execute.a.fuzzy.command.-n.256
+ *
+ * Isn't this flexible enough for you? Than PermisssionsEx may help you, it allows you to configure Permissions with
+ * Regular Expressions.
+ */
+ public static IDynamicPermission COMMAND(String cmd) {
+ return new CommandPermission(ALL, cmd);
+ }
+
+ public static class CommandPermission extends DynamicPermission {
+ private String cmd;
+ public CommandPermission(IAbstractPermission parent, String cmd) {
+ super(parent);
+ this.cmd = cmd;
+ }
+
+ @Override
+ protected void buildPermissionsToCheck(Collection perms) {
+ String[] chunks = cmd.split("\\s+");
+ String chain = "";
+ for (String chunk : chunks) {
+ if (chain.length() > 0)
+ chain += IAbstractPermission.SEP;
+ chain += chunk;
+ perms.add(new BasicPermission(CONTAINER, chain));
+ }
+ }
+ }
+}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/CmdBlockerConfig.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/CmdBlockerConfig.java
new file mode 100644
index 0000000..3e5bbdb
--- /dev/null
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/CmdBlockerConfig.java
@@ -0,0 +1,90 @@
+package de.jaschastarke.minecraft.limitedcreative.cmdblocker;
+
+import de.jaschastarke.bukkit.lib.configuration.Configuration;
+import de.jaschastarke.configuration.IConfigurationNode;
+import de.jaschastarke.configuration.IConfigurationSubGroup;
+import de.jaschastarke.configuration.InvalidValueException;
+import de.jaschastarke.configuration.annotations.IsConfigurationNode;
+import de.jaschastarke.minecraft.limitedcreative.ModCmdBlocker;
+import de.jaschastarke.modularize.IModule;
+import de.jaschastarke.modularize.ModuleEntry;
+
+public class CmdBlockerConfig extends Configuration implements IConfigurationSubGroup {
+ protected ModCmdBlocker mod;
+ protected ModuleEntry entry;
+
+ public CmdBlockerConfig(ModCmdBlocker modCmdBlocker, ModuleEntry modEntry) {
+ mod = modCmdBlocker;
+ entry = modEntry;
+ }
+
+ @Override
+ public void setValue(IConfigurationNode node, Object pValue) throws InvalidValueException {
+ super.setValue(node, pValue);
+ if (node.getName().equals("enabled")) {
+ if (getEnabled()) {
+ entry.enable();
+ } else {
+ entry.disable();
+ }
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "cmdblock";
+ }
+ @Override
+ public int getOrder() {
+ return 500;
+ }
+
+ /**
+ * CmdBlockerEnabled
+ *
+ * Enables the feature for blocking certain commands in creative mode.
+ *
+ * default: true
+ */
+ @IsConfigurationNode(order = 100)
+ public boolean getEnabled() {
+ return config.getBoolean("enabled", true);
+ }
+
+ private CmdBlockList blockList;
+
+ /**
+ * CmdBlockerList
+ *
+ * Defines the list of commands that are blocked while in creative mode. The leading / isn't included. By default
+ * the list-item is treated as simple string as typed in by the user after the /. All commands starting with
+ * this string are blocked, even if more parameteres are entered by the user.
+ * If the first character is ^ the entry is interpreted as a regular expression (including the ^ for begin of the string).
+ * Only use regular expressions if you know them!
+ *
+ * Examples:
+ * - home
+ * - give diamond
+ * - ^home .+
+ * - ^chest (one|two|three)
+ * - ^(lc|limitedcreative) s(urvival)?\s*$
+ *
+ * default: []
+ */
+ @IsConfigurationNode(order = 200, name = "commands")
+ public CmdBlockList getCommandBlockList() {
+ if (blockList == null) {
+ blockList = new CmdBlockList();
+ if (config.contains("commands") && config.isList("commands")) {
+ for (Object e : config.getList("commands")) {
+ try {
+ blockList.add(e.toString());
+ } catch (InvalidValueException e1) {
+ mod.getLog().warn(e1.getMessage());
+ }
+ }
+ }
+ }
+ return blockList;
+ }
+}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/CommandListener.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/CommandListener.java
new file mode 100644
index 0000000..b1983a8
--- /dev/null
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/CommandListener.java
@@ -0,0 +1,36 @@
+package de.jaschastarke.minecraft.limitedcreative.cmdblocker;
+
+import org.bukkit.GameMode;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerCommandPreprocessEvent;
+
+import de.jaschastarke.minecraft.limitedcreative.ModCmdBlocker;
+
+public class CommandListener implements Listener {
+ private ModCmdBlocker mod;
+ public CommandListener(ModCmdBlocker mod) {
+ this.mod = mod;
+ }
+
+ @EventHandler
+ public void onPreCommand(PlayerCommandPreprocessEvent event) {
+ if (event.getPlayer().getGameMode() == GameMode.CREATIVE) {
+ String cmd = event.getMessage();
+ if (cmd.startsWith("/")) { // just to be sure ;)
+ cmd = cmd.substring(1);
+ for (ICmdBlockEntry blockentry : mod.getConfig().getCommandBlockList()) {
+ if (blockentry.test(cmd)) {
+ if (!mod.getPlugin().getPermManager().hasPermission(event.getPlayer(), CmdBlockPermissions.COMMAND(cmd))) {
+ if (mod.isDebug())
+ mod.getLog().debug("CmdBlock: " + event.getPlayer().getName() + ": '/" + cmd + "' blocked by rule '" + blockentry.toString() + "'");
+ event.setCancelled(true);
+ event.getPlayer().sendMessage(mod.getPlugin().getLocale().trans("cmdblock.blocked"));
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/ICmdBlockEntry.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/ICmdBlockEntry.java
new file mode 100644
index 0000000..499f85a
--- /dev/null
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/ICmdBlockEntry.java
@@ -0,0 +1,5 @@
+package de.jaschastarke.minecraft.limitedcreative.cmdblocker;
+
+public interface ICmdBlockEntry {
+ public boolean test(String cmd);
+}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/RegexpBlockEntry.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/RegexpBlockEntry.java
new file mode 100644
index 0000000..ac1db19
--- /dev/null
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/RegexpBlockEntry.java
@@ -0,0 +1,19 @@
+package de.jaschastarke.minecraft.limitedcreative.cmdblocker;
+
+import java.util.regex.Pattern;
+
+public class RegexpBlockEntry implements ICmdBlockEntry {
+ private Pattern rx;
+ public RegexpBlockEntry(String regex) {
+ rx = Pattern.compile(regex);
+ }
+
+ @Override
+ public boolean test(String cmd) {
+ return rx.matcher(cmd).matches();
+ }
+
+ public String toString() {
+ return rx.pattern();
+ }
+}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/StringBlockEntry.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/StringBlockEntry.java
new file mode 100644
index 0000000..8a3911d
--- /dev/null
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/cmdblocker/StringBlockEntry.java
@@ -0,0 +1,17 @@
+package de.jaschastarke.minecraft.limitedcreative.cmdblocker;
+
+public class StringBlockEntry implements ICmdBlockEntry {
+ private String str;
+ public StringBlockEntry(String cmd) {
+ str = cmd;
+ }
+
+ @Override
+ public boolean test(String cmd) {
+ return cmd.startsWith(this.str);
+ }
+
+ public String toString() {
+ return str;
+ }
+}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/NoLimitPermissions.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/NoLimitPermissions.java
index ac908dc..8f74839 100644
--- a/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/NoLimitPermissions.java
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/NoLimitPermissions.java
@@ -31,22 +31,23 @@ import de.jaschastarke.minecraft.lib.permissions.IDynamicPermission;
import de.jaschastarke.minecraft.lib.permissions.IPermission;
import de.jaschastarke.minecraft.lib.permissions.IPermissionContainer;
import de.jaschastarke.minecraft.lib.permissions.IsChildPermission;
+import de.jaschastarke.minecraft.lib.permissions.ParentPermissionContainerNode;
import de.jaschastarke.minecraft.lib.permissions.SimplePermissionContainerNode;
import de.jaschastarke.minecraft.limitedcreative.Permissions;
@ArchiveDocComments
-public class NoLimitPermissions extends BasicPermission {
- public NoLimitPermissions(IAbstractPermission parent, String name, PermissionDefault defaultValue) {
- super(parent, name, defaultValue);
+public class NoLimitPermissions extends SimplePermissionContainerNode {
+ public NoLimitPermissions(IAbstractPermission parent, String name) {
+ super(parent, name);
}
- public static final IPermissionContainer PARENT = new SimplePermissionContainerNode(Permissions.CONTAINER, "nolimit");
+ public static final IPermissionContainer PARENT = new NoLimitPermissions(Permissions.CONTAINER, "nolimit");
/**
* Grants bypassing of all nolimit-permissions.
*/
- public static final IPermission ALL = new NoLimitPermissions(PARENT, "*", PermissionDefault.OP);
+ public static final IPermission ALL = new ParentPermissionContainerNode(PARENT, "*", PermissionDefault.OP, PARENT);
/**
* Allows bypassing the "do not open a chest"-limitation
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/BlockListener.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/BlockListener.java
new file mode 100644
index 0000000..bfa09e4
--- /dev/null
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/BlockListener.java
@@ -0,0 +1,167 @@
+package de.jaschastarke.minecraft.limitedcreative.regions;
+
+import org.bukkit.GameMode;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Item;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.event.block.BlockPistonExtendEvent;
+import org.bukkit.event.block.BlockPistonRetractEvent;
+import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.event.entity.ItemSpawnEvent;
+import org.bukkit.event.hanging.HangingBreakByEntityEvent;
+
+import de.jaschastarke.bukkit.lib.Utils;
+import de.jaschastarke.minecraft.limitedcreative.ModRegions;
+import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.ApplicableRegions;
+import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.CustomRegionManager;
+
+public class BlockListener implements Listener {
+ private ModRegions mod;
+ private CustomRegionManager rm;
+
+ public BlockListener(ModRegions mod) {
+ this.mod = mod;
+ rm = mod.getRegionManager();
+ }
+
+ private ApplicableRegions regionSet(Location loc) {
+ return rm.getRegionSet(loc);
+ }
+ private ApplicableRegions regionSet(Block block) {
+ return rm.getRegionSet(block);
+ }
+
+ @EventHandler
+ public void onBlockBreak(BlockBreakEvent event) {
+ if (event.isCancelled())
+ return;
+ whenBlockBreak(event, event.getBlock(), event.getPlayer());
+ }
+
+ @EventHandler
+ public void onHangingBreak(HangingBreakByEntityEvent event) {
+ if (event.getRemover() instanceof Player) {
+ Player eventPlayer = (Player) event.getRemover();
+ whenBlockBreak(event, event.getEntity().getLocation().getBlock(), eventPlayer);
+ }
+ }
+
+ private void whenBlockBreak(Cancellable event, Block block, Player player) {
+ boolean diffrent_region = rm.isDiffrentRegion(player, block.getLocation());
+
+ PlayerData.Data pdata = mod.getPlayerData(player);
+
+ if (pdata.isActiveRegionGameMode() && diffrent_region) {
+ // do not break outside of "gamemod-change-region" when in the region
+ if (rm.getRegionSet(block).getFlag(Flags.GAMEMODE, player) != pdata.getActiveRegionGameMode()) {
+ player.sendMessage(L("blocked.outside_break"));
+ event.setCancelled(true);
+ }
+ } else if (diffrent_region) {
+ // do not break inside of "survial-region in creative world" when outside
+ if (rm.getRegionSet(block).getFlag(Flags.GAMEMODE) != null) {
+ player.sendMessage(L("blocked.inside_break"));
+ event.setCancelled(true);
+ }
+ }
+ if (!event.isCancelled()) {
+ // prevent any drops for survival players in creative regions
+ if (player.getGameMode() != GameMode.CREATIVE && rm.getRegionSet(block).getFlag(Flags.GAMEMODE) == GameMode.CREATIVE) {
+ mod.getBlockSpawn().block(block, player);
+ }
+ }
+ }
+
+ @EventHandler
+ public void onBlockPlace(BlockPlaceEvent event) {
+ if (event.isCancelled())
+ return;
+
+ PlayerData.Data pdata = mod.getPlayerData(event.getPlayer());
+ boolean diffrent_region = rm.isDiffrentRegion(event.getPlayer(), event.getBlock().getLocation());
+
+ if (pdata.isActiveRegionGameMode() && diffrent_region) {
+ // do not build outside of "gamemod-change-region" when in the region
+ if (rm.getRegionSet(event.getBlock()).getFlag(Flags.GAMEMODE, event.getPlayer()) != pdata.getActiveRegionGameMode()) {
+ event.getPlayer().sendMessage(L("blocked.outside_place"));
+ event.setCancelled(true);
+ }
+ } else if (diffrent_region) {
+ // do not build inside of "survial-region in creative world" when outside
+ if (rm.getRegionSet(event.getBlock()).getFlag(Flags.GAMEMODE) != null) {
+ event.getPlayer().sendMessage(L("blocked.inside_place"));
+ event.setCancelled(true);
+ }
+ }
+ }
+
+ @EventHandler
+ public void onPistonExtend(BlockPistonExtendEvent event) {
+ if (event.isCancelled())
+ return;
+
+ Block source = event.getBlock().getRelative(event.getDirection());
+ if (mod.isDebug())
+ mod.getLog().debug("PistonExtend "+source.getType()+" "+event.getDirection());
+ if (source.getType() != Material.AIR) {
+ if (regionSet(source).getFlag(Flags.GAMEMODE) == GameMode.CREATIVE) {
+ for (int i = 1; i <= 12; i++) {
+ Block dest = source.getRelative(event.getDirection(), i);
+ if (mod.isDebug())
+ mod.getLog().debug("dest "+i+": "+dest.getType());
+ if (regionSet(dest).getFlag(Flags.GAMEMODE) != GameMode.CREATIVE) {
+ mod.getLog().warn(L("blocked.piston", source.getRelative(event.getDirection(), i - 1).getType().toString(), Utils.toString(source.getLocation())));
+ event.setCancelled(true);
+ break;
+ } else if (dest.getType() == Material.AIR) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ @EventHandler
+ public void onPistonRetract(BlockPistonRetractEvent event) {
+ if (event.isCancelled())
+ return;
+ Block source = event.getBlock().getRelative(event.getDirection(), 2);
+ Block dest = source.getRelative(event.getDirection().getOppositeFace());
+ if (mod.isDebug())
+ mod.getLog().debug("PistonRetract "+source.getType()+" "+event.getDirection() + " " + event.isSticky());
+ if (event.isSticky() && source.getType() != Material.AIR) {
+ if (mod.isDebug())
+ mod.getLog().debug("dest "+dest.getType());
+ if (regionSet(source).getFlag(Flags.GAMEMODE) == GameMode.CREATIVE) {
+ if (regionSet(dest).getFlag(Flags.GAMEMODE) != GameMode.CREATIVE) {
+ mod.getLog().warn(L("blocked.piston", source.getType().toString(), Utils.toString(source.getLocation())));
+ event.setCancelled(true);
+ }
+ } else if (regionSet(dest).getFlag(Flags.GAMEMODE) == GameMode.CREATIVE) {
+ // source isn't creative
+ mod.getLog().warn(L("blocked.piston_in", source.getType().toString(), Utils.toString(source.getLocation())));
+ event.setCancelled(true);
+ }
+ }
+ }
+
+ @EventHandler
+ public void onItemSpawn(ItemSpawnEvent event) {
+ if (event.isCancelled())
+ return;
+ if (event.getEntity() instanceof Item) {
+ if (!regionSet(event.getLocation()).allows(Flags.SPAWNDROPS))
+ event.setCancelled(true);
+ }
+ }
+
+ private String L(String msg, Object... args) {
+ return mod.getPlugin().getLocale().trans(msg, args);
+ }
+}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/Flags.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/Flags.java
new file mode 100644
index 0000000..1c20af6
--- /dev/null
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/Flags.java
@@ -0,0 +1,20 @@
+package de.jaschastarke.minecraft.limitedcreative.regions;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.sk89q.worldguard.protection.flags.Flag;
+import com.sk89q.worldguard.protection.flags.RegionGroup;
+import com.sk89q.worldguard.protection.flags.StateFlag;
+
+public final class Flags {
+ public static final StateFlag SPAWNDROPS = new StateFlag("spawndrops", true);
+ public static final GameModeFlag GAMEMODE = new GameModeFlag("gamemode", RegionGroup.MEMBERS);
+
+ public static List> getList() {
+ return Arrays.asList(new Flag>[]{
+ SPAWNDROPS,
+ GAMEMODE,
+ });
+ }
+}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/GameModeFlag.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/GameModeFlag.java
new file mode 100644
index 0000000..e43686f
--- /dev/null
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/GameModeFlag.java
@@ -0,0 +1,48 @@
+package de.jaschastarke.minecraft.limitedcreative.regions;
+
+import org.bukkit.GameMode;
+import org.bukkit.command.CommandSender;
+
+import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
+import com.sk89q.worldguard.protection.flags.Flag;
+import com.sk89q.worldguard.protection.flags.InvalidFlagFormat;
+import com.sk89q.worldguard.protection.flags.RegionGroup;
+
+/**
+ * Well, that was an interesting idea, but it doesn't work.
+ */
+public class GameModeFlag extends Flag {
+ public GameModeFlag(String name, RegionGroup defaultGroup) {
+ super(name, defaultGroup);
+ }
+
+ @Override
+ public GameMode parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat {
+ input = input.trim();
+ if (input.equalsIgnoreCase("creative")) {
+ return GameMode.CREATIVE;
+ } else if (input.equalsIgnoreCase("survival")) {
+ return GameMode.SURVIVAL;
+ } else if (input.equalsIgnoreCase("adventure")) {
+ return GameMode.ADVENTURE;
+ } else if (input.equalsIgnoreCase("none")) {
+ return null;
+ } else {
+ throw new InvalidFlagFormat("Expected survival/creative/none but got '" + input + "'");
+ }
+ }
+
+ @Override
+ public GameMode unmarshal(Object o) {
+ GameMode gm = null;
+ if (o != null) {
+ gm = GameMode.valueOf((String) o);
+ }
+ return gm;
+ }
+
+ @Override
+ public Object marshal(GameMode o) {
+ return o == null ? null : o.name();
+ }
+}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/PlayerData.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/PlayerData.java
new file mode 100644
index 0000000..f9fc210
--- /dev/null
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/PlayerData.java
@@ -0,0 +1,143 @@
+package de.jaschastarke.minecraft.limitedcreative.regions;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.util.WeakHashMap;
+
+import org.bukkit.GameMode;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.entity.Player;
+
+import de.jaschastarke.minecraft.limitedcreative.ModRegions;
+
+public class PlayerData {
+ private static final String DEFAULT_FILENAME = "players.yml";
+ private ModRegions mod;
+ private File file;
+ private YamlConfiguration data;
+ private WeakHashMap players = new WeakHashMap();
+
+ public PlayerData(ModRegions mod) {
+ this(mod, new File(mod.getPlugin().getDataFolder(), DEFAULT_FILENAME));
+ }
+ public PlayerData(ModRegions mod, File yamlFile) {
+ this.mod = mod;
+ this.file = yamlFile;
+ if (yamlFile.exists())
+ this.data = YamlConfiguration.loadConfiguration(file);
+ else
+ this.data = new YamlConfiguration();
+ this.data.options().header("DO NOT MODIFY THIS FILE");
+ }
+
+ protected ConfigurationSection getStorage() {
+ return data;
+ }
+
+ public Data getData(final Player player) {
+ if (players.containsKey(player)) {
+ return players.get(player);
+ } else {
+ Data pdata = new Data(player);
+ players.put(player, pdata);
+ return pdata;
+ }
+ }
+
+ protected void save() {
+ try {
+ data.save(file);
+ } catch (IOException e) {
+ mod.getPlugin().getLogger().severe("Failed to save " + file.getName());
+ e.printStackTrace();
+ }
+ }
+
+ public void clearAllTemp() {
+ for (Data data : players.values()) {
+ data.clearTemp();
+ }
+ }
+
+ private ConfigurationSection getSect(final String player) {
+ if (data.contains(player) && data.isConfigurationSection(player)) {
+ return data.getConfigurationSection(player);
+ } else {
+ return data.createSection(player);
+ }
+ }
+
+ public class Data {
+ private WeakReference player;
+ private String currentHash;
+
+ private Data(final Player player) {
+ this.player = new WeakReference(player);
+ }
+ private String n() {
+ return player.get().getName();
+ }
+
+ public boolean isActiveRegionGameMode() {
+ return getActiveRegionGameMode() != null;
+ }
+ public boolean isActiveRegionGameMode(GameMode regionGameMode) {
+ return getActiveRegionGameMode() == regionGameMode;
+ }
+ public GameMode getActiveRegionGameMode() {
+ return getGameMode("region_gamemode");
+ }
+ public void storeActiveRegionGameMode(GameMode regionGameMode) {
+ getSect(n()).set("region_gamemode", regionGameMode);
+ }
+ public boolean isInPermanentGameMode(GameMode currentGameMode) {
+ return getPermanentRegionGameMode() == currentGameMode;
+ }
+ public void storePermanentGameMode(GameMode currentGameMode) {
+ getSect(n()).set("permanent_gamemode", currentGameMode);
+ }
+ public GameMode getPermanentRegionGameMode() {
+ return getGameMode("permanent_gamemode");
+ }
+ public GameMode getOptionalRegionGameMode(String regionHash) {
+ return getGameMode("optional_gamemode." + regionHash);
+ }
+ public void setOptionalRegionGameMode(String regionHash, GameMode currentGameMode) {
+ getSect(n()+".optional_gamemode").set(regionHash, currentGameMode);
+ cleanUp();
+ }
+
+ private GameMode getGameMode(String path) {
+ if (getSect(n()).contains(path) && getSect(n()).isString(path)) {
+ return GameMode.valueOf(getSect(n()).getString(path));
+ } else if (getSect(n()).contains(path)) {
+ return (GameMode) getSect(n()).get(path);
+ } else {
+ return null;
+ }
+ }
+
+ private void cleanUp() {
+ if (data.contains(n()) && data.isConfigurationSection(n())) {
+ if (data.getConfigurationSection(n()).getKeys(false).size() == 0) {
+ remove();
+ }
+ }
+ }
+ public void remove() {
+ data.set(n(), null);
+ }
+
+ public void setHash(String hash) {
+ currentHash = hash;
+ }
+ public String getHash() {
+ return currentHash;
+ }
+ public void clearTemp() {
+ currentHash = null;
+ }
+ }
+}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/PlayerListener.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/PlayerListener.java
new file mode 100644
index 0000000..351291c
--- /dev/null
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/PlayerListener.java
@@ -0,0 +1,74 @@
+package de.jaschastarke.minecraft.limitedcreative.regions;
+
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.Sign;
+import org.bukkit.event.Event;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.inventory.InventoryHolder;
+import org.bukkit.material.Button;
+import org.bukkit.material.Lever;
+
+import de.jaschastarke.minecraft.limitedcreative.ModRegions;
+import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.CustomRegionManager;
+
+public class PlayerListener implements Listener {
+ private ModRegions mod;
+ private CustomRegionManager rm;
+
+ public PlayerListener(ModRegions mod) {
+ this.mod = mod;
+ rm = mod.getRegionManager();
+ }
+
+ /**
+ * The isCancelled in PlayerInteractEvent doesn't check useItemInHand, even this decides (when clicking on
+ * entity with e.g. a bucket)
+ * @param event
+ * @return The relevant "isCancelled"
+ */
+ private static boolean isCancelled(PlayerInteractEvent event) {
+ return event.useInteractedBlock() == Event.Result.DENY && event.useItemInHand() == Event.Result.DENY;
+ }
+
+ @EventHandler
+ public void onPlayerInteract(PlayerInteractEvent event) {
+ if (isCancelled(event))
+ return;
+
+ if (event.getAction() != Action.RIGHT_CLICK_BLOCK)
+ return;
+
+ Block block = event.getClickedBlock();
+
+ if (block.getState() instanceof InventoryHolder || block.getType() == Material.ENDER_CHEST || // Workaround, Bukkit not recognize a Enderchest
+ block.getState() instanceof Sign ||
+ block.getState() instanceof Lever || block.getState() instanceof Button ||
+ block.getType() == Material.WORKBENCH || block.getType() == Material.ANVIL) {
+
+ PlayerData.Data pdata = mod.getPlayerData(event.getPlayer());
+ boolean diffrent_region = rm.isDiffrentRegion(event.getPlayer(), block.getLocation());
+
+ if (pdata.isActiveRegionGameMode() && diffrent_region) {
+ // do not break outside of "gamemod-change-region" when in the region
+ if (rm.getRegionSet(block).getFlag(Flags.GAMEMODE, event.getPlayer()) != pdata.getActiveRegionGameMode()) {
+ event.getPlayer().sendMessage(L("blocked.outside_interact"));
+ event.setCancelled(true);
+ }
+ } else if (diffrent_region) {
+ // do not break inside of "survial-region in creative world" when outside
+ if (rm.getRegionSet(block).getFlag(Flags.GAMEMODE) != null) {
+ event.getPlayer().sendMessage(L("blocked.inside_interact"));
+ event.setCancelled(true);
+ }
+ }
+ }
+ }
+
+ private String L(String msg, Object... args) {
+ return mod.getPlugin().getLocale().trans(msg, args);
+ }
+}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/RegionConfig.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/RegionConfig.java
new file mode 100644
index 0000000..6333e96
--- /dev/null
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/RegionConfig.java
@@ -0,0 +1,76 @@
+package de.jaschastarke.minecraft.limitedcreative.regions;
+
+import de.jaschastarke.bukkit.lib.configuration.Configuration;
+import de.jaschastarke.configuration.IConfigurationNode;
+import de.jaschastarke.configuration.IConfigurationSubGroup;
+import de.jaschastarke.configuration.InvalidValueException;
+import de.jaschastarke.configuration.annotations.IsConfigurationNode;
+import de.jaschastarke.minecraft.limitedcreative.ModRegions;
+import de.jaschastarke.minecraft.limitedcreative.limits.BlackList;
+import de.jaschastarke.modularize.IModule;
+import de.jaschastarke.modularize.ModuleEntry;
+
+/**
+ * Region GameModes-Feature
+ *
+ * http://dev.bukkit.org/server-mods/limited-creative/pages/features/region/
+ */
+public class RegionConfig extends Configuration implements IConfigurationSubGroup {
+ protected ModRegions mod;
+ protected ModuleEntry entry;
+
+ public RegionConfig(ModRegions modRegions, ModuleEntry modEntry) {
+ mod = modRegions;
+ entry = modEntry;
+ }
+
+ @Override
+ public void setValue(IConfigurationNode node, Object pValue) throws InvalidValueException {
+ if (!(pValue instanceof BlackList))
+ super.setValue(node, pValue);
+ if (node.getName().equals("enabled")) {
+ if (getEnabled()) {
+ entry.enable();
+ } else {
+ entry.disable();
+ }
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "region";
+ }
+
+ @Override
+ public int getOrder() {
+ return 400;
+ }
+
+ /**
+ * RegionEnabled
+ *
+ * Enables the feature for "creative-regions". This Feature is automatically disabled, if the required plugin
+ * "WorldGuard" (http://dev.bukkit.org/server-mods/worldguard/) isn't found.
+ *
+ * default: true
+ */
+ @IsConfigurationNode(order = 100)
+ public boolean getEnabled() {
+ return config.getBoolean("enabled", true);
+ }
+
+ /**
+ * RegionMaximumFallingHeight
+ *
+ * When the player is more than this count of blocks above the ground, he is prevented from changing the region that
+ * sets him survival which would cause him falling and hurting.
+ *
+ * default: 3
+ */
+ @IsConfigurationNode(order = 500)
+ public int getMaximumFloatingHeight() {
+ return config.getInt("maxFallingHeight", 3);
+ }
+
+}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/RegionListener.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/RegionListener.java
new file mode 100644
index 0000000..ce40e87
--- /dev/null
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/RegionListener.java
@@ -0,0 +1,172 @@
+package de.jaschastarke.minecraft.limitedcreative.regions;
+
+import org.bukkit.GameMode;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.entity.Item;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Event;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.ItemSpawnEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.player.PlayerMoveEvent;
+
+import de.jaschastarke.bukkit.lib.Utils;
+import de.jaschastarke.minecraft.limitedcreative.Hooks;
+import de.jaschastarke.minecraft.limitedcreative.ModRegions;
+import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.ApplicableRegions;
+import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.CustomRegionManager;
+import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.events.PlayerAreaEvent;
+import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.events.PlayerChangedAreaEvent;
+import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.events.PlayerNewLocationAreaEvent;
+import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.events.PlayerSetAreaEvent;
+import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.events.PlayerUpdateAreaEvent;
+
+public class RegionListener implements Listener {
+ private ModRegions mod;
+ private CustomRegionManager rm;
+
+ public RegionListener(ModRegions mod) {
+ this.mod = mod;
+ rm = mod.getRegionManager();
+ }
+
+ /**
+ * The isCancelled in PlayerInteractEvent doesn't check useItemInHand, even this decides (when clicking on
+ * entity with e.g. a bucket)
+ * @param event
+ * @return The relevant "isCancelled"
+ */
+ public static boolean isCancelled(PlayerInteractEvent event) {
+ return event.useInteractedBlock() == Event.Result.DENY && event.useItemInHand() == Event.Result.DENY;
+ }
+
+ private ApplicableRegions regionSet(Location loc) {
+ return rm.getRegionSet(loc);
+ }
+
+ public int getFloatingHeight(Player player) {
+ return getFloatingHeight(player.getLocation());
+ }
+ public int getFloatingHeight(Location loc) {
+ Block b = loc.getBlock();
+ int steps = 0;
+ while (b.getType() == Material.AIR) {
+ steps++;
+ b = b.getRelative(BlockFace.DOWN);
+ }
+ return steps;
+ }
+
+ private boolean checkSwitchFlight(PlayerMoveEvent event) {
+ if (event != null && event.getPlayer().getGameMode() == GameMode.CREATIVE && getFloatingHeight(event.getTo()) > mod.getConfig().getMaximumFloatingHeight()) {
+ // but not if he is too high
+ Utils.sendTimeoutMessage(event.getPlayer(), L("blocked.survival_flying"));
+
+ Location newloc = event.getTo().clone();
+ newloc.setX(event.getFrom().getX());
+ newloc.setY(event.getFrom().getY()); // well, otherwise flying high out of the region is possible
+ newloc.setZ(event.getFrom().getZ());
+ event.setTo(newloc);
+ return false;
+ }
+ return true;
+ }
+ private boolean checkSwitchFlight(PlayerAreaEvent area_event) {
+ if (area_event instanceof PlayerChangedAreaEvent) {
+ if (!checkSwitchFlight(((PlayerChangedAreaEvent) area_event).getMoveEvent())) {
+ ((PlayerChangedAreaEvent) area_event).setCancelled(true);
+ return false;
+ }
+ }
+ return true;
+ }
+ private void setRegionGameMode(GameMode region_gamemode, PlayerAreaEvent area_event) {
+ Player player = area_event.getPlayer();
+ PlayerData.Data pdata = mod.getPlayerData(player);
+ if (mod.isDebug())
+ mod.getLog().debug(player.getName()+": changed region: "+region_gamemode+": " + area_event);
+
+ PlayerMoveEvent event = null;
+ if (area_event instanceof PlayerChangedAreaEvent)
+ event = ((PlayerChangedAreaEvent) area_event).getMoveEvent();
+ GameMode CURRENT_GAMEMODE = player.getGameMode();
+ GameMode DEFAULT_GAMEMODE = Hooks.DefaultWorldGameMode.get(event != null ? event.getTo().getWorld() : player.getWorld());
+
+ if (region_gamemode != null && CURRENT_GAMEMODE != region_gamemode && !pdata.isActiveRegionGameMode(region_gamemode)) {
+ if (mod.isDebug())
+ mod.getLog().debug(player.getName()+": entering creative area");
+ // 1. the region allows "the other (temporary) gamemode"
+ // 2. but the player is not in that mode
+ // 3. and the player is not aware of that
+ // result: change him to that mode
+
+ boolean isOptional = pdata.getOptionalRegionGameMode(area_event.getRegionHash()) == CURRENT_GAMEMODE;
+
+ if (isOptional || checkSwitchFlight(area_event)) {
+ pdata.storeActiveRegionGameMode(region_gamemode); // have to be set, before setGameMode
+
+ if (!isOptional) {
+ player.setGameMode(region_gamemode);
+ }
+ }
+ } else if (region_gamemode == null && player.getGameMode() != DEFAULT_GAMEMODE && !pdata.isInPermanentGameMode(CURRENT_GAMEMODE) && pdata.getActiveRegionGameMode() != null) {
+ if (mod.isDebug())
+ mod.getLog().debug(player.getName()+": leaving creative area");
+ // 1. the region doesn't allow "the other gamemode"
+ // 2. but the player is in that mode
+ // 3. and the player isn't global (permanent) in that mode
+ // 4. and the player isn't temporary in that mode (that means its maybe a world teleport, and the mode changes afterwards)
+ // result: change him back to default mode
+ if (checkSwitchFlight(area_event)) {
+ pdata.storeActiveRegionGameMode(null);
+ player.setGameMode(DEFAULT_GAMEMODE);
+ }
+ } else if (region_gamemode == null && pdata.isActiveRegionGameMode()) {
+ if (mod.isDebug())
+ mod.getLog().debug(player.getName()+": leaving creative area (while already in default gamemode)");
+ // 1. the region doesn't allow "the other gamemode"
+ // 2. but he thinks he is still allowed
+ // 3. (because of else) we are not longer in that mode
+ // result: advise him to not longer allowed to that region
+ pdata.storeActiveRegionGameMode(null);
+ } else if (region_gamemode == CURRENT_GAMEMODE && !pdata.isInPermanentGameMode(CURRENT_GAMEMODE)) {
+ if (!pdata.isActiveRegionGameMode(region_gamemode)) {
+ // we have no information why we are already in this gamemode, so this may be because of an AuthMe change-and-teleport
+ pdata.storeActiveRegionGameMode(region_gamemode);
+ }
+ }
+ }
+
+ @EventHandler
+ public void onPlayerChangedArea(PlayerNewLocationAreaEvent event) {
+ setRegionGameMode(event.getRegionSet().getFlag(Flags.GAMEMODE, event.getPlayer()), event);
+ }
+
+ @EventHandler
+ public void onPlayerSetArea(PlayerSetAreaEvent event) {
+ setRegionGameMode(event.getRegionSet().getFlag(Flags.GAMEMODE, event.getPlayer()), event);
+ }
+
+ @EventHandler
+ public void onPlayerUpdateArea(PlayerUpdateAreaEvent event) {
+ setRegionGameMode(event.getRegionSet().getFlag(Flags.GAMEMODE, event.getPlayer()), event);
+ }
+
+ @EventHandler
+ public void onItemSpawn(ItemSpawnEvent event) {
+ if (event.isCancelled())
+ return;
+ if (event.getEntity() instanceof Item) {
+ if (!regionSet(event.getLocation()).allows(Flags.SPAWNDROPS))
+ event.setCancelled(true);
+ }
+ }
+
+ private String L(String msg, Object... args) {
+ return mod.getPlugin().getLocale().trans(msg, args);
+ }
+}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/RegionPermissions.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/RegionPermissions.java
new file mode 100644
index 0000000..360b03a
--- /dev/null
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/RegionPermissions.java
@@ -0,0 +1,32 @@
+package de.jaschastarke.minecraft.limitedcreative.regions;
+
+import org.bukkit.permissions.PermissionDefault;
+
+import de.jaschastarke.maven.ArchiveDocComments;
+import de.jaschastarke.minecraft.lib.permissions.BasicPermission;
+import de.jaschastarke.minecraft.lib.permissions.IAbstractPermission;
+import de.jaschastarke.minecraft.lib.permissions.IPermission;
+import de.jaschastarke.minecraft.lib.permissions.SimplePermissionContainerNode;
+import de.jaschastarke.minecraft.limitedcreative.Permissions;
+
+/**
+ * Allows usage of the //region commands
+ */
+@ArchiveDocComments
+final public class RegionPermissions extends SimplePermissionContainerNode implements IPermission {
+ private RegionPermissions(IAbstractPermission parent, String name) {
+ super(parent, name);
+ }
+
+ @Override
+ public PermissionDefault getDefault() {
+ return PermissionDefault.OP;
+ }
+
+ public static final RegionPermissions REGION = new RegionPermissions(Permissions.CONTAINER, "region");
+
+ /**
+ * Ignores the force of a gamemode, when region optional is disabled
+ */
+ public static final IPermission BYPASS = new BasicPermission(REGION, "bypass", PermissionDefault.FALSE);
+}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/RegionsCommand.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/RegionsCommand.java
new file mode 100644
index 0000000..f42bd72
--- /dev/null
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/RegionsCommand.java
@@ -0,0 +1,191 @@
+package de.jaschastarke.minecraft.limitedcreative.regions;
+
+import org.apache.commons.lang.StringUtils;
+import org.bukkit.ChatColor;
+import org.bukkit.World;
+
+import com.sk89q.worldguard.protection.flags.Flag;
+import com.sk89q.worldguard.protection.flags.InvalidFlagFormat;
+import com.sk89q.worldguard.protection.managers.RegionManager;
+import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
+import com.sk89q.worldguard.protection.regions.ProtectedRegion;
+
+import de.jaschastarke.LocaleString;
+import de.jaschastarke.bukkit.lib.chat.ChatFormattings;
+import de.jaschastarke.bukkit.lib.commands.BukkitCommand;
+import de.jaschastarke.bukkit.lib.commands.CommandContext;
+import de.jaschastarke.bukkit.lib.commands.CommandException;
+import de.jaschastarke.bukkit.lib.commands.HelpCommand;
+import de.jaschastarke.bukkit.lib.commands.IHelpDescribed;
+import de.jaschastarke.bukkit.lib.commands.MissingPermissionCommandException;
+import de.jaschastarke.bukkit.lib.commands.annotations.IsCommand;
+import de.jaschastarke.bukkit.lib.commands.annotations.Usages;
+import de.jaschastarke.bukkit.lib.commands.parser.DefinedParameterParser;
+import de.jaschastarke.maven.ArchiveDocComments;
+import de.jaschastarke.minecraft.lib.permissions.IAbstractPermission;
+import de.jaschastarke.minecraft.limitedcreative.ModRegions;
+import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.FlagList;
+import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.FlagValue;
+import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.Region;
+
+/**
+ * LimitedCreative-Region-Command: configure creative regions
+ * @usage / - displays Regions-Command-Help
+ * @permission limitedcreative.region
+ */
+@ArchiveDocComments
+public class RegionsCommand extends BukkitCommand implements IHelpDescribed {
+ private ModRegions mod;
+ private HelpCommand help;
+
+ public RegionsCommand() {
+ this.help = this.getDefaultHelpCommand();
+ }
+ public RegionsCommand(ModRegions mod) {
+ this.mod = mod;
+ this.help = this.getDefaultHelpCommand();
+ }
+
+ @Override
+ public String getName() {
+ return "lcr";
+ }
+
+ @Override
+ public String[] getAliases() {
+ return new String[]{"/region"};
+ }
+
+ /**
+ * @internal has no effect, as not tested by any command handler
+ * @see IHelpDescribed
+ */
+ @Override
+ public IAbstractPermission[] getRequiredPermissions() {
+ return new IAbstractPermission[]{RegionPermissions.REGION};
+ }
+ @Override
+ public String[] getUsages() {
+ return null;
+ }
+ @Override
+ public CharSequence getDescription() {
+ return new LocaleString("command.regions");
+ }
+ @Override
+ public String getPackageName() {
+ return mod.getPlugin().getName() + " - " + mod.getName();
+ }
+
+ /*@Override
+ public IPermission getPermission(String subPerm) {
+ if (subPerm.equals("region"))
+ return RegionPermissions.REGION;
+ else
+ return RegionPermissions.REGION.getPermission(subPerm);
+ }*/
+
+ /**
+ * Sets the Flag of a region to a new value. If no value given, the flag is removed.
+ * -g sets the affected group of the flag, instead the flag (equivalent to using flag-group as flag-name)
+ * -w world uses a world by name instead the world your in (required from console)
+ */
+ @IsCommand("flag")
+ //@NeedsPermission("region") // not needed as the whole command requires permissions
+ @Usages(" -g -w world [value]")
+ public boolean setFlag(CommandContext context, String... args) throws CommandException, MissingPermissionCommandException {
+ DefinedParameterParser params = new DefinedParameterParser(args, new String[]{"g"}, 2);
+ if (params.getArgumentCount() < 2) {// doesn't count parameters
+ help.execute(context, new String[]{"flag"});
+ context.response(L("command.worldguard.available_flags") + FlagList.getStringListAvailableFlags(context.getSender()));
+ return true;
+ }
+
+ World w = context.isPlayer() ? context.getPlayer().getWorld() : null;
+ if (params.getParameter("-w") != null)
+ w = mod.getPlugin().getServer().getWorld(params.getParameter("-w"));
+ if (w == null)
+ throw new CommandException(L("command.worldguard.world_not_found"));
+
+ RegionManager mgr = mod.getWorldGuard().getGlobalRegionManager().get(w);
+ ProtectedRegion region = mgr.getRegion(params.getArgument(0));
+ if (region == null && params.getArgument(0).equalsIgnoreCase("__global__")) {
+ region = new GlobalProtectedRegion(params.getArgument(0));
+ mgr.addRegion(region);
+ }
+ if (region == null)
+ throw new CommandException(L("command.worldguard.region_not_found"));
+
+ Region reg = mod.getRegionManager().world(w).region(region);
+
+ Flag> flag = FlagList.getFlag(params.getArgument(1));
+ if (flag == null) {
+ String msg = L("command.worldguard.unknown_flag") + params.getArgument(1) + "\n"
+ + L("command.worldguard.available_flags") + FlagList.getStringListAvailableFlags(context.getSender());
+ throw new CommandException(msg);
+ }
+
+ String value = params.getValue();
+ try {
+ if (value != null) {
+ reg.setFlag(flag, flag.parseInput(mod.getWorldGuard(), context.getSender(), value));
+ } else {
+ reg.setFlag(flag, null);
+ }
+ } catch (InvalidFlagFormat e) {
+ context.response(context.getFormatter().formatString(ChatFormattings.ERROR, e.getLocalizedMessage()));
+ return true;
+ }
+
+ context.response(L("command.worldguard.flag_set", flag.getName()));
+ return true;
+ }
+
+ @IsCommand("info")
+ //@NeedsPermission("region")
+ @Usages("[world] [id]")
+ public boolean getInfo(CommandContext context, String... args) throws CommandException {
+ DefinedParameterParser params = new DefinedParameterParser(args, new String[]{"s"}, 1);
+
+ /*
+ * WorldEdits intercepting Servers privates commandMap via Reflections realy sucks!
+ * Just because they are to lazy to add all the lines commands to plugin.yml
+ */
+ String orgCmd = ("region info " + StringUtils.join(args)).trim();
+ mod.getPlugin().getServer().dispatchCommand(context.getSender(), orgCmd);
+
+ World w = context.isPlayer() ? context.getPlayer().getWorld() : null;
+ if (params.getArgumentCount() > 1)
+ w = mod.getPlugin().getServer().getWorld(params.getArgument(0));
+ if (w == null)
+ throw new CommandException(L("command.worldguard.world_not_found"));
+
+ int rpc = params.getArgumentCount() > 1 ? 2 : 1;
+ RegionManager mgr = mod.getWorldGuard().getGlobalRegionManager().get(w);
+ ProtectedRegion region = mgr.getRegion(params.getArgument(rpc));
+ if (region == null && params.getArgument(rpc).equalsIgnoreCase("__global__")) {
+ region = new GlobalProtectedRegion(params.getArgument(rpc));
+ mgr.addRegion(region);
+ }
+ if (region == null)
+ throw new CommandException(L("command.worldguard.region_not_found"));
+
+ Region reg = mod.getRegionManager().world(w).region(region);
+
+ StringBuilder list = new StringBuilder();
+ for (FlagValue data : reg.getFlags()) {
+ if (list.length() > 0)
+ list.append(", ");
+ list.append(data.getFlag().getName());
+ list.append(": ");
+ list.append(data.getValue().toString());
+ }
+
+ context.response(ChatColor.GREEN + L("command.worldguard.additional_flags") + list.toString());
+ return true;
+ }
+
+ private String L(String msg, Object... args) {
+ return mod.getPlugin().getLocale().trans(msg, args);
+ }
+}
diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/ApplicableRegions.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/ApplicableRegions.java
new file mode 100644
index 0000000..1dba934
--- /dev/null
+++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/ApplicableRegions.java
@@ -0,0 +1,99 @@
+/*
+ * Limited Creative - (Bukkit Plugin)
+ * Copyright (C) 2012 jascha@ja-s.de
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package de.jaschastarke.minecraft.limitedcreative.regions.worldguard;
+
+import org.bukkit.entity.Player;
+
+import com.sk89q.worldguard.protection.ApplicableRegionSet;
+import com.sk89q.worldguard.protection.flags.Flag;
+import com.sk89q.worldguard.protection.flags.StateFlag;
+import com.sk89q.worldguard.protection.regions.ProtectedRegion;
+
+public class ApplicableRegions {
+ private ApplicableRegionSet regions;
+ private CustomRegionManager.CWorld mgr;
+
+ public ApplicableRegions(ApplicableRegionSet regions, CustomRegionManager.CWorld rm) {
+ this.regions = regions;
+ this.mgr = rm;
+ }
+
+
+ public boolean allows(StateFlag flag) {
+ extendRegionFlags();
+ boolean r = regions.allows(flag);
+ contractRegionFlags();
+ return r;
+ }
+
+ public boolean allows(StateFlag flag, Player player) {
+ extendRegionFlags();
+ boolean r = regions.allows(flag, mgr.getWorldGuard().wrapPlayer(player));
+ contractRegionFlags();
+ return r;
+ }
+
+ public , V> V getFlag(T flag) {
+ extendRegionFlags();
+ V r = regions.getFlag(flag);
+ contractRegionFlags();
+ return r;
+ }
+
+ public , V> V getFlag(T flag, Player player) {
+ extendRegionFlags();
+ V r = regions.getFlag(flag, mgr.getWorldGuard().wrapPlayer(player));
+ contractRegionFlags();
+ return r;
+ }
+
+ @SuppressWarnings("unchecked")
+ private void extendRegionFlags() {
+ for (ProtectedRegion pr : regions) {
+ for (FlagValue data : mgr.region(pr).getFlags()) {
+ Flag