diff --git a/.gitignore b/.gitignore index 46af922..6162bc0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ /.classpath /.settings /.buildpath +/.checkstyle # maven /target diff --git a/pom.xml b/pom.xml index 5f46b73..43016b8 100644 --- a/pom.xml +++ b/pom.xml @@ -56,12 +56,12 @@ org.bukkit bukkit - 1.4.6-R0.1 + 1.4.7-R0.1 org.bukkit craftbukkit - 1.4.6-R0.1 + 1.4.7-R0.1 com.sk89q diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/Config.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/Config.java index 7399a56..38c4c69 100644 --- a/src/main/java/de/jaschastarke/minecraft/limitedcreative/Config.java +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/Config.java @@ -28,8 +28,27 @@ public class Config extends PluginConfiguration { super.save(); } + /** + * Metrics + * + * This settings allows the Addon-Author to track the Servers using this plugin. It will not track any player + * related data like names, ips, online time or such. Please do not disable the option! As more servers are using + * the plugin and the author knows, as more he is willing to support the plugin! Its a win-win for both. + * + * default: true + * @TODO Move to a sub-class modular configuration + */ + @IsConfigurationNode(order = 1000) + public boolean getMetrics() { + return config.getBoolean("metrics", true); + } + /** * Debug + * + * The debug modus spams much details about the plugin to the server-log (console) which can help to solve issues. + * + * default: false */ @IsConfigurationNode(order = 9999) public boolean getDebug() { diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/FeatureMetrics.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/FeatureMetrics.java new file mode 100644 index 0000000..14e0a8c --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/FeatureMetrics.java @@ -0,0 +1,41 @@ +package de.jaschastarke.minecraft.limitedcreative; + +import org.bukkit.event.Listener; + +import de.jaschastarke.bukkit.lib.CoreModule; +import de.jaschastarke.bukkit.tools.stats.IStatistics; +import de.jaschastarke.bukkit.tools.stats.PiwikStatistics; +import de.jaschastarke.modularize.IModule; +import de.jaschastarke.modularize.ModuleEntry; +import de.jaschastarke.modularize.ModuleEntry.ModuleState; + +public class FeatureMetrics extends CoreModule implements Listener { + public FeatureMetrics(LimitedCreative plugin) { + super(plugin); + } + private IStatistics metric; + + @Override + public void initialize(ModuleEntry pEntry) { + super.initialize(pEntry); + if (!plugin.getPluginConfig().getMetrics()) { + pEntry.initialState = ModuleState.DISABLED; + } + } + + @Override + public void onEnable() { + metric = new PiwikStatistics(plugin); + } + + @Override + public void onDisable() { + metric.unregister(); + } + + public void track(String event) { + if (metric == null) + throw new IllegalAccessError("The feature hasn't been enabled"); + metric.trackEvent(event); + } +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/FeatureSwitchGameMode.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/FeatureSwitchGameMode.java index 2aebe9e..cae9fdb 100644 --- a/src/main/java/de/jaschastarke/minecraft/limitedcreative/FeatureSwitchGameMode.java +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/FeatureSwitchGameMode.java @@ -16,7 +16,7 @@ import de.jaschastarke.bukkit.lib.commands.ICommand; import de.jaschastarke.bukkit.lib.commands.MethodCommand; import de.jaschastarke.bukkit.lib.commands.IMethodCommandContainer; import de.jaschastarke.bukkit.lib.commands.MissingPermissionCommandException; -import de.jaschastarke.bukkit.lib.commands.NeedsPlayerCommandException; +import de.jaschastarke.bukkit.lib.commands.NeedsPlayerArgumentCommandException; import de.jaschastarke.bukkit.lib.commands.annotations.Alias; import de.jaschastarke.bukkit.lib.commands.annotations.Description; import de.jaschastarke.bukkit.lib.commands.annotations.IsCommand; @@ -37,14 +37,14 @@ public class FeatureSwitchGameMode extends CoreModule { } @Override - public void OnEnable() { + public void onEnable() { if (commands == null) commands = new Commands(); plugin.getMainCommand().getHandler().registerCommands(commands.getCommandList()); } @Override - public void OnDisable() { + public void onDisable() { if (commands != null) plugin.getMainCommand().getHandler().removeCommands(commands.getCommandList()); } @@ -66,20 +66,23 @@ public class FeatureSwitchGameMode extends CoreModule { protected boolean changeGameMode(CommandContext context, String player, GameMode tgm, IAbstractPermission permission) throws MissingPermissionCommandException, CommandException { Player target = null; - if (player != null && !player.isEmpty()) + if (player != null && !player.isEmpty()) { target = Bukkit.getPlayer(player); - else if (context.isPlayer()) + if (target == null) + throw new CommandException("Player " + player + " not found"); + } else if (context.isPlayer()) { target = context.getPlayer(); + } if (target == null) - throw new NeedsPlayerCommandException(); + throw new NeedsPlayerArgumentCommandException(); if (!target.equals(context.getSender()) && !context.checkPermission(SwitchGameModePermissions.OTHER)) throw new MissingPermissionCommandException(SwitchGameModePermissions.OTHER); GameMode wgm = Hooks.DefaultWorldGameMode.get(target.getWorld()); - if (context.checkPermission(permission) || (wgm == tgm && context.checkPermission(SwitchGameModePermissions.BACKONLY))) + if (!context.checkPermission(permission) && !(wgm != tgm || !context.checkPermission(SwitchGameModePermissions.BACKONLY))) throw new MissingPermissionCommandException(permission); target.setGameMode(tgm); diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/LimitedCreative.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/LimitedCreative.java index 802b32f..70d72ed 100644 --- a/src/main/java/de/jaschastarke/minecraft/limitedcreative/LimitedCreative.java +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/LimitedCreative.java @@ -1,22 +1,25 @@ package de.jaschastarke.minecraft.limitedcreative; -import de.jaschastarke.i18n; +import de.jaschastarke.I18n; import de.jaschastarke.bukkit.lib.Core; import de.jaschastarke.bukkit.lib.PluginLang; +import de.jaschastarke.bukkit.lib.configuration.ConfigCommand; public class LimitedCreative extends Core { protected Config config = null; protected MainCommand command = null; @Override - public void OnInitialize() { - super.OnInitialize(); + public void onInitialize() { + super.onInitialize(); config = new Config(this); - this.debug = config.getDebug(); setLang(new PluginLang("lang/messages", this)); command = new MainCommand(this); + ConfigCommand cc = new ConfigCommand(config, Permissions.CONFIG); + cc.setPackageName(this.getName() + " - " + this.getLocale().trans(cc.getPackageName())); + command.registerCommand(cc); commands.registerCommand(command); Hooks.inizializeHooks(this); @@ -26,15 +29,21 @@ public class LimitedCreative extends Core { addModule(new ModCreativeLimits(this)); addModule(new ModRegions(this)); addModule(new ModCmdBlocker(this)); + addModule(new FeatureMetrics(this)); config.saveDefault(); } + @Override + public boolean isDebug() { + return config.getDebug(); + } + public Config getPluginConfig() { return config; } - public i18n getLocale() { + public I18n getLocale() { return getLang(); } diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/ModCreativeLimits.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/ModCreativeLimits.java index 545942b..ff47961 100644 --- a/src/main/java/de/jaschastarke/minecraft/limitedcreative/ModCreativeLimits.java +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/ModCreativeLimits.java @@ -1,19 +1,26 @@ package de.jaschastarke.minecraft.limitedcreative; import de.jaschastarke.bukkit.lib.CoreModule; +import de.jaschastarke.minecraft.limitedcreative.limits.LimitConfig; import de.jaschastarke.modularize.IModule; import de.jaschastarke.modularize.ModuleEntry; public class ModCreativeLimits extends CoreModule { + protected LimitConfig config; + public ModCreativeLimits(LimitedCreative plugin) { super(plugin); } + public LimitConfig getConfig() { + return config; + } + protected FeatureBlockItemSpawn blockDrops = null; @Override - public void Initialize(ModuleEntry entry) { - super.Initialize(entry); + public void initialize(ModuleEntry entry) { + super.initialize(entry); blockDrops = plugin.getModule(FeatureBlockItemSpawn.class); if (blockDrops == null) blockDrops = plugin.addModule(new FeatureBlockItemSpawn(plugin)).getModule(); diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/ModInventories.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/ModInventories.java index 5e73ca1..1351d32 100644 --- a/src/main/java/de/jaschastarke/minecraft/limitedcreative/ModInventories.java +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/ModInventories.java @@ -18,6 +18,7 @@ import de.jaschastarke.minecraft.limitedcreative.inventories.store.InvYamlStorag import de.jaschastarke.minecraft.limitedcreative.inventories.store.PlayerInventoryStorage; import de.jaschastarke.modularize.IModule; import de.jaschastarke.modularize.ModuleEntry; +import de.jaschastarke.modularize.ModuleEntry.ModuleState; public class ModInventories extends CoreModule { protected PlayerInventoryStorage storage; @@ -34,20 +35,30 @@ public class ModInventories extends CoreModule { } @Override - public void Initialize(ModuleEntry entry) { - super.Initialize(entry); + public void initialize(ModuleEntry entry) { + super.initialize(entry); listeners.addListener(new PlayerListener(this)); - config = plugin.getPluginConfig().registerSection(new InventoryConfig(this)); + config = plugin.getPluginConfig().registerSection(new InventoryConfig(this, entry)); armor_config = config.registerSection(new ArmoryConfig(this)); + if (!config.getEnabled()) { + entry.initialState = ModuleState.DISABLED; + return; + } + String incomp = Hooks.InventoryIncompatible.test(); if (incomp != null) { getLog().warn(plugin.getLocale().trans("basic.conflict", incomp, this.getName())); + entry.initialState = ModuleState.NOT_INITIALIZED; } } @Override - public void OnEnable() { - super.OnEnable(); + public void onEnable() { + String incomp = Hooks.InventoryIncompatible.test(); + if (incomp != null) { + throw new IllegalAccessError(plugin.getLocale().trans("basic.conflict", incomp, this.getName())); + } + super.onEnable(); storage = new InvYamlStorage(this, new File(plugin.getDataFolder(), config.getFolder())); inventories = new WeakHashMap(); getLog().info(plugin.getLocale().trans("basic.loaded.module")); diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/inventories/ArmoryConfig.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/inventories/ArmoryConfig.java index 93b18a1..42f353d 100644 --- a/src/main/java/de/jaschastarke/minecraft/limitedcreative/inventories/ArmoryConfig.java +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/inventories/ArmoryConfig.java @@ -11,7 +11,7 @@ import de.jaschastarke.bukkit.lib.ModuleLogger; import de.jaschastarke.bukkit.lib.configuration.Configuration; import de.jaschastarke.bukkit.lib.items.MaterialDataNotRecognizedException; import de.jaschastarke.bukkit.lib.items.MaterialNotRecognizedException; -import de.jaschastarke.bukkit.lib.items.Utils; +import de.jaschastarke.bukkit.lib.items.ItemUtils; import de.jaschastarke.configuration.IConfigurationSubGroup; import de.jaschastarke.configuration.annotations.IsConfigurationNode; import de.jaschastarke.maven.ArchiveDocComments; @@ -28,6 +28,12 @@ public class ArmoryConfig extends Configuration implements IConfigurationSubGrou public ArmoryConfig(ModInventories modInventories) { mod = modInventories; } + + @Override + public boolean isReadOnly() { + return false; + } + @Override public void setValues(ConfigurationSection sect) { if (sect == null || sect.getValues(false).size() == 0) { @@ -68,7 +74,7 @@ public class ArmoryConfig extends Configuration implements IConfigurationSubGrou } else { MaterialData md = null; try { - md = Utils.parseMaterial((String) entry.getValue()); + md = ItemUtils.parseMaterial((String) entry.getValue()); } catch (MaterialNotRecognizedException e) { getLog().warn(L("exception.config.material_not_found", entry.getValue())); } catch (MaterialDataNotRecognizedException e) { diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/inventories/InventoryConfig.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/inventories/InventoryConfig.java index 4b1f7e1..60f46a8 100644 --- a/src/main/java/de/jaschastarke/minecraft/limitedcreative/inventories/InventoryConfig.java +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/inventories/InventoryConfig.java @@ -3,10 +3,14 @@ package de.jaschastarke.minecraft.limitedcreative.inventories; import org.bukkit.configuration.ConfigurationSection; 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.maven.ArchiveDocComments; import de.jaschastarke.minecraft.limitedcreative.ModInventories; +import de.jaschastarke.modularize.IModule; +import de.jaschastarke.modularize.ModuleEntry; /** * Inventory-Feature @@ -15,10 +19,32 @@ import de.jaschastarke.minecraft.limitedcreative.ModInventories; */ @ArchiveDocComments public class InventoryConfig extends Configuration implements IConfigurationSubGroup { + protected ModInventories mod; - public InventoryConfig(ModInventories modInventories) { + protected ModuleEntry entry; + + public InventoryConfig(ModInventories modInventories, ModuleEntry modEntry) { mod = modInventories; + entry = modEntry; } + + @Override + public boolean isReadOnly() { + return false; + } + + @Override + public void setValue(IConfigurationNode node, Object pValue) throws InvalidValueException { + super.setValue(node, pValue); + if (node.getName().equals("enabled")) { + if ((Boolean) pValue) { + entry.activate(); + } else { + entry.disable(); + } + } + } + @Override public void setValues(ConfigurationSection sect) { if (sect == null || sect.getValues(false).size() == 0) { @@ -91,7 +117,7 @@ public class InventoryConfig extends Configuration implements IConfigurationSubG * * default: "inventories" */ - @IsConfigurationNode(order = 400) + @IsConfigurationNode(order = 400, readonly = true) public String getFolder() { return config.getString("folder", "inventories"); } diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/BlackList.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/BlackList.java new file mode 100644 index 0000000..f691b24 --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/BlackList.java @@ -0,0 +1,120 @@ +package de.jaschastarke.minecraft.limitedcreative.limits; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.inventory.ItemStack; +import org.bukkit.material.MaterialData; + +import de.jaschastarke.bukkit.lib.configuration.ConfigurableList; +import de.jaschastarke.bukkit.lib.items.ItemUtils; +import de.jaschastarke.bukkit.lib.items.MaterialDataNotRecognizedException; +import de.jaschastarke.bukkit.lib.items.MaterialNotRecognizedException; + +public class BlackList extends ArrayList implements ConfigurableList { + private static final long serialVersionUID = -3701659163474405152L; + + public static class Blacklisted { + private String stringRep; + private MaterialData md; + private boolean hasData = false; + + public Blacklisted(String rep) { + stringRep = rep; + try { + md = ItemUtils.parseMaterial(rep); + hasData = rep.contains(ItemUtils.MATERIAL_DATA_SEP); + } catch (MaterialNotRecognizedException e) { + throw new IllegalArgumentException(e); + } catch (MaterialDataNotRecognizedException e) { + throw new IllegalArgumentException(e); + } + } + public Blacklisted(Material m) { + md = new MaterialData(m); + stringRep = m.toString(); + } + public Blacklisted(MaterialData md) { + this.md = md; + stringRep = md.getItemType().toString() + ItemUtils.MATERIAL_DATA_SEP + Integer.toString(md.getData()); + } + + public boolean matches(ItemStack item) { + if (hasData) { + return md.equals(item.getData()); + } else { + return item.getType().equals(md.getItemType()); + } + } + public boolean matches(Block block) { + if (hasData) { + return md.equals(block.getData()); + } else { + return block.getType().equals(md.getItemType()); + } + } + public String toString() { + return stringRep; + } + } + + + public BlackList() { + } + + public BlackList(List list) { + if (list != null) { + for (Object el : list) { + if (el instanceof Blacklisted) + add((Blacklisted) el); + else + add(el.toString()); + } + } + } + + public boolean contains(String e) { + for (Blacklisted bl : this) { + if (bl.toString().equals(e)) + return true; + } + return false; + } + + public boolean isListed(ItemStack item) { + for (Blacklisted bl : this) { + if (bl.matches(item)) + return true; + } + return false; + } + public boolean isListed(Block block) { + for (Blacklisted bl : this) { + if (bl.matches(block)) + return true; + } + return false; + } + + @Override // ConfigurableList, not List + public void add(String e) { + if (!contains(e)) { + add(new Blacklisted(e)); + } + } + + @Override // ConfigurableList, not List + public boolean remove(String e) { + Iterator it = iterator(); + while (it.hasNext()) { + if (it.next().toString().equals(e)) { + it.remove(); + return true; + } + } + return false; + } +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/BlockListener.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/BlockListener.java new file mode 100644 index 0000000..083dd02 --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/BlockListener.java @@ -0,0 +1,62 @@ +/* + * 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.limits; + +import org.bukkit.GameMode; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; + +import de.jaschastarke.minecraft.lib.permissions.IDynamicPermission; +import de.jaschastarke.minecraft.limitedcreative.ModCreativeLimits; + +public class BlockListener implements Listener { + private ModCreativeLimits mod; + public BlockListener(ModCreativeLimits mod) { + this.mod = mod; + } + + @EventHandler + public void onBlockBreak(BlockBreakEvent event) { + if (!event.isCancelled() && event.getPlayer().getGameMode() == GameMode.CREATIVE) { + if (mod.getConfig().getBlockBreak().isListed(event.getBlock())) { + if (!checkPermission(event.getPlayer(), NoLimitPermissions.BREAK(event.getBlock()))) { + event.setCancelled(true); + event.getPlayer().sendMessage(mod.getPlugin().getLocale().trans("blocked.break")); + } + } + } + } + @EventHandler + public void onBlockPlace(BlockPlaceEvent event) { + if (!event.isCancelled() && event.getPlayer().getGameMode() == GameMode.CREATIVE) { + if (mod.getConfig().getBlockUse().isListed(event.getBlock())) { + if (!checkPermission(event.getPlayer(), NoLimitPermissions.USE(event.getBlock()))) { + event.setCancelled(true); + event.getPlayer().sendMessage(mod.getPlugin().getLocale().trans("blocked.place")); + } + } + } + } + + private boolean checkPermission(Player player, IDynamicPermission perm) { + return mod.getPlugin().getPermManager().hasPermission(player, perm); + } +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/EntityListener.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/EntityListener.java new file mode 100644 index 0000000..37c7e40 --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/EntityListener.java @@ -0,0 +1,55 @@ +/* + * 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.limits; + +import org.bukkit.GameMode; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityTargetEvent; + +import de.jaschastarke.minecraft.lib.permissions.IAbstractPermission; +import de.jaschastarke.minecraft.limitedcreative.ModCreativeLimits; + +public class EntityListener implements Listener { + private ModCreativeLimits mod; + public EntityListener(ModCreativeLimits mod) { + this.mod = mod; + } + + /** + * don't let the player be target by creatures he can't kill + */ + @EventHandler + public void onEntityTargetPlayer(EntityTargetEvent event) { + if (event.getTarget() instanceof Player && !event.isCancelled()) { + if (event.getEntity() instanceof Creature) { + if (((Player) event.getTarget()).getGameMode() == GameMode.CREATIVE && mod.getConfig().getBlockDamageMob()) { + if (!checkPermission((Player) event.getTarget(), NoLimitPermissions.MOB_DAMAGE)) { + event.setCancelled(true); + } + } + } + } + } + + private boolean checkPermission(Player player, IAbstractPermission perm) { + return mod.getPlugin().getPermManager().hasPermission(player, perm); + } +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/LimitConfig.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/LimitConfig.java new file mode 100644 index 0000000..7b477ba --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/LimitConfig.java @@ -0,0 +1,243 @@ +package de.jaschastarke.minecraft.limitedcreative.limits; + +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; + +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.maven.ArchiveDocComments; +import de.jaschastarke.minecraft.limitedcreative.ModCreativeLimits; +import de.jaschastarke.modularize.IModule; +import de.jaschastarke.modularize.ModuleEntry; + +/** + * Creative Limits-Feature + * + * http://dev.bukkit.org/server-mods/limited-creative/pages/features/limit/ + */ +@ArchiveDocComments +public class LimitConfig extends Configuration implements IConfigurationSubGroup { + + protected ModCreativeLimits mod; + protected ModuleEntry entry; + + public LimitConfig(ModCreativeLimits modInventories, ModuleEntry modEntry) { + mod = modInventories; + entry = modEntry; + } + + @Override + public boolean isReadOnly() { + return false; + } + + @Override + public void setValue(IConfigurationNode node, Object pValue) throws InvalidValueException { + super.setValue(node, pValue); + if (node.getName().equals("enabled")) { + if ((Boolean) pValue) { + entry.activate(); + } else { + entry.disable(); + } + } + } + + @Override + public void setValues(ConfigurationSection sect) { + super.setValues(sect); + + // Config Upgrade + if (!sect.contains("interact") && sect.contains("sign")) { + interactList = new BlackList(); + if (config.getBoolean("sign", true)) { + interactList.add(new BlackList.Blacklisted(Material.SIGN)); + interactList.add(new BlackList.Blacklisted(Material.SIGN_POST)); + } + if (config.getBoolean("button", false)) { + interactList.add(new BlackList.Blacklisted(Material.LEVER)); + interactList.add(new BlackList.Blacklisted(Material.STONE_BUTTON)); + interactList.add(new BlackList.Blacklisted(Material.WOOD_BUTTON)); + } + if (config.getBoolean("workbench", false)) { + interactList.add(new BlackList.Blacklisted(Material.WORKBENCH)); + interactList.add(new BlackList.Blacklisted(Material.ANVIL)); + interactList.add(new BlackList.Blacklisted(Material.ENCHANTMENT_TABLE)); + } + } + if (!sect.contains("removeDrops") && sect.contains("remove_drops")) + sect.set("removeDrops", sect.getBoolean("remove_drops")); + if (!sect.contains("damageToMobs") && sect.contains("damagemob")) + sect.set("damageToMobs", sect.getBoolean("damagemob")); + } + @Override + public String getName() { + return "limit"; + } + @Override + public int getOrder() { + return 200; + } + + /** + * LimitEnabled + * + * Prevents all players in creative-mode from: + * - accessing chests + * - dropping items from "inventory" to the ground + * - doing PvP (wouldn't be fair, would it?) + * + * Also if this option is disabled all other Limit-Options below are disabled too. To just disable some of these + * limitations, use the "nolimit"-permissions. + * + * default: true + */ + @IsConfigurationNode(order = 100) + public boolean getEnabled() { + return config.getBoolean("enabled", true); + } + + /** + * LimitDropsInsteadPrevent + * + * When enabled items that are dropped by creative players are removed (burning in the hellfire or so, they just + * disappear). When disabled the items stay in the inventory of the player. + * + * default: false + */ + @IsConfigurationNode(order = 200) + public boolean getRemoveDrops() { + return config.getBoolean("removeDrops", false); + } + + + public static enum BlockPickup { + PREVENT, + REMOVE; + } + + /** + * LimitDamageToMobs + * + * Prevents dealing damage to all creatures when the player is in creative (friendly sheeps as well as hostile + * creepers). + * + * default: false + */ + @IsConfigurationNode(name = "damageToMobs", order = 300) + public boolean getBlockDamageMob() { + return config.getBoolean("damageToMobs", false); + } + + + /** + * LimitPickup + * + * Prevents the pickup of items while in creative mode. Either the items are just stay on ground and ignore that a + * creative player walks over it ("prevent"), or the are "remove"d when a creative player walks over it. This is + * helpful e.g. when the creative player destroys a long line of rails. + * + * valid options: remove / prevent / false + * default: remove + */ + @IsConfigurationNode(name = "pickup", order = 300) + public BlockPickup getBlockPickup() { + return getEnum(BlockPickup.class, "pickup", BlockPickup.PREVENT); + } + + + private BlackList interactList; + /** + * LimitInteraction + * + * Prevents players of using interacting with specific blocks as addition to chests in creative mode (and only in + * creative). + * + * You can use the technical name (see http://jd.bukkit.org/doxygen/d6/d0e/enumorg_1_1bukkit_1_1Material.html) or + * the id of the block/item (better use the id, if you're not sure). You may add the data separated with a colon + * e.g.: "WOOL:11" blocks blue wool. But be sure to put it in quotes, to not break yml-configuration! Named data + * values aren't supported yet. If you don't add a data-value, all blocks of this material are blocked. + * + * default: + * - SIGN + * - SIGN_POST + * - LEVER + * - STONE_BUTTON + * - WOOD_BUTTON + * - WORKBENCH + * - ANVIL + * - ENCHANTMENT_TABLE + */ + @IsConfigurationNode(name = "interact", order = 600) + public BlackList getBlockInteraction() { + if (interactList == null) { + interactList = new BlackList(config.getList("interact")); + if (!config.contains("interact")) { + interactList.add(new BlackList.Blacklisted(Material.SIGN)); + interactList.add(new BlackList.Blacklisted(Material.SIGN_POST)); + interactList.add(new BlackList.Blacklisted(Material.LEVER)); + interactList.add(new BlackList.Blacklisted(Material.STONE_BUTTON)); + interactList.add(new BlackList.Blacklisted(Material.WOOD_BUTTON)); + interactList.add(new BlackList.Blacklisted(Material.WORKBENCH)); + interactList.add(new BlackList.Blacklisted(Material.ANVIL)); + interactList.add(new BlackList.Blacklisted(Material.ENCHANTMENT_TABLE)); + } + } + return interactList; + } + + private BlackList useList; + /** + * LimitUse + * + * Prevents players of using or placing specific items/blocks in creative mode (and only in creative). + * + * You can use the technical name (see http://jd.bukkit.org/doxygen/d6/d0e/enumorg_1_1bukkit_1_1Material.html) or + * the id of the block/item (better use the id, if you're not sure). You may add the data separated with a colon + * e.g.: "WOOL:11" blocks blue wool. But be sure to put it in quotes, to not break yml-configuration! Named data + * values aren't supported yet. If you don't add a data-value, all blocks of this material are blocked. + * + * default: + * - EXP_BOTTLE + * - BEDROCK + */ + @IsConfigurationNode(name = "use", order = 700) + public BlackList getBlockUse() { + if (useList == null) { + useList = new BlackList(config.getList("use")); + if (!config.contains("use")) { + useList.add(new BlackList.Blacklisted(Material.EXP_BOTTLE)); + useList.add(new BlackList.Blacklisted(Material.BEDROCK)); + } + } + return useList; + } + + private BlackList breakList; + /** + * LimitBreak + * + * Prevents players of destroying specific blocks in creative mode (and only in creative). + * + * You can use the technical name (see http://jd.bukkit.org/doxygen/d6/d0e/enumorg_1_1bukkit_1_1Material.html) or + * the id of the block/item (better use the id, if you're not sure). You may add the data separated with a colon + * e.g.: "WOOL:11" blocks blue wool. But be sure to put it in quotes, to not break yml-configuration! Named data + * values aren't supported yet. If you don't add a data-value, all blocks of this material are blocked. + * + * default: + * - BEDROCK + */ + @IsConfigurationNode(name = "break", order = 800) + public BlackList getBlockBreak() { + if (breakList == null) { + breakList = new BlackList(config.getList("use")); + if (!config.contains("break")) { + breakList.add(new BlackList.Blacklisted(Material.BEDROCK)); + } + } + return breakList; + } +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/NoLimitPermissions.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/NoLimitPermissions.java new file mode 100644 index 0000000..ac908dc --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/NoLimitPermissions.java @@ -0,0 +1,118 @@ +/* + * 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.limits; + +import java.util.Collection; + +import org.bukkit.block.Block; +import org.bukkit.material.MaterialData; +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.IPermissionContainer; +import de.jaschastarke.minecraft.lib.permissions.IsChildPermission; +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 static final IPermissionContainer PARENT = new SimplePermissionContainerNode(Permissions.CONTAINER, "nolimit"); + + /** + * Grants bypassing of all nolimit-permissions. + */ + public static final IPermission ALL = new NoLimitPermissions(PARENT, "*", PermissionDefault.OP); + + /** + * Allows bypassing the "do not open a chest"-limitation + */ + @IsChildPermission + public static final IPermission CHEST = new BasicPermission(PARENT, "chest", PermissionDefault.FALSE); + /** + * Allows bypassing the "do not drop anything"-limitation + */ + @IsChildPermission + public static final IPermission DROP = new BasicPermission(PARENT, "drop", PermissionDefault.FALSE); + /** + * Allows bypassing the "do not pickup anything"-limitation + */ + @IsChildPermission + public static final IPermission PICKUP = new BasicPermission(PARENT, "pickup", PermissionDefault.FALSE); + /** + * Allows bypassing the "no pvp"-limitation + */ + @IsChildPermission + public static final IPermission PVP = new BasicPermission(PARENT, "pvp", PermissionDefault.FALSE); + /** + * Allows bypassing the "no dealing damage to creatures"-limitation + */ + @IsChildPermission + public static final IPermission MOB_DAMAGE = new BasicPermission(PARENT, "mob_damage", PermissionDefault.FALSE); + /** + * Allows bypassing the "do not interact with specific blocks"-limitation + */ + @IsChildPermission + public static final IPermission BASE_INTERACT = new BasicPermission(PARENT, "interact", PermissionDefault.FALSE); + /** + * Allows bypassing the "block place/item use"-limitation + */ + @IsChildPermission + public static final IPermission BASE_USE = new BasicPermission(PARENT, "use", PermissionDefault.FALSE); + /** + * Allows bypassing the "block break"-limitation + */ + @IsChildPermission + public static final IPermission BASE_BREAK = new BasicPermission(PARENT, "break", PermissionDefault.FALSE); + + public static IDynamicPermission INTERACT(Block block) { + return new MaterialPermission(BASE_INTERACT, new MaterialData(block.getType(), block.getData())); + } + public static IDynamicPermission USE(Block block) { + return new MaterialPermission(BASE_USE, new MaterialData(block.getType(), block.getData())); + } + public static IDynamicPermission USE(MaterialData m) { + return new MaterialPermission(BASE_USE, m); + } + public static IDynamicPermission BREAK(Block block) { + return new MaterialPermission(BASE_BREAK, new MaterialData(block.getType(), block.getData())); + } + + public static class MaterialPermission extends DynamicPermission { + private MaterialData md; + public MaterialPermission(IAbstractPermission parent, MaterialData m) { + super(parent); + md = m; + } + + @Override + protected void buildPermissionsToCheck(Collection perms) { + perms.add(new BasicPermission(parent, md.getItemType().toString())); + perms.add(new BasicPermission(parent, md.getItemType().toString() + IAbstractPermission.SEP + md.getData())); + } + } +} diff --git a/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/PlayerListener.java b/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/PlayerListener.java new file mode 100644 index 0000000..2f09666 --- /dev/null +++ b/src/main/java/de/jaschastarke/minecraft/limitedcreative/limits/PlayerListener.java @@ -0,0 +1,209 @@ +/* + * 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.limits; + +import org.bukkit.GameMode; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.ItemFrame; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.StorageMinecart; +import org.bukkit.entity.Villager; +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.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerPickupItemEvent; +import org.bukkit.inventory.InventoryHolder; + +import de.jaschastarke.minecraft.lib.permissions.IAbstractPermission; +import de.jaschastarke.minecraft.lib.permissions.IDynamicPermission; +import de.jaschastarke.minecraft.limitedcreative.ModCreativeLimits; +import de.jaschastarke.minecraft.limitedcreative.limits.LimitConfig.BlockPickup; + +public class PlayerListener implements Listener { + private ModCreativeLimits mod; + public PlayerListener(ModCreativeLimits mod) { + this.mod = mod; + } + + /** + * 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; + } + + @EventHandler + public void onPlayerDropItem(PlayerDropItemEvent event) { + if (!event.isCancelled() && event.getPlayer().getGameMode() == GameMode.CREATIVE) { + if (checkPermission(event, NoLimitPermissions.DROP)) + return; + + event.getItemDrop().remove(); + //event.setCancelled(true); // doesn't make much sense + } + } + + @EventHandler + public void onEntityDeath(EntityDeathEvent event) { + if (event.getEntity() instanceof Player) { + Player player = (Player) event.getEntity(); + if (player.getGameMode() == GameMode.CREATIVE) { + if (checkPermission(player, NoLimitPermissions.DROP)) + return; + event.getDrops().clear(); + } + } + } + + @EventHandler + public void onPlayerPickupItem(PlayerPickupItemEvent event) { + if (!event.isCancelled() && event.getPlayer().getGameMode() == GameMode.CREATIVE) { + LimitConfig.BlockPickup pickup = mod.getConfig().getBlockPickup(); + if (pickup != null) { + if (checkPermission(event, NoLimitPermissions.DROP)) + return; + + if (pickup == BlockPickup.REMOVE) { + event.getItem().remove(); + } + event.setCancelled(true); + } + } + } + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + if (!isCancelled(event) && event.getPlayer().getGameMode() == GameMode.CREATIVE) { + if (mod.getConfig().getBlockUse().isListed(event.getItem())) { + if (!checkPermission(event, NoLimitPermissions.USE(event.getItem().getData()))) { + event.setCancelled(true); + event.setUseItemInHand(Event.Result.DENY); + event.getPlayer().sendMessage(mod.getPlugin().getLocale().trans("blocked.use")); + return; + } + } + if (event.getAction() == Action.RIGHT_CLICK_BLOCK) { + Block block = event.getClickedBlock(); + if (isChest(block)) { + if (!checkPermission(event, NoLimitPermissions.CHEST)) { + event.setCancelled(true); + event.getPlayer().sendMessage(mod.getPlugin().getLocale().trans("blocked.chest")); + return; + } + } else if (mod.getConfig().getBlockInteraction().isListed(block)) { + if (!checkPermission(event, NoLimitPermissions.INTERACT(block))) { + event.setCancelled(true); + event.getPlayer().sendMessage(mod.getPlugin().getLocale().trans("blocked.interact")); + return; + } + } + } + } + } + @EventHandler + public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { + if (!event.isCancelled() && event.getPlayer().getGameMode() == GameMode.CREATIVE) { + if (mod.getConfig().getBlockUse().isListed(event.getPlayer().getItemInHand())) { + if (!checkPermission(event, NoLimitPermissions.USE(event.getPlayer().getItemInHand().getData()))) { + event.setCancelled(true); + event.getPlayer().sendMessage(mod.getPlugin().getLocale().trans("blocked.use")); + return; + } + } + Entity entity = event.getRightClicked(); + if (isChest(entity)) { + if (!checkPermission(event, NoLimitPermissions.CHEST)) { + event.setCancelled(true); + event.getPlayer().sendMessage(mod.getPlugin().getLocale().trans("blocked.chest")); + return; + } + } else if (entity instanceof Villager && mod.getConfig().getBlockInteraction().size() > 0) { + if (!checkPermission(event, NoLimitPermissions.BASE_INTERACT)) { + event.setCancelled(true); + event.getPlayer().sendMessage(mod.getPlugin().getLocale().trans("blocked.entity")); + return; + } + } + } + } + + @EventHandler + public void onEntityDamageByEntity(EntityDamageEvent rawevent) { + if (rawevent instanceof EntityDamageByEntityEvent && !rawevent.isCancelled()) { + EntityDamageByEntityEvent event = (EntityDamageByEntityEvent) rawevent; + + Entity source = event.getDamager(); + if (source instanceof Projectile) + source = ((Projectile) source).getShooter(); + + if (source instanceof Player) { + Player player = (Player) source; + if (player.getGameMode() == GameMode.CREATIVE) { + if (event.getEntity() instanceof Player) { + if (!checkPermission(player, NoLimitPermissions.PVP)) { + event.setCancelled(true); + } + } else if (event.getEntity() instanceof LivingEntity && mod.getConfig().getBlockDamageMob()) { + if (!checkPermission(player, NoLimitPermissions.MOB_DAMAGE)) { + event.setCancelled(true); + } + } + } + } + } + } + + /** + * Returns if the block is a chest or an other inventory-holder, that can hold items. + */ + private boolean isChest(Block block) { + return block.getState() instanceof InventoryHolder || + block.getType() == Material.ENDER_CHEST || block.getType() == Material.BEACON; // Workaround, Bukkit not recognize a Enderchests/Beacons + } + /** + * Returns if the entity can hold items. Like storage minecarts or item-frames. + */ + private boolean isChest(Entity entity) { + return entity instanceof StorageMinecart || entity instanceof ItemFrame; + } + + private boolean checkPermission(Player player, IAbstractPermission perm) { + return mod.getPlugin().getPermManager().hasPermission(player, perm); + } + private boolean checkPermission(PlayerEvent event, IAbstractPermission perm) { + return mod.getPlugin().getPermManager().hasPermission(event.getPlayer(), perm); + } + private boolean checkPermission(PlayerEvent event, IDynamicPermission perm) { + return mod.getPlugin().getPermManager().hasPermission(event.getPlayer(), perm); + } +}