From 2e6faff8c103b6a8cc92a228b38d33fd2c7b520d Mon Sep 17 00:00:00 2001 From: sk89q Date: Sun, 31 Aug 2014 19:17:05 -0700 Subject: [PATCH] Add option to whiteist some blocks / items so they can always be used. Closes WORLDGUARD-3159. --- .../worldguard/bukkit/WorldConfiguration.java | 29 +++++++- .../listener/EventAbstractionListener.java | 14 +++- .../bukkit/util/TargetMatcherSet.java | 73 +++++++++++++++++++ 3 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/sk89q/worldguard/bukkit/util/TargetMatcherSet.java diff --git a/src/main/java/com/sk89q/worldguard/bukkit/WorldConfiguration.java b/src/main/java/com/sk89q/worldguard/bukkit/WorldConfiguration.java index bae4a93a..48a22a95 100644 --- a/src/main/java/com/sk89q/worldguard/bukkit/WorldConfiguration.java +++ b/src/main/java/com/sk89q/worldguard/bukkit/WorldConfiguration.java @@ -26,7 +26,10 @@ import com.sk89q.worldguard.blacklist.logger.ConsoleHandler; import com.sk89q.worldguard.blacklist.logger.DatabaseHandler; import com.sk89q.worldguard.blacklist.logger.FileHandler; +import com.sk89q.worldguard.blacklist.target.TargetMatcherParseException; +import com.sk89q.worldguard.blacklist.target.TargetMatcherParser; import com.sk89q.worldguard.bukkit.commands.CommandUtils; +import com.sk89q.worldguard.bukkit.util.TargetMatcherSet; import com.sk89q.worldguard.chest.ChestProtection; import com.sk89q.worldguard.chest.SignChestProtection; import org.bukkit.block.Block; @@ -55,6 +58,7 @@ public class WorldConfiguration { private static final Logger log = Logger.getLogger(WorldConfiguration.class.getCanonicalName()); + private static final TargetMatcherParser matcherParser = new TargetMatcherParser(); public static final String CONFIG_HEADER = "#\r\n" + "# WorldGuard's world configuration file\r\n" + @@ -177,10 +181,10 @@ public class WorldConfiguration { public boolean disableDeathMessages; public boolean disableObsidianGenerators; public boolean strictEntitySpawn; + public TargetMatcherSet allowAllInteract; private Map maxRegionCounts; - /* Configuration data end */ /** @@ -265,6 +269,26 @@ private List getIntList(String node, List def) { return res; } + private TargetMatcherSet getTargetMatchers(String node) { + TargetMatcherSet set = new TargetMatcherSet(); + List inputs = parentConfig.getStringList(node, null); + + if (inputs == null || inputs.size() == 0) { + parentConfig.setProperty(node, new ArrayList()); + return set; + } + + for (String input : inputs) { + try { + set.add(matcherParser.fromInput(input)); + } catch (TargetMatcherParseException e) { + log.warning("Failed to parse the block / item type specified as '" + input + "'"); + } + } + + return set; + } + private List getStringList(String node, List def) { List res = parentConfig.getStringList(node, def); @@ -320,7 +344,8 @@ private void loadConfiguration() { buildPermissionDenyMessage = CommandUtils.replaceColorMacros( getString("build-permission-nodes.deny-message", "&eSorry, but you are not permitted to do that here.")); - strictEntitySpawn = getBoolean("strictness.block-entity-spawns-with-untraceable-cause", false); + strictEntitySpawn = getBoolean("event-handling.block-entity-spawns-with-untraceable-cause", false); + allowAllInteract = getTargetMatchers("event-handling.interaction-whitelist"); itemDurability = getBoolean("protection.item-durability", true); removeInfiniteStacks = getBoolean("protection.remove-infinite-stacks", false); diff --git a/src/main/java/com/sk89q/worldguard/bukkit/listener/EventAbstractionListener.java b/src/main/java/com/sk89q/worldguard/bukkit/listener/EventAbstractionListener.java index f55f118c..25609438 100644 --- a/src/main/java/com/sk89q/worldguard/bukkit/listener/EventAbstractionListener.java +++ b/src/main/java/com/sk89q/worldguard/bukkit/listener/EventAbstractionListener.java @@ -120,8 +120,6 @@ import java.util.List; import static com.sk89q.worldguard.bukkit.cause.Cause.create; -import static com.sk89q.worldguard.bukkit.util.Materials.isBlockModifiedOnClick; -import static com.sk89q.worldguard.bukkit.util.Materials.isItemAppliedToBlock; public class EventAbstractionListener extends AbstractListener { @@ -362,7 +360,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { placed = clicked.getRelative(event.getBlockFace()); // Only fire events for blocks that are modified when right clicked - if (isBlockModifiedOnClick(clicked.getType()) || (item != null && isItemAppliedToBlock(item.getType(), clicked.getType()))) { + if (isBlockModifiedOnClick(clicked) || (item != null && isItemAppliedToBlock(item, clicked))) { if (Events.fireAndTestCancel(new UseBlockEvent(event, cause, clicked))) { event.setUseInteractedBlock(Result.DENY); } @@ -874,6 +872,16 @@ private static void handleInventoryHolderUse(T o } } + private boolean isBlockModifiedOnClick(Block block) { + return Materials.isBlockModifiedOnClick(block.getType()) && !getWorldConfig(block.getWorld()).allowAllInteract.test(block); + } + + private boolean isItemAppliedToBlock(ItemStack item, Block clicked) { + return Materials.isItemAppliedToBlock(item.getType(), clicked.getType()) + && !getWorldConfig(clicked.getWorld()).allowAllInteract.test(clicked) + && !getWorldConfig(clicked.getWorld()).allowAllInteract.test(item); + } + private void playDenyEffect(Player player, Location location) { //player.playSound(location, Sound.SUCCESSFUL_HIT, 0.2f, 0.4f); player.playEffect(location, Effect.SMOKE, BlockFace.UP); diff --git a/src/main/java/com/sk89q/worldguard/bukkit/util/TargetMatcherSet.java b/src/main/java/com/sk89q/worldguard/bukkit/util/TargetMatcherSet.java new file mode 100644 index 00000000..555c41f2 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/bukkit/util/TargetMatcherSet.java @@ -0,0 +1,73 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.bukkit.util; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.sk89q.worldguard.blacklist.target.MaterialTarget; +import com.sk89q.worldguard.blacklist.target.Target; +import com.sk89q.worldguard.blacklist.target.TargetMatcher; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.inventory.ItemStack; + +import java.util.Collection; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class TargetMatcherSet { + + private final Multimap entries = HashMultimap.create(); + + public boolean add(TargetMatcher matcher) { + checkNotNull(matcher); + return entries.put(matcher.getMatchedTypeId(), matcher); + } + + public boolean test(Target target) { + Collection matchers = entries.get(target.getTypeId()); + + for (TargetMatcher matcher : matchers) { + if (matcher.test(target)) { + return true; + } + } + + return false; + } + + public boolean test(Material material) { + return test(new MaterialTarget(material.getId(), (short) 0)); + } + + public boolean test(Block block) { + return test(new MaterialTarget(block.getTypeId(), block.getData())); + } + + public boolean test(BlockState state) { + return test(new MaterialTarget(state.getTypeId(), state.getRawData())); + } + + public boolean test(ItemStack itemStack) { + return test(new MaterialTarget(itemStack.getTypeId(), itemStack.getDurability())); + } + +}