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 flag = (Flag) data.getFlag(); + Object value = data.getValue(); + pr.setFlag(flag, value); + } + } + if (mgr.getGlobalRegion() != null) { + for (FlagValue data : mgr.region(mgr.getGlobalRegion()).getFlags()) { + Flag flag = (Flag) data.getFlag(); + Object value = data.getValue(); + mgr.getGlobalRegion().setFlag(flag, value); + } + } + } + + @SuppressWarnings("unchecked") + private void contractRegionFlags() { + for (ProtectedRegion pr : regions) { + for (FlagValue data : mgr.region(pr).getFlags()) { + Flag flag = (Flag) data.getFlag(); + pr.setFlag(flag, null); + } + } + if (mgr.getGlobalRegion() != null) { + for (FlagValue data : mgr.region(mgr.getGlobalRegion()).getFlags()) { + Flag flag = (Flag) data.getFlag(); + mgr.getGlobalRegion().setFlag(flag, null); + } + } + } + +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/CustomRegionManager.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/CustomRegionManager.java new file mode 100644 index 0000000..bc4a3cc --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/CustomRegionManager.java @@ -0,0 +1,187 @@ +/* + * 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 java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; + +import com.sk89q.worldguard.bukkit.BukkitUtil; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.protection.GlobalRegionManager; +import com.sk89q.worldguard.protection.flags.Flag; +import com.sk89q.worldguard.protection.managers.RegionManager; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; + +import de.jaschastarke.minecraft.limitedcreative.ModRegions; +import de.jaschastarke.utils.StringUtil; + +public class CustomRegionManager { + protected YamlConfiguration c; + protected File file; + private Map worlds = new HashMap(); + private ModRegions mod; + public CustomRegionManager(File file, ModRegions mod) { + this.file = file; + this.mod = mod; + c = YamlConfiguration.loadConfiguration(file); + } + + + public CWorld world(World w) { + if (worlds.containsKey(w)) { + return worlds.get(w); + } else { + CWorld r = new CWorld(w); + worlds.put(w, r); + return r; + } + } + + public class CWorld { + private World world; + private ConfigurationSection wc = null; + public CWorld(World w) { + world = w; + } + public CustomRegionManager getManager() { + return CustomRegionManager.this; + } + private Map regions = new HashMap(); + public Region region(ProtectedRegion pr) { + if (regions.containsKey(pr)) { + return regions.get(pr); + } else { + Region r = new Region(this, pr); + regions.put(pr, r); + return r; + } + } + public World getWorld() { + return world; + } + public ProtectedRegion getGlobalRegion() { + return getWGManager(world).getRegion("__global__"); + } + + @SuppressWarnings("unchecked") + public void storeFlag(Region region, Flag flag, Object value) { + if (wc == null) { + if (c.contains(world.getName().toLowerCase())) + wc = c.getConfigurationSection(world.getName().toLowerCase()); + else + wc = c.createSection(world.getName().toLowerCase()); + } + + ConfigurationSection rs; + if (wc.contains(region.getProtectedRegion().getId())) + rs = wc.getConfigurationSection(region.getProtectedRegion().getId()); + else + rs = wc.createSection(region.getProtectedRegion().getId()); + + ConfigurationSection fs = rs.contains("flags") ? rs.getConfigurationSection("flags") : rs.createSection("flags"); + + fs.set(flag.getName(), flag.marshal((V) value)); + + try { + c.save(file); + } catch (IOException e) { + e.printStackTrace(); + } + } + public List getFlags(Region region) { + List list = new ArrayList(); + + if (c.contains(world.getName().toLowerCase())) { + ConfigurationSection wc = c.getConfigurationSection(world.getName().toLowerCase()); + if (wc.contains(region.getProtectedRegion().getId())) { + ConfigurationSection rs = wc.getConfigurationSection(region.getProtectedRegion().getId()); + if (rs.contains("flags")) { + ConfigurationSection fs = rs.getConfigurationSection("flags"); + for (Map.Entry data : fs.getValues(false).entrySet()) { + Flag flag = null; + if (data.getKey().endsWith("-group")) { + flag = FlagList.getFlag(data.getKey().substring(0, data.getKey().length() - 6)); + if (flag != null) + flag = flag.getRegionGroupFlag(); + } else { + flag = FlagList.getFlag(data.getKey()); + } + if (flag != null) { // the flag doesn't exists anymore. just ignore it without error + Object value = flag.unmarshal(data.getValue()); + list.add(new FlagValue(flag, value)); + } else { + if (mod.isDebug()) + mod.getLog().debug("Couldn't load unknown Flag: "+data.getKey()); + } + } + } + } + } + return list; + } + + public WorldGuardPlugin getWorldGuard() { + return mod.getWorldGuard(); + } + } + + public GlobalRegionManager getWGGlobalManager() { + return mod.getWorldGuard().getGlobalRegionManager(); + } + public RegionManager getWGManager(World world) { + return mod.getWorldGuard().getRegionManager(world); + } + + public String getRegionsHash(Location loc) { + StringBuilder hash = new StringBuilder(loc.getWorld().getName()); + List idlist = getWGGlobalManager().get(loc.getWorld()).getApplicableRegionsIDs(BukkitUtil.toVector(loc)); + if (idlist.size() > 0) { + hash.append("#"); + String[] ids = idlist.toArray(new String[idlist.size()]); + if (ids.length > 1) { + Arrays.sort(ids); + } + hash.append(StringUtil.join(ids, ",")); + } + return hash.toString(); + } + + public ApplicableRegions getRegionSet(Location loc) { + return new ApplicableRegions(getWGManager(loc.getWorld()).getApplicableRegions(loc), this.world(loc.getWorld())); + } + + public ApplicableRegions getRegionSet(Block block) { + return getRegionSet(block.getLocation()); + } + + public boolean isDiffrentRegion(Player player, Location loc) { + return !getRegionsHash(loc).equals(mod.getPlayerData(player).getHash()); + } +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/FlagList.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/FlagList.java new file mode 100644 index 0000000..7bd28c9 --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/FlagList.java @@ -0,0 +1,66 @@ +/* + * 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 java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.bukkit.command.CommandSender; + +import com.sk89q.worldguard.protection.flags.Flag; + +public class FlagList { + protected static List> list = new ArrayList>(); + + public static List> getFlags() { + return list; + } + public static void addFlag(Flag flag) { + list.add(flag); + } + public static void addFlags(Collection> flags) { + list.addAll(flags); + } + public static Flag getFlag(String flag) { + for (Flag f : list) { + if (f.getName().replace("-", "").equalsIgnoreCase(flag.replace("-", ""))) { + return f; + } + } + return null; + } + public static List> getAvailableFlags(CommandSender sender) { + List> result = new ArrayList>(); + for (Flag f : list) { + if (!(f instanceof IRestrictedFlag) || ((IRestrictedFlag) f).isAllowed(sender)) { + result.add(f); + } + } + return result; + } + public static String getStringListAvailableFlags(CommandSender sender) { + String result = ""; + for (Flag f : getAvailableFlags(sender)) { + if (result.length() > 0) + result += ", "; + result += f.getName(); + } + return result; + } +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/FlagValue.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/FlagValue.java new file mode 100644 index 0000000..f593183 --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/FlagValue.java @@ -0,0 +1,35 @@ +/* + * 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 com.sk89q.worldguard.protection.flags.Flag; + +public class FlagValue { + private Flag flag; + private Object value; + public FlagValue(Flag flag, Object value) { + this.flag = flag; + this.value = value; + } + public Flag getFlag() { + return flag; + } + public Object getValue() { + return value; + } +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/IRestrictedFlag.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/IRestrictedFlag.java new file mode 100644 index 0000000..5327ef3 --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/IRestrictedFlag.java @@ -0,0 +1,24 @@ +/* + * 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.command.CommandSender; + +public interface IRestrictedFlag { + public boolean isAllowed(CommandSender sender); +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/PlayerListener.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/PlayerListener.java new file mode 100644 index 0000000..b81dd96 --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/PlayerListener.java @@ -0,0 +1,107 @@ +/* + * 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.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerRespawnEvent; +import org.bukkit.event.player.PlayerTeleportEvent; + +import de.jaschastarke.minecraft.limitedcreative.ModRegions; +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; + +public class PlayerListener implements Listener { + private ModRegions mod; + + public PlayerListener(ModRegions mod) { + this.mod = mod; + } + + @EventHandler(priority=EventPriority.HIGHEST) // run very late, because the event may be cancelled + public void onPlayerMove(PlayerMoveEvent event) { + if (event.isCancelled()) + return; + + if (event.getFrom().getBlockX() != event.getTo().getBlockX() + || event.getFrom().getBlockY() != event.getTo().getBlockY() + || event.getFrom().getBlockZ() != event.getTo().getBlockZ() + || !event.getFrom().getWorld().equals(event.getTo().getWorld())) { // he really moved, and not just looked around + + String current_hash = mod.getPlayerData(event.getPlayer()).getHash(); + if (current_hash == null) { + String new_hash = mod.getRegionManager().getRegionsHash(event.getTo()); + Bukkit.getServer().getPluginManager().callEvent(new PlayerSetAreaEvent(mod.getRegionManager(), event.getPlayer(), new_hash, event.getTo())); + mod.getPlayerData(event.getPlayer()).setHash(new_hash); + } else if (mod.getRegionManager().isDiffrentRegion(event.getPlayer(), event.getTo())) { + String new_hash = mod.getRegionManager().getRegionsHash(event.getTo()); + PlayerChangedAreaEvent areaevent = new PlayerChangedAreaEvent(mod.getRegionManager(), event, current_hash, new_hash); + Bukkit.getServer().getPluginManager().callEvent(areaevent); + if (!areaevent.isCancelled()) + mod.getPlayerData(event.getPlayer()).setHash(new_hash); + } + } + } + + @EventHandler(priority=EventPriority.HIGHEST) // run very late, because the event may be cancelled + public void onPlayerTeleport(PlayerTeleportEvent event) { + onPlayerMove(event); + } + + @EventHandler + public void onPlayerRespawn(PlayerRespawnEvent event) { + String new_hash = mod.getRegionManager().getRegionsHash(event.getRespawnLocation()); + PlayerNewLocationAreaEvent areaevent = new PlayerNewLocationAreaEvent(mod.getRegionManager(), event.getPlayer(), event.getRespawnLocation(), new_hash); + Bukkit.getServer().getPluginManager().callEvent(areaevent); + mod.getPlayerData(event.getPlayer()).setHash(new_hash); + } + + @EventHandler + public void onPlayerLogin(PlayerJoinEvent event) { + String new_hash = mod.getRegionManager().getRegionsHash(event.getPlayer().getLocation()); + Bukkit.getServer().getPluginManager().callEvent(new PlayerSetAreaEvent(mod.getRegionManager(), event.getPlayer(), new_hash)); + mod.getPlayerData(event.getPlayer()).setHash(new_hash); + } + + /* Thanks to WeakReference not longer needed + @EventHandler + public void onPlayerLogout(PlayerQuitEvent event) { + CPlayer.remove(event.getPlayer()); + }*/ + + @EventHandler + public void onPlayerComamnd(PlayerCommandPreprocessEvent event) { + String[] cmd = event.getMessage().split(" "); + if (cmd.length >= 2) { + if (cmd[0].replaceAll("/", "").equalsIgnoreCase("region")) { + if (cmd[1].equalsIgnoreCase("addowner") || cmd[1].equalsIgnoreCase("addmember") || + cmd[1].equalsIgnoreCase("removeowner") || cmd[1].equalsIgnoreCase("remowner") || + cmd[1].equalsIgnoreCase("removemember") || cmd[1].equalsIgnoreCase("remmember") || + cmd[1].equalsIgnoreCase("removemem") || cmd[1].equalsIgnoreCase("remmem")) { + mod.getPlayerData().clearAllTemp(); + } + } + } + } +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/Region.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/Region.java new file mode 100644 index 0000000..681a357 --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/Region.java @@ -0,0 +1,72 @@ +/* + * 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 java.util.Iterator; +import java.util.List; + +import org.bukkit.World; + +import com.sk89q.worldguard.protection.flags.Flag; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; + +import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.CustomRegionManager.CWorld; + +public class Region { + private ProtectedRegion region; + private CWorld mgr; + private List flags = null; + + protected Region(CWorld w, ProtectedRegion reg) { + mgr = w; + region = reg; + } + + public void removeFlag(Flag flag) { + if (flags != null) { + Iterator i = flags.iterator(); + while (i.hasNext()) { + if (i.next().getFlag() == flag) + i.remove(); + } + } + mgr.storeFlag(this, flag, null); + } + + public void setFlag(Flag flag, Object value) { + if (value == null) { + removeFlag(flag); + } else { + if (flags != null) + flags.add(new FlagValue(flag, value)); + mgr.storeFlag(this, flag, value); + } + } + public ProtectedRegion getProtectedRegion() { + return region; + } + public World getWorld() { + return mgr.getWorld(); + } + public List getFlags() { + if (flags == null) { + flags = mgr.getFlags(this); + } + return flags; + } +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/events/PlayerAreaEvent.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/events/PlayerAreaEvent.java new file mode 100644 index 0000000..fcbe7c5 --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/events/PlayerAreaEvent.java @@ -0,0 +1,33 @@ +/* + * 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.events; + +import org.bukkit.entity.Player; +import org.bukkit.event.Event; + +import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.ApplicableRegions; + +public abstract class PlayerAreaEvent extends Event { + abstract public String getRegionHash(); + abstract public ApplicableRegions getRegionSet(); + abstract public Player getPlayer(); + + public String toString() { + return getClass().getSimpleName()+"["+getRegionHash()+"]"; + } +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/events/PlayerChangedAreaEvent.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/events/PlayerChangedAreaEvent.java new file mode 100644 index 0000000..8bd9899 --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/events/PlayerChangedAreaEvent.java @@ -0,0 +1,72 @@ +/* + * 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.events; + +import org.bukkit.event.Cancellable; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerTeleportEvent; + +import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.ApplicableRegions; +import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.CustomRegionManager; + +public class PlayerChangedAreaEvent extends PlayerNewLocationAreaEvent implements Cancellable { + private PlayerMoveEvent event; + private String _previous_hash; + private boolean _cancelled = false; + + public PlayerChangedAreaEvent(CustomRegionManager mgr, PlayerMoveEvent moveevent) { + super(mgr, moveevent.getPlayer(), moveevent.getTo()); + event = moveevent; + } + public PlayerChangedAreaEvent(CustomRegionManager mgr, PlayerMoveEvent moveevent, String previous_hash, String new_hash) { + super(mgr, moveevent.getPlayer(), moveevent.getTo(), new_hash); + event = moveevent; + _previous_hash = previous_hash; + } + + public boolean isTeleport() { + return event instanceof PlayerTeleportEvent; + } + + public ApplicableRegions getPreviousRegionSet() { + return mgr.getRegionSet(event.getFrom()); + } + + public String getPreviousRegionHash() { + if (_previous_hash == null) + _previous_hash = mgr.getRegionsHash(event.getFrom()); + return _previous_hash; + } + + public PlayerMoveEvent getMoveEvent() { + return event; + } + + public String toString() { + return getClass().getSimpleName()+"["+getPreviousRegionHash()+" -> "+getRegionHash()+"]"; + } + + @Override + public boolean isCancelled() { + return _cancelled; + } + @Override + public void setCancelled(boolean b) { + _cancelled = b; + } +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/events/PlayerNewLocationAreaEvent.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/events/PlayerNewLocationAreaEvent.java new file mode 100644 index 0000000..d2f3c79 --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/events/PlayerNewLocationAreaEvent.java @@ -0,0 +1,72 @@ +/* + * 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.events; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; + +import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.ApplicableRegions; +import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.CustomRegionManager; + + +public class PlayerNewLocationAreaEvent extends PlayerAreaEvent { + private Location location; + protected CustomRegionManager mgr; + private Player player; + private String _hash; + + public PlayerNewLocationAreaEvent(CustomRegionManager mgr, Player player, Location new_location) { + this.mgr = mgr; + this.player = player; + location = new_location; + } + public PlayerNewLocationAreaEvent(CustomRegionManager mgr, Player player, Location new_location, String new_hash) { + this(mgr, player, new_location); + _hash = new_hash; + } + + @Override + public String getRegionHash() { + if (_hash == null) + _hash = mgr.getRegionsHash(location); + return _hash; + } + @Override + public ApplicableRegions getRegionSet() { + return mgr.getRegionSet(location); + } + + public Player getPlayer() { + return player; + } + + public String toString() { + return getClass().getSimpleName()+"["+getRegionHash()+"]"; + } + + private static final HandlerList handlers = new HandlerList(); + + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/events/PlayerSetAreaEvent.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/events/PlayerSetAreaEvent.java new file mode 100644 index 0000000..0388493 --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/events/PlayerSetAreaEvent.java @@ -0,0 +1,69 @@ +/* + * 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.events; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; + +import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.ApplicableRegions; +import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.CustomRegionManager; + +public class PlayerSetAreaEvent extends PlayerAreaEvent { + private Player player; + private String hash; + private Location loc; + protected CustomRegionManager mgr; + + public PlayerSetAreaEvent(CustomRegionManager mgr, Player player, String hash) { + this.mgr = mgr; + this.player = player; + this.hash = hash; + } + public PlayerSetAreaEvent(CustomRegionManager mgr, Player player, String hash, Location location) { + this.mgr = mgr; + this.player = player; + this.hash = hash; + this.loc = location; + } + + @Override + public String getRegionHash() { + return hash; + } + + @Override + public ApplicableRegions getRegionSet() { + return mgr.getRegionSet(loc != null ? loc : player.getLocation()); + } + + @Override + public Player getPlayer() { + return player; + } + + private static final HandlerList handlers = new HandlerList(); + + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/events/PlayerUpdateAreaEvent.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/events/PlayerUpdateAreaEvent.java new file mode 100644 index 0000000..fcf0274 --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/regions/worldguard/events/PlayerUpdateAreaEvent.java @@ -0,0 +1,61 @@ +/* + * 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.events; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; + +import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.ApplicableRegions; +import de.jaschastarke.minecraft.limitedcreative.regions.worldguard.CustomRegionManager; + +public class PlayerUpdateAreaEvent extends PlayerAreaEvent { + private String player; + private String hash; + protected CustomRegionManager mgr; + + public PlayerUpdateAreaEvent(CustomRegionManager mgr, String player, String hash) { + this.mgr = mgr; + this.player = player; + this.hash = hash; + } + @Override + public String getRegionHash() { + return hash; + } + + @Override + public ApplicableRegions getRegionSet() { + return mgr.getRegionSet(getPlayer().getLocation()); + } + + @Override + public Player getPlayer() { + return Bukkit.getServer().getPlayerExact(player); + } + + private static final HandlerList handlers = new HandlerList(); + + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/src/main/resources/lang/messages.properties b/src/main/resources/lang/messages.properties index 43bbc19..b43c9d9 100644 --- a/src/main/resources/lang/messages.properties +++ b/src/main/resources/lang/messages.properties @@ -11,6 +11,7 @@ basic.warning.worldguard_not_found: WorldGuard isn't found, the feature {0} is d command.player: player command.general: LimitedCreative: GameMode-Switch, Creative-Regions, Config and more +command.regions: LimitedCreative-Region-Command: configure creative regions command.switch.survival: Changes the game mode of a player to survival command.switch.creative: Changes the game mode of a player to creative command.switch.adventure: Changes the game mode of a player to adventure @@ -22,13 +23,13 @@ command.gamemode.no_change: Already in that game mode. command.option.done: Option changed. command.worldguard.alias: Alias for //region-command command.worldguard.unknown_flag: Unknown flag specified -command.worldguard.available_flags: Available flags +command.worldguard.available_flags: Available flags: command.worldguard.region_not_found: Could not find a region by that ID command.worldguard.world_not_found: Could not find a world by that name command.worldguard.no_flag_given: You need to specify a flag to set command.worldguard.no_integration: The worldguard-commands are not available, because worldguard wasn't found command.worldguard.flag_set: "The flag {0} was set" -command.worldguard.additional_flags: Additional flags +command.worldguard.additional_flags: Additional flags: cmdblock.blocked: This command is blocked while in creative mode. diff --git a/src/main/resources/settings.properties b/src/main/resources/settings.properties new file mode 100644 index 0000000..ed3b3f7 --- /dev/null +++ b/src/main/resources/settings.properties @@ -0,0 +1,2 @@ +piwik_url = http://stats.ja-s.de/piwikProxy.php +piwik_site_id = 2 \ No newline at end of file