Fix and improve protection handlers.

This commit is contained in:
sk89q 2014-08-15 01:43:37 -07:00
parent 608d782321
commit 3f16fef57e
16 changed files with 582 additions and 235 deletions

View File

@ -42,7 +42,6 @@
import org.bukkit.entity.Tameable;
import org.bukkit.inventory.ItemStack;
import javax.annotation.Nullable;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
@ -320,9 +319,9 @@ public static Target createTarget(Block block) {
* @param material a fallback material
* @return a target
*/
public static Target createTarget(@Nullable Block block, Material material) {
public static Target createTarget(Block block, Material material) {
checkNotNull(material);
if (block != null) {
if (block.getType() == material) {
return new MaterialTarget(block.getTypeId(), block.getData());
} else {
return new MaterialTarget(material.getId(), (short) 0);

View File

@ -110,23 +110,7 @@ public ApplicableRegionSet queryContains(Location location) {
* @throws NullPointerException if there is no player for this query
*/
public boolean testPermission(Location location, Player player) {
checkNotNull(location);
checkNotNull(player);
LocalPlayer localPlayer = plugin.wrapPlayer(player);
World world = location.getWorld();
WorldConfiguration worldConfig = config.get(world);
if (!worldConfig.useRegions) {
return true;
}
if (globalManager.hasBypass(localPlayer, world)) {
return true;
} else {
RegionManager manager = globalManager.get(location.getWorld());
return manager == null || cache.queryContains(manager, location).canBuild(localPlayer);
}
return testPermission(location, player, new StateFlag[0]);
}
/**
@ -151,8 +135,8 @@ public boolean testPermission(Location location, Player player) {
*/
public boolean testPermission(Location location, Player player, StateFlag... flags) {
checkNotNull(location);
checkNotNull(flags);
checkNotNull(player);
checkNotNull(flags);
LocalPlayer localPlayer = plugin.wrapPlayer(player);
World world = location.getWorld();
@ -162,6 +146,10 @@ public boolean testPermission(Location location, Player player, StateFlag... fla
return true;
}
if (player.hasPermission("worldguard.region.bypass." + world.getName())) {
return true;
}
RegionManager manager = globalManager.get(location.getWorld());
if (manager != null) {

View File

@ -20,10 +20,14 @@
package com.sk89q.worldguard.bukkit.cause;
import com.google.common.base.Joiner;
import com.sk89q.worldguard.bukkit.util.WGMetadata;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.Vehicle;
import org.bukkit.metadata.Metadatable;
import javax.annotation.Nullable;
import java.util.ArrayList;
@ -43,6 +47,7 @@
*/
public class Cause {
private static final String CAUSE_KEY = "worldguard.cause";
private static final Cause UNKNOWN = new Cause(Collections.emptyList());
private final List<Object> causes;
@ -77,6 +82,17 @@ public Player getPlayerRootCause() {
return null;
}
@Nullable
public Entity getEntityRootCause() {
for (Object object : causes) {
if (object instanceof Entity) {
return (Entity) object;
}
}
return null;
}
@Override
public String toString() {
return Joiner.on(" | ").join(causes);
@ -95,12 +111,28 @@ private static void expand(List<Object> list, @Nullable Object ... element) {
continue;
}
if (o instanceof Projectile) {
// Add manually tracked parent causes
Object source = o;
int index = list.size();
while (source instanceof Metadatable) {
source = WGMetadata.getIfPresent((Metadatable) source, CAUSE_KEY, Object.class);
if (source != null) {
list.add(index, source);
}
}
if (o instanceof TNTPrimed) {
expand(list, ((TNTPrimed) o).getSource());
list.add(o);
} else if (o instanceof Projectile) {
expand(list, ((Projectile) o).getShooter());
list.add(o);
} else if (o instanceof Vehicle) {
expand(list, ((Vehicle) o).getPassenger());
list.add(o);
} else if (o instanceof Tameable) {
expand(list, ((Tameable) o).getOwner());
list.add(o);
} else {
list.add(o);
}
@ -135,4 +167,14 @@ public static Cause unknown() {
return UNKNOWN;
}
/**
* Add a parent cause to a {@code Metadatable} object.
*
* @param target the target
* @param parent the parent cause
*/
public static void trackParentCause(Metadatable target, Object parent) {
WGMetadata.put(target, CAUSE_KEY, parent);
}
}

View File

@ -0,0 +1,38 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.bukkit.event;
/**
* A bulk event contains several affected objects in a list.
*/
public interface BulkEvent {
/**
* Return whether the event is explicitly cancelled.
*
* <p>By default, bulk events will cancel itself if the number of affected
* objects drops to zero. This method returns the true cancellation
* status.</p>
*
* @return true if really cancelled
*/
boolean isExplicitlyCancelled();
}

View File

@ -19,56 +19,125 @@
package com.sk89q.worldguard.bukkit.event.block;
import com.google.common.base.Predicate;
import com.sk89q.worldguard.bukkit.cause.Cause;
import com.sk89q.worldguard.bukkit.event.AbstractDelegateEvent;
import com.sk89q.worldguard.bukkit.event.BulkEvent;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.event.Event;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
abstract class AbstractBlockEvent extends AbstractDelegateEvent {
abstract class AbstractBlockEvent extends AbstractDelegateEvent implements BulkEvent {
private final Location target;
@Nullable
private final Block block;
private final World world;
private final List<Block> blocks;
private final Material effectiveMaterial;
protected AbstractBlockEvent(@Nullable Event originalEvent, Cause cause, Block block) {
protected AbstractBlockEvent(@Nullable Event originalEvent, Cause cause, World world, List<Block> blocks, Material effectiveMaterial) {
super(originalEvent, cause);
checkNotNull(block);
this.target = block.getLocation();
this.block = block;
this.effectiveMaterial = block.getType();
}
protected AbstractBlockEvent(@Nullable Event originalEvent, Cause cause, Location target, Material effectiveMaterial) {
super(originalEvent, cause);
this.target = target;
this.block = null;
checkNotNull(world);
checkNotNull(blocks);
checkNotNull(effectiveMaterial);
this.world = world;
this.blocks = blocks;
this.effectiveMaterial = effectiveMaterial;
}
/**
* Get the target block being affected.
*
* @return a block
*/
public Location getTarget() {
return target;
protected AbstractBlockEvent(@Nullable Event originalEvent, Cause cause, Block block) {
this(originalEvent, cause, block.getWorld(), createList(checkNotNull(block)), block.getType());
}
protected AbstractBlockEvent(@Nullable Event originalEvent, Cause cause, Location target, Material effectiveMaterial) {
this(originalEvent, cause, target.getWorld(), createList(target.getBlock()), effectiveMaterial);
}
private static List<Block> createList(Block block) {
List<Block> blocks = new ArrayList<Block>();
blocks.add(block);
return blocks;
}
@Override
public boolean isCancelled() {
return super.isCancelled() || blocks.isEmpty();
}
@Override
public boolean isExplicitlyCancelled() {
return super.isCancelled();
}
/**
* Get the block.
* Get the world.
*
* @return the block
* @return the world
*/
@Nullable
public Block getBlock() {
return block;
public World getWorld() {
return world;
}
/**
* Get the affected blocks.
*
* @return a list of affected block
*/
public List<Block> getBlocks() {
return blocks;
}
/**
* Filter the list of affected blocks with the given predicate. If the
* predicate returns {@code false}, then the block is removed.
*
* @param predicate the predicate
* @param cancelEventOnFalse true to cancel the event and clear the block
* list once the predicate returns {@code false}
* @return true if one or more blocks were filtered out
*/
public boolean filterBlocks(Predicate<Location> predicate, boolean cancelEventOnFalse) {
boolean hasRemoval = false;
Iterator<Block> it = blocks.iterator();
while (it.hasNext()) {
if (!predicate.apply(it.next().getLocation())) {
hasRemoval = true;
if (cancelEventOnFalse) {
getBlocks().clear();
setCancelled(true);
break;
} else {
it.remove();
}
}
}
return hasRemoval;
}
/**
* Filter the list of affected blocks with the given predicate. If the
* predicate returns {@code false}, then the block is removed.
*
* <p>This method will <strong>not</strong> fail fast and
* cancel the event the first instance that the predicate returns
* {@code false}. See {@link #filterBlocks(Predicate, boolean)} to adjust
* this behavior.</p>
*
* @param predicate the predicate
* @return true if one or more blocks were filtered out
*/
public boolean filterBlocks(Predicate<Location> predicate) {
return filterBlocks(predicate, false);
}
/**

View File

@ -22,16 +22,22 @@
import com.sk89q.worldguard.bukkit.cause.Cause;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import javax.annotation.Nullable;
import java.util.List;
public class BreakBlockEvent extends AbstractBlockEvent {
private static final HandlerList handlers = new HandlerList();
public BreakBlockEvent(@Nullable Event originalEvent, Cause cause, World world, List<Block> blocks, Material effectiveMaterial) {
super(originalEvent, cause, world, blocks, effectiveMaterial);
}
public BreakBlockEvent(@Nullable Event originalEvent, Cause cause, Block block) {
super(originalEvent, cause, block);
}

View File

@ -22,16 +22,22 @@
import com.sk89q.worldguard.bukkit.cause.Cause;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import javax.annotation.Nullable;
import java.util.List;
public class PlaceBlockEvent extends AbstractBlockEvent {
private static final HandlerList handlers = new HandlerList();
public PlaceBlockEvent(@Nullable Event originalEvent, Cause cause, World world, List<Block> blocks, Material effectiveMaterial) {
super(originalEvent, cause, world, blocks, effectiveMaterial);
}
public PlaceBlockEvent(@Nullable Event originalEvent, Cause cause, Block block) {
super(originalEvent, cause, block);
}

View File

@ -22,11 +22,13 @@
import com.sk89q.worldguard.bukkit.cause.Cause;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import javax.annotation.Nullable;
import java.util.List;
/**
* Fired when a block is interacted with.
@ -35,6 +37,10 @@ public class UseBlockEvent extends AbstractBlockEvent {
private static final HandlerList handlers = new HandlerList();
public UseBlockEvent(@Nullable Event originalEvent, Cause cause, World world, List<Block> blocks, Material effectiveMaterial) {
super(originalEvent, cause, world, blocks, effectiveMaterial);
}
public UseBlockEvent(@Nullable Event originalEvent, Cause cause, Block block) {
super(originalEvent, cause, block);
}

View File

@ -19,6 +19,7 @@
package com.sk89q.worldguard.bukkit.listener;
import com.google.common.base.Predicate;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.blacklist.event.BlockBreakBlacklistEvent;
import com.sk89q.worldguard.blacklist.event.BlockDispenseBlacklistEvent;
@ -38,8 +39,8 @@
import com.sk89q.worldguard.bukkit.event.entity.SpawnEntityEvent;
import com.sk89q.worldguard.bukkit.event.inventory.UseItemEvent;
import com.sk89q.worldguard.bukkit.util.Materials;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
@ -68,75 +69,86 @@ public BlacklistListener(WorldGuardPlugin plugin) {
}
@EventHandler(ignoreCancelled = true)
public void onBreakBlock(BreakBlockEvent event) {
Player player = event.getCause().getPlayerRootCause();
public void onBreakBlock(final BreakBlockEvent event) {
final Player player = event.getCause().getPlayerRootCause();
if (player == null) {
return;
}
LocalPlayer localPlayer = getPlugin().wrapPlayer(player);
Block target = event.getBlock();
WorldConfiguration wcfg = getWorldConfig(player);
final LocalPlayer localPlayer = getPlugin().wrapPlayer(player);
final WorldConfiguration wcfg = getWorldConfig(player);
// Blacklist guard
if (wcfg.getBlacklist() == null) {
return;
}
event.filterBlocks(new Predicate<Location>() {
@Override
public boolean apply(Location target) {
if (!wcfg.getBlacklist().check(
new BlockBreakBlacklistEvent(localPlayer, toVector(event.getTarget()), createTarget(target, event.getEffectiveMaterial())), false, false)) {
event.setCancelled(true);
new BlockBreakBlacklistEvent(localPlayer, toVector(target), createTarget(target.getBlock(), event.getEffectiveMaterial())), false, false)) {
return false;
} else if (!wcfg.getBlacklist().check(
new ItemDestroyWithBlacklistEvent(localPlayer, toVector(event.getTarget()), createTarget(player.getItemInHand())), false, false)) {
event.setCancelled(true);
new ItemDestroyWithBlacklistEvent(localPlayer, toVector(target), createTarget(player.getItemInHand())), false, false)) {
return false;
}
return true;
}
});
}
@EventHandler(ignoreCancelled = true)
public void onPlaceBlock(PlaceBlockEvent event) {
public void onPlaceBlock(final PlaceBlockEvent event) {
Player player = event.getCause().getPlayerRootCause();
if (player == null) {
return;
}
LocalPlayer localPlayer = getPlugin().wrapPlayer(player);
Block target = event.getBlock();
WorldConfiguration wcfg = getWorldConfig(player);
final LocalPlayer localPlayer = getPlugin().wrapPlayer(player);
final WorldConfiguration wcfg = getWorldConfig(player);
// Blacklist guard
if (wcfg.getBlacklist() == null) {
return;
}
if (!wcfg.getBlacklist().check(new BlockPlaceBlacklistEvent(
localPlayer, toVector(event.getTarget()), createTarget(target, event.getEffectiveMaterial())), false, false)) {
event.setCancelled(true);
event.filterBlocks(new Predicate<Location>() {
@Override
public boolean apply(Location target) {
return wcfg.getBlacklist().check(new BlockPlaceBlacklistEvent(
localPlayer, toVector(target), createTarget(target.getBlock(), event.getEffectiveMaterial())), false, false);
}
});
}
@EventHandler(ignoreCancelled = true)
public void onUseBlock(UseBlockEvent event) {
public void onUseBlock(final UseBlockEvent event) {
Player player = event.getCause().getPlayerRootCause();
if (player == null) {
return;
}
LocalPlayer localPlayer = getPlugin().wrapPlayer(player);
Block target = event.getBlock();
WorldConfiguration wcfg = getWorldConfig(player);
final LocalPlayer localPlayer = getPlugin().wrapPlayer(player);
final WorldConfiguration wcfg = getWorldConfig(player);
// Blacklist guard
if (wcfg.getBlacklist() == null) {
return;
}
if (!wcfg.getBlacklist().check(new BlockInteractBlacklistEvent(
localPlayer, toVector(event.getTarget()), createTarget(target, event.getEffectiveMaterial())), false, false)) {
event.setCancelled(true);
event.filterBlocks(new Predicate<Location>() {
@Override
public boolean apply(Location target) {
return wcfg.getBlacklist().check(new BlockInteractBlacklistEvent(
localPlayer, toVector(target), createTarget(target.getBlock(), event.getEffectiveMaterial())), false, false);
}
});
}
@EventHandler(ignoreCancelled = true)

View File

@ -19,6 +19,7 @@
package com.sk89q.worldguard.bukkit.listener;
import com.google.common.base.Predicate;
import com.sk89q.worldedit.blocks.BlockID;
import com.sk89q.worldguard.bukkit.WorldConfiguration;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
@ -46,31 +47,36 @@ public ChestProtectionListener(WorldGuardPlugin plugin) {
}
@EventHandler(ignoreCancelled = true)
public void onPlaceBlock(PlaceBlockEvent event) {
Player player = event.getCause().getPlayerRootCause();
Location target = event.getTarget();
public void onPlaceBlock(final PlaceBlockEvent event) {
final Player player = event.getCause().getPlayerRootCause();
if (player != null) {
WorldConfiguration wcfg = getWorldConfig(player);
final WorldConfiguration wcfg = getWorldConfig(player);
// Early guard
if (!wcfg.signChestProtection) {
return;
}
event.filterBlocks(new Predicate<Location>() {
@Override
public boolean apply(Location target) {
if (wcfg.getChestProtection().isChest(event.getEffectiveMaterial().getId()) && wcfg.isChestProtected(target.getBlock(), player)) {
player.sendMessage(ChatColor.DARK_RED + "This spot is for a chest that you don't have permission for.");
event.setCancelled(true);
return false;
}
return true;
}
}, true);
}
}
@EventHandler(ignoreCancelled = true)
public void onBreakBlock(BreakBlockEvent event) {
Player player = event.getCause().getPlayerRootCause();
Location target = event.getTarget();
public void onBreakBlock(final BreakBlockEvent event) {
final Player player = event.getCause().getPlayerRootCause();
WorldConfiguration wcfg = getWorldConfig(target.getWorld());
final WorldConfiguration wcfg = getWorldConfig(event.getWorld());
// Early guard
if (!wcfg.signChestProtection) {
@ -78,24 +84,33 @@ public void onBreakBlock(BreakBlockEvent event) {
}
if (player != null) {
event.filterBlocks(new Predicate<Location>() {
@Override
public boolean apply(Location target) {
if (wcfg.isChestProtected(target.getBlock(), player)) {
player.sendMessage(ChatColor.DARK_RED + "This chest is protected.");
event.setCancelled(true);
return false;
}
return true;
}
}, true);
} else {
if (wcfg.isChestProtected(target.getBlock())) {
// No player? Deny anyway
event.setCancelled(true);
event.filterBlocks(new Predicate<Location>() {
@Override
public boolean apply(Location target) {
return !wcfg.isChestProtected(target.getBlock());
}
});
}
}
@EventHandler(ignoreCancelled = true)
public void onUseBlock(UseBlockEvent event) {
Player player = event.getCause().getPlayerRootCause();
Location target = event.getTarget();
public void onUseBlock(final UseBlockEvent event) {
final Player player = event.getCause().getPlayerRootCause();
WorldConfiguration wcfg = getWorldConfig(target.getWorld());
final WorldConfiguration wcfg = getWorldConfig(event.getWorld());
// Early guard
if (!wcfg.signChestProtection) {
@ -103,15 +118,25 @@ public void onUseBlock(UseBlockEvent event) {
}
if (player != null) {
event.filterBlocks(new Predicate<Location>() {
@Override
public boolean apply(Location target) {
if (wcfg.isChestProtected(target.getBlock(), player)) {
player.sendMessage(ChatColor.DARK_RED + "This chest is protected.");
event.setCancelled(true);
return false;
}
return true;
}
}, true);
} else {
if (wcfg.isChestProtected(target.getBlock())) {
// No player? Deny anyway
event.setCancelled(true);
event.filterBlocks(new Predicate<Location>() {
@Override
public boolean apply(Location target) {
return !wcfg.isChestProtected(target.getBlock());
}
});
}
}

View File

@ -28,8 +28,13 @@
import com.sk89q.worldguard.bukkit.event.entity.UseEntityEvent;
import com.sk89q.worldguard.bukkit.event.inventory.UseItemEvent;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import javax.annotation.Nullable;
import java.util.List;
import java.util.logging.Logger;
import static com.google.common.base.Preconditions.checkNotNull;
@ -50,22 +55,25 @@ public DebuggingListener(WorldGuardPlugin plugin, Logger logger) {
this.logger = logger;
}
@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public void onPlaceBlock(PlaceBlockEvent event) {
StringBuilder builder = new StringBuilder();
builder.append("PLACE");
builder.append(" ");
builder.append("").append(event.getEffectiveMaterial());
builder.append(" ");
builder.append("@").append(toBlockString(event.getTarget()));
builder.append("@").append(toBlockString(event.getBlocks()));
builder.append(" ");
builder.append("[").append(event.getCause()).append("]");
builder.append(" ");
builder.append(":").append(event.getOriginalEvent().getEventName());
builder.append(":").append(getEventName(event.getOriginalEvent()));
if (event.isCancelled()) {
builder.append(" [CANCELLED]");
}
logger.info(builder.toString());
}
@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public void onBreakBlock(BreakBlockEvent event) {
StringBuilder builder = new StringBuilder();
builder.append("DIG");
@ -74,13 +82,16 @@ public void onBreakBlock(BreakBlockEvent event) {
builder.append(" ");
builder.append("[").append(event.getCause()).append("]");
builder.append(" ");
builder.append("@").append(toBlockString(event.getTarget()));
builder.append("@").append(toBlockString(event.getBlocks()));
builder.append(" ");
builder.append(":").append(event.getOriginalEvent().getEventName());
builder.append(":").append(getEventName(event.getOriginalEvent()));
if (event.isCancelled()) {
builder.append(" [CANCELLED]");
}
logger.info(builder.toString());
}
@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public void onUseBlock(UseBlockEvent event) {
StringBuilder builder = new StringBuilder();
builder.append("INTERACT");
@ -89,13 +100,16 @@ public void onUseBlock(UseBlockEvent event) {
builder.append(" ");
builder.append("[").append(event.getCause()).append("]");
builder.append(" ");
builder.append("@").append(toBlockString(event.getTarget()));
builder.append("@").append(toBlockString(event.getBlocks()));
builder.append(" ");
builder.append(":").append(event.getOriginalEvent().getEventName());
builder.append(":").append(getEventName(event.getOriginalEvent()));
if (event.isCancelled()) {
builder.append(" [CANCELLED]");
}
logger.info(builder.toString());
}
@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public void onSpawnEntity(SpawnEntityEvent event) {
StringBuilder builder = new StringBuilder();
builder.append("SPAWN");
@ -106,11 +120,14 @@ public void onSpawnEntity(SpawnEntityEvent event) {
builder.append(" ");
builder.append("@").append(toBlockString(event.getTarget()));
builder.append(" ");
builder.append(":").append(event.getOriginalEvent().getEventName());
builder.append(":").append(getEventName(event.getOriginalEvent()));
if (event.isCancelled()) {
builder.append(" [CANCELLED]");
}
logger.info(builder.toString());
}
@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public void onDestroyEntity(DestroyEntityEvent event) {
StringBuilder builder = new StringBuilder();
builder.append("DESTROY");
@ -121,11 +138,14 @@ public void onDestroyEntity(DestroyEntityEvent event) {
builder.append(" ");
builder.append("@").append(toBlockString(event.getTarget()));
builder.append(" ");
builder.append(":").append(event.getOriginalEvent().getEventName());
builder.append(":").append(getEventName(event.getOriginalEvent()));
if (event.isCancelled()) {
builder.append(" [CANCELLED]");
}
logger.info(builder.toString());
}
@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public void onUseEntity(UseEntityEvent event) {
StringBuilder builder = new StringBuilder();
builder.append("INTERACT");
@ -136,11 +156,14 @@ public void onUseEntity(UseEntityEvent event) {
builder.append(" ");
builder.append("@").append(toBlockString(event.getTarget()));
builder.append(" ");
builder.append(":").append(event.getOriginalEvent().getEventName());
builder.append(":").append(getEventName(event.getOriginalEvent()));
if (event.isCancelled()) {
builder.append(" [CANCELLED]");
}
logger.info(builder.toString());
}
@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public void onUseItem(UseItemEvent event) {
StringBuilder builder = new StringBuilder();
builder.append("USE");
@ -151,7 +174,10 @@ public void onUseItem(UseItemEvent event) {
builder.append(" ");
builder.append("@").append(event.getWorld().getName());
builder.append(" ");
builder.append(":").append(event.getOriginalEvent().getEventName());
builder.append(":").append(getEventName(event.getOriginalEvent()));
if (event.isCancelled()) {
builder.append(" [CANCELLED]");
}
logger.info(builder.toString());
}
@ -159,4 +185,21 @@ private static String toBlockString(Location location) {
return location.getBlockX() + "," + location.getBlockY() + "," + location.getBlockZ();
}
private static String toBlockString(List<Block> blocks) {
StringBuilder builder = new StringBuilder();
boolean first = true;
for (Block block : blocks) {
if (!first) {
builder.append("|");
}
builder.append(block.getX()).append(",").append(block.getY()).append(",").append(block.getZ());
first = false;
}
return builder.toString();
}
private String getEventName(@Nullable Event event) {
return event != null ? event.getEventName() : "?";
}
}

View File

@ -31,7 +31,6 @@
import com.sk89q.worldguard.bukkit.util.Blocks;
import com.sk89q.worldguard.bukkit.util.Events;
import com.sk89q.worldguard.bukkit.util.Materials;
import com.sk89q.worldguard.bukkit.util.WGMetadata;
import org.bukkit.DyeColor;
import org.bukkit.Material;
import org.bukkit.World;
@ -67,6 +66,7 @@
import org.bukkit.event.entity.EntityDamageByBlockEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntityTameEvent;
import org.bukkit.event.entity.EntityUnleashEvent;
import org.bukkit.event.entity.PotionSplashEvent;
@ -101,7 +101,6 @@ public class EventAbstractionListener implements Listener {
* Currently disabled as it creates a lot of new events.
*/
public static final boolean ABSTRACT_FROM_TO_EVENTS = false;
private static final String FALLING_SOURCE_KEY = "worldguard.fallingSource";
private final WorldGuardPlugin plugin;
@ -155,7 +154,7 @@ public void onEntityChangeBlock(EntityChangeBlockEvent event) {
if (event.getTo() == Material.AIR) {
// Track the source so later we can create a proper chain of causes
if (entity instanceof FallingBlock) {
WGMetadata.put(entity, FALLING_SOURCE_KEY, block);
Cause.trackParentCause(entity, block);
// Switch around the event
Events.fireToCancel(event, new SpawnEntityEvent(event, create(block), entity));
@ -163,23 +162,21 @@ public void onEntityChangeBlock(EntityChangeBlockEvent event) {
Events.fireToCancel(event, new BreakBlockEvent(event, create(entity), event.getBlock()));
}
} else {
Cause cause;
// Return the source for falling blocks
if (entity instanceof FallingBlock) {
Block source = WGMetadata.getIfPresent(entity, FALLING_SOURCE_KEY, Block.class);
cause = create(source, entity);
} else {
cause = create(entity);
}
Cause cause = create(entity);
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, event.getBlock().getLocation(), to));
}
}
}
@EventHandler
public void onEntityExplode(EntityExplodeEvent event) {
Entity entity = event.getEntity();
Events.fireBulkEventToCancel(event, new BreakBlockEvent(event, create(entity), event.getLocation().getWorld(), event.blockList(), Material.AIR));
}
// TODO: Handle pistons
// TODO: Handle EntityExplodeEvent
//-------------------------------------------------------------------------
// Block external interaction

View File

@ -19,8 +19,12 @@
package com.sk89q.worldguard.bukkit.listener;
import com.google.common.base.Predicate;
import com.sk89q.worldguard.bukkit.ConfigurationManager;
import com.sk89q.worldguard.bukkit.RegionQuery;
import com.sk89q.worldguard.bukkit.WorldConfiguration;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.cause.Cause;
import com.sk89q.worldguard.bukkit.event.block.BreakBlockEvent;
import com.sk89q.worldguard.bukkit.event.block.PlaceBlockEvent;
import com.sk89q.worldguard.bukkit.event.block.UseBlockEvent;
@ -30,14 +34,20 @@
import com.sk89q.worldguard.bukkit.util.Entities;
import com.sk89q.worldguard.bukkit.util.Materials;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.EnderDragon;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import javax.annotation.Nullable;
/**
* Handle events that need to be processed by region protection.
*/
@ -52,18 +62,58 @@ public RegionProtectionListener(WorldGuardPlugin plugin) {
super(plugin);
}
/**
* Tell a sender that s/he cannot do something 'here'.
*
* @param sender the sender
* @param subject the subject that the sender was blocked from touching
*/
private void tellErrorMessage(CommandSender sender, Object subject) {
sender.sendMessage(ChatColor.DARK_RED + "Sorry, but you are not allowed to do that here.");
}
@EventHandler(ignoreCancelled = true)
public void onPlaceBlock(PlaceBlockEvent event) {
Player player = event.getCause().getPlayerRootCause();
Location target = event.getTarget();
Material type = event.getEffectiveMaterial();
/**
* Return whether the given cause is whitelist (should be ignored).
*
* @param cause the cause
* @return true if whitelisted
*/
private boolean isWhitelisted(Cause cause) {
return false;
}
if (player != null) {
RegionQuery query = getPlugin().getRegionContainer().createQuery();
/**
* Create a new predicate to test a state flag for each location.
*
* @param query the query
* @param flag the flag
* @return a predicate
*/
private Predicate<Location> createStateFlagPredicate(final RegionQuery query, final StateFlag flag) {
return new Predicate<Location>() {
@Override
public boolean apply(@Nullable Location location) {
return query.testState(location, null, flag);
}
};
}
@EventHandler(ignoreCancelled = true)
public void onPlaceBlock(final PlaceBlockEvent event) {
if (isWhitelisted(event.getCause())) {
return; // Whitelisted cause
}
final Material type = event.getEffectiveMaterial();
final Player player;
if ((player = event.getCause().getPlayerRootCause()) != null) {
final RegionQuery query = getPlugin().getRegionContainer().createQuery();
event.filterBlocks(new Predicate<Location>() {
@Override
public boolean apply(Location target) {
boolean canPlace;
// Flint and steel, fire charge
@ -76,35 +126,88 @@ public void onPlaceBlock(PlaceBlockEvent event) {
if (!canPlace) {
tellErrorMessage(player, target);
event.setCancelled(true);
return false;
}
return true;
}
});
} else {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true)
public void onBreakBlock(BreakBlockEvent event) {
Player player = event.getCause().getPlayerRootCause();
Location target = event.getTarget();
public void onBreakBlock(final BreakBlockEvent event) {
if (isWhitelisted(event.getCause())) {
return; // Whitelisted cause
}
if (player != null) {
RegionQuery query = getPlugin().getRegionContainer().createQuery();
final RegionQuery query = getPlugin().getRegionContainer().createQuery();
ConfigurationManager globalConfig = getPlugin().getGlobalStateManager();
WorldConfiguration config = globalConfig.get(event.getWorld());
final Player player;
final Entity entity;
// ====================================================================
// Player caused
// ====================================================================
if ((player = event.getCause().getPlayerRootCause()) != null) {
event.filterBlocks(new Predicate<Location>() {
@Override
public boolean apply(Location target) {
boolean canBreak = query.testPermission(target, player);
if (!canBreak) {
tellErrorMessage(player, target);
event.setCancelled(true);
return false;
}
return true;
}
});
// ====================================================================
// Entity caused
// ====================================================================
} else if ((entity = event.getCause().getEntityRootCause()) != null) {
// Creeper
if (entity instanceof Creeper) {
event.filterBlocks(createStateFlagPredicate(query, DefaultFlag.CREEPER_EXPLOSION), config.explosionFlagCancellation);
// Enderdragon
} else if (entity instanceof EnderDragon) {
event.filterBlocks(createStateFlagPredicate(query, DefaultFlag.ENDERDRAGON_BLOCK_DAMAGE), config.explosionFlagCancellation);
// TNT + explosive TNT carts
} else if (Entities.isTNTBased(entity)) {
event.filterBlocks(createStateFlagPredicate(query, DefaultFlag.TNT), config.explosionFlagCancellation);
}
} else {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true)
public void onUseBlock(UseBlockEvent event) {
Player player = event.getCause().getPlayerRootCause();
Location target = event.getTarget();
Material type = event.getEffectiveMaterial();
public void onUseBlock(final UseBlockEvent event) {
if (isWhitelisted(event.getCause())) {
return; // Whitelisted cause
}
if (player != null) {
RegionQuery query = getPlugin().getRegionContainer().createQuery();
final Material type = event.getEffectiveMaterial();
final Player player;
if ((player = event.getCause().getPlayerRootCause()) != null) {
final RegionQuery query = getPlugin().getRegionContainer().createQuery();
event.filterBlocks(new Predicate<Location>() {
@Override
public boolean apply(Location target) {
boolean canUse;
// Inventory blocks (CHEST_ACCESS)
@ -126,18 +229,29 @@ public void onUseBlock(UseBlockEvent event) {
if (!canUse) {
tellErrorMessage(player, target);
event.setCancelled(true);
return false;
}
return true;
}
});
} else {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true)
public void onSpawnEntity(SpawnEntityEvent event) {
Player player = event.getCause().getPlayerRootCause();
if (isWhitelisted(event.getCause())) {
return; // Whitelisted cause
}
Location target = event.getTarget();
EntityType type = event.getEffectiveType();
if (player != null) {
Player player;
if ((player = event.getCause().getPlayerRootCause()) != null) {
RegionQuery query = getPlugin().getRegionContainer().createQuery();
boolean canSpawn;
@ -151,16 +265,23 @@ public void onSpawnEntity(SpawnEntityEvent event) {
tellErrorMessage(player, target);
event.setCancelled(true);
}
} else {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true)
public void onDestroyEntity(DestroyEntityEvent event) {
Player player = event.getCause().getPlayerRootCause();
if (isWhitelisted(event.getCause())) {
return; // Whitelisted cause
}
Location target = event.getTarget();
EntityType type = event.getEntity().getType();
if (player != null) {
Player player;
if ((player = event.getCause().getPlayerRootCause()) != null) {
RegionQuery query = getPlugin().getRegionContainer().createQuery();
boolean canDestroy;
@ -174,15 +295,22 @@ public void onDestroyEntity(DestroyEntityEvent event) {
tellErrorMessage(player, target);
event.setCancelled(true);
}
} else {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true)
public void onUseEntity(UseEntityEvent event) {
Player player = event.getCause().getPlayerRootCause();
if (isWhitelisted(event.getCause())) {
return; // Whitelisted cause
}
Location target = event.getTarget();
if (player != null) {
Player player;
if ((player = event.getCause().getPlayerRootCause()) != null) {
RegionQuery query = getPlugin().getRegionContainer().createQuery();
boolean canUse = query.testPermission(target, player, DefaultFlag.USE);
@ -190,6 +318,8 @@ public void onUseEntity(UseEntityEvent event) {
tellErrorMessage(player, target);
event.setCancelled(true);
}
} else {
event.setCancelled(true);
}
}

View File

@ -569,35 +569,11 @@ public void onEntityExplode(EntityExplodeEvent event) {
event.blockList().clear();
return;
}
if (wcfg.useRegions) {
RegionManager mgr = plugin.getGlobalRegionManager().get(world);
for (Block block : event.blockList()) {
if (!plugin.getRegionContainer().createQuery().queryContains(block.getLocation()).allows(DefaultFlag.CREEPER_EXPLOSION)) {
event.blockList().clear();
if (wcfg.explosionFlagCancellation) event.setCancelled(true);
return;
}
}
}
} else if (ent instanceof EnderDragon) {
if (wcfg.blockEnderDragonBlockDamage) {
event.blockList().clear();
return;
}
if (wcfg.useRegions) {
RegionManager mgr = plugin.getGlobalRegionManager().get(world);
for (Block block : event.blockList()) {
if (!plugin.getRegionContainer().createQuery().queryContains(block.getLocation()).allows(DefaultFlag.ENDERDRAGON_BLOCK_DAMAGE)) {
event.blockList().clear();
if (wcfg.explosionFlagCancellation) event.setCancelled(true);
return;
}
}
}
} else if (ent instanceof TNTPrimed || ent instanceof ExplosiveMinecart) {
if (wcfg.blockTNTExplosions) {
event.setCancelled(true);
@ -607,18 +583,6 @@ public void onEntityExplode(EntityExplodeEvent event) {
event.blockList().clear();
return;
}
if (wcfg.useRegions) {
RegionManager mgr = plugin.getGlobalRegionManager().get(world);
for (Block block : event.blockList()) {
if (!plugin.getRegionContainer().createQuery().queryContains(block.getLocation()).allows(DefaultFlag.TNT)) {
event.blockList().clear();
if (wcfg.explosionFlagCancellation) event.setCancelled(true);
return;
}
}
}
} else if (ent instanceof Fireball) {
if (ent instanceof WitherSkull) {
if (wcfg.blockWitherSkullExplosions) {

View File

@ -22,7 +22,9 @@
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.minecart.ExplosiveMinecart;
import org.bukkit.projectiles.ProjectileSource;
import javax.annotation.Nullable;
@ -45,11 +47,11 @@ public static boolean isTamed(@Nullable Entity entity) {
/**
* Return if the given entity type is TNT-based.
*
* @param type the type
* @param entity the entity
* @return true if TNT based
*/
public static boolean isTNTBased(EntityType type) {
return type == EntityType.PRIMED_TNT || type == EntityType.MINECART_TNT;
public static boolean isTNTBased(Entity entity) {
return entity instanceof TNTPrimed || entity instanceof ExplosiveMinecart;
}
/**

View File

@ -19,6 +19,7 @@
package com.sk89q.worldguard.bukkit.util;
import com.sk89q.worldguard.bukkit.event.BulkEvent;
import org.bukkit.Bukkit;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
@ -83,4 +84,23 @@ public static <T extends Event & Cancellable> boolean fireItemEventToCancel(Play
return false;
}
/**
* Fire the {@code eventToFire} and cancel the original if the fired event
* is <strong>explicitly</strong> cancelled.
*
* @param original the original event to potentially cancel
* @param eventToFire the event to fire to consider cancelling the original event
* @param <T> an event that can be fired and is cancellable
* @return true if the event was fired and it caused the original event to be cancelled
*/
public static <T extends Event & Cancellable & BulkEvent> boolean fireBulkEventToCancel(Cancellable original, T eventToFire) {
Bukkit.getServer().getPluginManager().callEvent(eventToFire);
if (eventToFire.isExplicitlyCancelled()) {
original.setCancelled(true);
return true;
}
return false;
}
}