Improve level of event listening.

This commit is contained in:
sk89q 2014-08-11 20:08:38 -07:00
parent 110aa2e56b
commit 26d3645f86
11 changed files with 346 additions and 119 deletions

View File

@ -33,6 +33,11 @@
import com.sk89q.worldguard.bukkit.commands.GeneralCommands;
import com.sk89q.worldguard.bukkit.commands.ProtectionCommands;
import com.sk89q.worldguard.bukkit.commands.ToggleCommands;
import com.sk89q.worldguard.bukkit.listener.BlacklistListener;
import com.sk89q.worldguard.bukkit.listener.BlockedPotionsListener;
import com.sk89q.worldguard.bukkit.listener.ChestProtectionListener;
import com.sk89q.worldguard.bukkit.listener.EventAbstractionListener;
import com.sk89q.worldguard.bukkit.listener.RegionProtectionListener;
import com.sk89q.worldguard.bukkit.listener.WorldGuardBlockListener;
import com.sk89q.worldguard.bukkit.listener.WorldGuardCommandBookListener;
import com.sk89q.worldguard.bukkit.listener.WorldGuardEntityListener;
@ -42,10 +47,6 @@
import com.sk89q.worldguard.bukkit.listener.WorldGuardVehicleListener;
import com.sk89q.worldguard.bukkit.listener.WorldGuardWeatherListener;
import com.sk89q.worldguard.bukkit.listener.WorldGuardWorldListener;
import com.sk89q.worldguard.bukkit.listener.BlacklistListener;
import com.sk89q.worldguard.bukkit.listener.BlockedPotionsListener;
import com.sk89q.worldguard.bukkit.listener.ChestProtectionListener;
import com.sk89q.worldguard.bukkit.listener.RegionProtectionListener;
import com.sk89q.worldguard.protection.GlobalRegionManager;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.util.FatalConfigurationLoadingException;
@ -200,6 +201,7 @@ public void run() {
(new ChestProtectionListener(this)).registerEvents();
(new RegionProtectionListener(this)).registerEvents();
(new BlockedPotionsListener(this)).registerEvents();
(new EventAbstractionListener(this)).registerEvents();
configuration.updateCommandBookGodMode();

View File

@ -71,21 +71,23 @@ public void onBreakBlock(BreakBlockEvent event) {
Player player = Causes.getInvolvedPlayer(event.getCauses());
Location target = event.getTarget();
WorldConfiguration wcfg = getWorldConfig(target.getWorld());
// Early guard
if (!wcfg.signChestProtection) {
return;
}
if (player != null) {
WorldConfiguration wcfg = getWorldConfig(player);
// Early guard
if (!wcfg.signChestProtection) {
return;
}
if (wcfg.isChestProtected(target.getBlock(), player)) {
player.sendMessage(ChatColor.DARK_RED + "This chest is protected.");
event.setCancelled(true);
}
} else {
// No player? Deny anyway
event.setCancelled(true);
if (wcfg.isChestProtected(target.getBlock())) {
// No player? Deny anyway
event.setCancelled(true);
}
}
}
@ -94,21 +96,23 @@ public void onUseBlock(UseBlockEvent event) {
Player player = Causes.getInvolvedPlayer(event.getCauses());
Location target = event.getTarget();
WorldConfiguration wcfg = getWorldConfig(target.getWorld());
// Early guard
if (!wcfg.signChestProtection) {
return;
}
if (player != null) {
WorldConfiguration wcfg = getWorldConfig(player);
// Early guard
if (!wcfg.signChestProtection) {
return;
}
if (wcfg.isChestProtected(target.getBlock(), player)) {
player.sendMessage(ChatColor.DARK_RED + "This chest is protected.");
event.setCancelled(true);
}
} else {
// No player? Deny anyway
event.setCancelled(true);
if (wcfg.isChestProtected(target.getBlock())) {
// No player? Deny anyway
event.setCancelled(true);
}
}
}

View File

@ -20,11 +20,6 @@
package com.sk89q.worldguard.bukkit.listener;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.util.Blocks;
import com.sk89q.worldguard.bukkit.util.Materials;
import com.sk89q.worldguard.bukkit.util.Events;
import com.sk89q.worldguard.util.cause.Cause;
import com.sk89q.worldguard.util.cause.Causes;
import com.sk89q.worldguard.bukkit.event.block.BreakBlockEvent;
import com.sk89q.worldguard.bukkit.event.block.PlaceBlockEvent;
import com.sk89q.worldguard.bukkit.event.block.UseBlockEvent;
@ -32,16 +27,26 @@
import com.sk89q.worldguard.bukkit.event.entity.SpawnEntityEvent;
import com.sk89q.worldguard.bukkit.event.entity.UseEntityEvent;
import com.sk89q.worldguard.bukkit.event.inventory.UseItemEvent;
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 com.sk89q.worldguard.util.cause.Cause;
import com.sk89q.worldguard.util.cause.Causes;
import org.bukkit.DyeColor;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.ThrownPotion;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.Event.Result;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@ -55,6 +60,7 @@
import org.bukkit.event.block.BlockIgniteEvent.IgniteCause;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import org.bukkit.event.entity.EntityCombustByBlockEvent;
import org.bukkit.event.entity.EntityCombustByEntityEvent;
@ -80,6 +86,8 @@
import org.bukkit.event.vehicle.VehicleDamageEvent;
import org.bukkit.event.vehicle.VehicleDestroyEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.Dispenser;
import org.bukkit.material.MaterialData;
import javax.annotation.Nullable;
import java.util.Collections;
@ -91,6 +99,13 @@
public class EventAbstractionListener implements Listener {
/**
* Abstract {@link BlockFromToEvent}s into break and place events.
* 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;
public EventAbstractionListener(WorldGuardPlugin plugin) {
@ -112,7 +127,14 @@ public void onBlockBreak(BlockBreakEvent event) {
@EventHandler
public void onBlockPlace(BlockPlaceEvent event) {
Events.fireToCancel(event, new UseBlockEvent(event, create(event.getPlayer()), event.getBlock()));
BlockState previousState = event.getBlockReplacedState();
// Some blocks, like tall grass and fire, get replaced
if (previousState.getType() != Material.AIR) {
Events.fireToCancel(event, new BreakBlockEvent(event, create(event.getPlayer()), previousState.getLocation(), previousState.getType()));
}
Events.fireToCancel(event, new PlaceBlockEvent(event, create(event.getPlayer()), event.getBlock()));
}
@EventHandler
@ -124,15 +146,37 @@ public void onBlockBurn(BlockBurnEvent event) {
@EventHandler
public void onEntityChangeBlock(EntityChangeBlockEvent event) {
Block block = event.getBlock();
Entity entity = event.getEntity();
Material to = event.getTo();
// Fire two events: one as BREAK and one as PLACE
if (event.getTo() != Material.AIR && event.getBlock().getType() != Material.AIR) {
Events.fireToCancel(event, new BreakBlockEvent(event, create(event.getEntity()), event.getBlock()));
Events.fireToCancel(event, new PlaceBlockEvent(event, create(event.getEntity()), event.getBlock()));
Events.fireToCancel(event, new BreakBlockEvent(event, create(entity), block));
Events.fireToCancel(event, new PlaceBlockEvent(event, create(entity), block.getLocation(), to));
} else {
if (event.getTo() == Material.AIR) {
Events.fireToCancel(event, new BreakBlockEvent(event, create(event.getEntity()), event.getBlock()));
// Track the source so later we can create a proper chain of causes
if (entity instanceof FallingBlock) {
WGMetadata.put(entity, FALLING_SOURCE_KEY, block);
// Switch around the event
Events.fireToCancel(event, new SpawnEntityEvent(event, create(block), entity));
} else {
Events.fireToCancel(event, new BreakBlockEvent(event, create(entity), event.getBlock()));
}
} else {
Events.fireToCancel(event, new PlaceBlockEvent(event, create(event.getEntity()), event.getBlock()));
List<? extends Cause<?>> causes;
// Return the source for falling blocks
if (entity instanceof FallingBlock) {
Block source = WGMetadata.getIfPresent(entity, FALLING_SOURCE_KEY, Block.class);
causes = create(source, entity);
} else {
causes = create(entity);
}
Events.fireToCancel(event, new PlaceBlockEvent(event, causes, event.getBlock().getLocation(), to));
}
}
}
@ -159,69 +203,37 @@ public void onBlockDamage(BlockDamageEvent event) {
public void onPlayerInteract(PlayerInteractEvent event) {
Player player = event.getPlayer();
@Nullable ItemStack item = player.getItemInHand();
Block block = event.getClickedBlock();
Block clicked = event.getClickedBlock();
Block placed;
List<? extends Cause<?>> causes = create(player);
switch (event.getAction()) {
case PHYSICAL:
// TODO: Don't fire events for blocks that can't be interacted with using PHYSICAL
if (Events.fireAndTestCancel(new UseBlockEvent(event, causes, block))) {
if (Events.fireAndTestCancel(new UseBlockEvent(event, causes, clicked))) {
event.setUseInteractedBlock(Result.DENY);
event.setCancelled(true);
}
break;
case RIGHT_CLICK_BLOCK:
if (item != null && item.getType() == Material.TNT) {
// Workaround for a bug that allowed tnt to trigger instantly if placed
// next to redstone, without plugins getting the block place event
// (not sure if this actually still happens)
Events.fireToCancel(event, new UseBlockEvent(event, create(event.getPlayer()), block.getLocation(), Material.TNT));
}
placed = clicked.getRelative(event.getBlockFace());
// Handle created Minecarts
if (item != null && Materials.isMinecart(item.getType())) {
// TODO: Give a more specific minecart type
Block placedBlock = block.getRelative(event.getBlockFace());
Events.fireToCancel(event, new SpawnEntityEvent(event, create(event.getPlayer()), placedBlock.getLocation().add(0.5, 0, 0.5), EntityType.MINECART));
}
// Handle cocoa beans
if (item != null && item.getType() == Material.INK_SACK && Materials.isDyeColor(item.getData(), DyeColor.BROWN)) {
// CraftBukkit doesn't or didn't throw a block place for this
if (!(event.getBlockFace() == BlockFace.DOWN || event.getBlockFace() == BlockFace.UP)) {
Block placedBlock = block.getRelative(event.getBlockFace());
Events.fireToCancel(event, new PlaceBlockEvent(event, create(event.getPlayer()), placedBlock.getLocation(), Material.COCOA));
}
}
// Workaround for http://leaky.bukkit.org/issues/1034
if (item != null && item.getType() == Material.TNT) {
Block placedBlock = block.getRelative(event.getBlockFace());
Events.fireToCancel(event, new PlaceBlockEvent(event, create(event.getPlayer()), placedBlock.getLocation(), Material.TNT));
}
// Handle flint and steel and fire charge as fire place
if (item != null && (item.getType() == Material.FIREBALL || item.getType() == Material.FLINT_AND_STEEL)) {
Block placedBlock = block.getRelative(event.getBlockFace());
if (!Events.fireAndTestCancel(new PlaceBlockEvent(event, create(event.getPlayer()), placedBlock.getLocation(), Material.FIRE))) {
event.setUseItemInHand(Result.DENY);
}
}
// Re-used for dispensers
handleBlockRightClick(event, create(event.getPlayer()), item, clicked, event.getBlockFace(), placed);
case LEFT_CLICK_BLOCK:
// TODO: Don't fire events for blocks that can't be interacted with using clicks
placed = clicked.getRelative(event.getBlockFace());
// As of MC ~1.6, sneaking blocks the use of blocks with right click
if (!player.isSneaking() || event.getAction() == Action.LEFT_CLICK_BLOCK) {
// Only fire events for blocks that are modified when right clicked
if (isBlockModifiedOnClick(block.getType()) || (item != null && isItemAppliedToBlock(item.getType(), block.getType()))) {
if (Events.fireAndTestCancel(new UseBlockEvent(event, causes, block))) {
if (isBlockModifiedOnClick(clicked.getType()) || (item != null && isItemAppliedToBlock(item.getType(), clicked.getType()))) {
if (Events.fireAndTestCancel(new UseBlockEvent(event, causes, clicked))) {
event.setUseInteractedBlock(Result.DENY);
}
// Handle connected blocks (i.e. beds, chests)
for (Block connected : Blocks.getConnected(block)) {
for (Block connected : Blocks.getConnected(clicked)) {
if (Events.fireAndTestCancel(new UseBlockEvent(event, create(event.getPlayer()), connected))) {
event.setUseInteractedBlock(Result.DENY);
break;
@ -230,8 +242,8 @@ public void onPlayerInteract(PlayerInteractEvent event) {
}
// Special handling of flint and steel on TNT
if (block.getType() == Material.TNT && item != null && item.getType() == Material.FLINT_AND_STEEL) {
if (Events.fireAndTestCancel(new BreakBlockEvent(event, create(event.getPlayer()), block))) {
if (clicked.getType() == Material.TNT && item != null && item.getType() == Material.FLINT_AND_STEEL) {
if (Events.fireAndTestCancel(new BreakBlockEvent(event, create(event.getPlayer()), clicked))) {
event.setUseInteractedBlock(Result.DENY);
break;
}
@ -239,8 +251,8 @@ public void onPlayerInteract(PlayerInteractEvent event) {
}
// Special handling of putting out fires
if (event.getAction() == Action.LEFT_CLICK_BLOCK && block.getType() == Material.FIRE) {
if (Events.fireAndTestCancel(new BreakBlockEvent(event, create(event.getPlayer()), block))) {
if (event.getAction() == Action.LEFT_CLICK_BLOCK && placed.getType() == Material.FIRE) {
if (Events.fireAndTestCancel(new BreakBlockEvent(event, create(event.getPlayer()), placed))) {
event.setUseInteractedBlock(Result.DENY);
break;
}
@ -248,7 +260,7 @@ public void onPlayerInteract(PlayerInteractEvent event) {
case LEFT_CLICK_AIR:
case RIGHT_CLICK_AIR:
if (item != null && Events.fireAndTestCancel(new UseItemEvent(event, causes, player.getWorld(), item))) {
if (item != null && !item.getType().isBlock() && Events.fireAndTestCancel(new UseItemEvent(event, causes, player.getWorld(), item))) {
event.setUseItemInHand(Result.DENY);
}
@ -263,6 +275,7 @@ public void onEntityInteract(org.bukkit.event.entity.EntityInteractEvent event)
@EventHandler
public void onBlockIgnite(BlockIgniteEvent event) {
Block block = event.getBlock();
List<? extends Cause<?>> causes;
// Find the cause
@ -276,7 +289,9 @@ public void onBlockIgnite(BlockIgniteEvent event) {
causes = Collections.emptyList();
}
Events.fireToCancel(event, new BreakBlockEvent(event, causes, event.getBlock()));
if (block.getType() != Material.AIR) {
Events.fireToCancel(event, new BreakBlockEvent(event, causes, event.getBlock()));
}
// This is also handled in the PlayerInteractEvent listener
if (event.getCause() == IgniteCause.FLINT_AND_STEEL || event.getCause() == IgniteCause.FIREBALL) {
@ -303,7 +318,8 @@ public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) {
// Milk buckets can't be emptied as of writing
if (event.getBucket() != Material.MILK_BUCKET) {
ItemStack item = new ItemStack(event.getBucket(), 1);
Events.fireToCancel(event, new PlaceBlockEvent(event, create(player), blockAffected));
Material blockMaterial = Materials.getBucketBlockMaterial(event.getBucket());
Events.fireToCancel(event, new PlaceBlockEvent(event, create(player), blockAffected.getLocation(), blockMaterial));
Events.fireToCancel(event, new UseItemEvent(event, create(player), player.getWorld(), item));
}
}
@ -329,13 +345,34 @@ public void onPlayerBucketFill(PlayerBucketFillEvent event) {
@EventHandler
public void onBlockFromTo(BlockFromToEvent event) {
Events.fireToCancel(event, new PlaceBlockEvent(event, create(event.getBlock()), event.getToBlock()));
if (ABSTRACT_FROM_TO_EVENTS) {
Block from = event.getBlock();
Block to = event.getToBlock();
// Liquids pass this event when flowing to solid blocks
if (to.getType().isSolid() && Materials.isLiquid(from.getType())) {
return;
}
List<? extends Cause<?>> causes = create(from);
if (from.getType() != Material.AIR) {
Events.fireToCancel(event, new BreakBlockEvent(event, causes, to));
}
Events.fireToCancel(event, new PlaceBlockEvent(event, causes, to.getLocation(), from.getType()));
}
}
//-------------------------------------------------------------------------
// Entity break / place
//-------------------------------------------------------------------------
@EventHandler
public void onCreatureSpawn(CreatureSpawnEvent event) {
Events.fireToCancel(event, new SpawnEntityEvent(event, Collections.<Cause<?>>emptyList(), event.getEntity()));
}
@EventHandler
public void onHangingPlace(HangingPlaceEvent event) {
Events.fireToCancel(event, new SpawnEntityEvent(event, create(event.getPlayer()), event.getEntity()));
@ -355,6 +392,8 @@ public void onVehicleDestroy(VehicleDestroyEvent event) {
Events.fireToCancel(event, new DestroyEntityEvent(event, create(event.getAttacker()), event.getVehicle()));
}
// TODO: XP pickup is an entity destroy event
//-------------------------------------------------------------------------
// Entity external interaction
//-------------------------------------------------------------------------
@ -482,7 +521,59 @@ public void onPotionSplash(PotionSplashEvent event) {
@EventHandler
public void onBlockDispense(BlockDispenseEvent event) {
Events.fireToCancel(event, new UseItemEvent(event, create(event.getBlock()), event.getBlock().getWorld(), event.getItem()));
List<? extends Cause<?>> causes = create(event.getBlock());
Block dispenserBlock = event.getBlock();
ItemStack item = event.getItem();
MaterialData materialData = dispenserBlock.getState().getData();
Events.fireToCancel(event, new UseItemEvent(event, causes, dispenserBlock.getWorld(), item));
// Simulate right click event as players have it
if (materialData instanceof Dispenser) {
Dispenser dispenser = (Dispenser) materialData;
Block placed = dispenserBlock.getRelative(dispenser.getFacing());
Block clicked = placed.getRelative(dispenser.getFacing());
handleBlockRightClick(event, causes, item, clicked, dispenser.getFacing().getOppositeFace(), placed);
}
}
/**
* Handle the right click of a block while an item is held.
*
* @param event the original event
* @param causes the list of causes
* @param item the item
* @param clicked the clicked block
* @param faceClicked the face of the clicked block
* @param placed the placed block
* @param <T> the event type
*/
private static <T extends Event & Cancellable> void handleBlockRightClick(T event, List<? extends Cause<?>> causes, @Nullable ItemStack item, Block clicked, BlockFace faceClicked, Block placed) {
if (item != null && item.getType() == Material.TNT) {
// Workaround for a bug that allowed TNT to trigger instantly if placed
// next to redstone, without plugins getting the clicked place event
// (not sure if this actually still happens)
Events.fireToCancel(event, new UseBlockEvent(event, causes, clicked.getLocation(), Material.TNT));
}
// Handle created Minecarts
if (item != null && Materials.isMinecart(item.getType())) {
// TODO: Give a more specific Minecart type
Events.fireToCancel(event, new SpawnEntityEvent(event, causes, placed.getLocation().add(0.5, 0, 0.5), EntityType.MINECART));
}
// Handle cocoa beans
if (item != null && item.getType() == Material.INK_SACK && Materials.isDyeColor(item.getData(), DyeColor.BROWN)) {
// CraftBukkit doesn't or didn't throw a clicked place for this
if (!(faceClicked == BlockFace.DOWN || faceClicked == BlockFace.UP)) {
Events.fireToCancel(event, new PlaceBlockEvent(event, causes, placed.getLocation(), Material.COCOA));
}
}
// Workaround for http://leaky.bukkit.org/issues/1034
if (item != null && item.getType() == Material.TNT) {
Events.fireToCancel(event, new PlaceBlockEvent(event, causes, placed.getLocation(), Material.TNT));
}
}
// TODO: Inventory events?

View File

@ -38,7 +38,7 @@ private Events() {
*
* @param eventToFire the event to fire
* @param <T> an event that can be fired and is cancellable
* @return true if the event was fired
* @return true if the event was cancelled
*/
public static <T extends Event & Cancellable> boolean fireAndTestCancel( T eventToFire) {
Bukkit.getServer().getPluginManager().callEvent(eventToFire);

View File

@ -36,8 +36,8 @@
*/
public final class Materials {
private static final int MODIFED_ON_CLICK = 1;
private static final int MODIFIES_BLOCKS = 1;
private static final int MODIFIED_ON_CLICK = 1;
private static final int MODIFIES_BLOCKS = 2;
private static final BiMap<EntityType, Material> ENTITY_ITEMS = HashBiMap.create();
private static final Map<Material, Integer> MATERIAL_FLAGS = new HashMap<Material, Integer>();
@ -86,10 +86,10 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.GLASS, 0);
MATERIAL_FLAGS.put(Material.LAPIS_ORE, 0);
MATERIAL_FLAGS.put(Material.LAPIS_BLOCK, 0);
MATERIAL_FLAGS.put(Material.DISPENSER, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.DISPENSER, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.SANDSTONE, 0);
MATERIAL_FLAGS.put(Material.NOTE_BLOCK, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.BED_BLOCK, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.NOTE_BLOCK, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.BED_BLOCK, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.POWERED_RAIL, 0);
MATERIAL_FLAGS.put(Material.DETECTOR_RAIL, 0);
MATERIAL_FLAGS.put(Material.PISTON_STICKY_BASE, 0);
@ -109,7 +109,7 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.DOUBLE_STEP, 0);
MATERIAL_FLAGS.put(Material.STEP, 0);
MATERIAL_FLAGS.put(Material.BRICK, 0);
MATERIAL_FLAGS.put(Material.TNT, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.TNT, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.BOOKSHELF, 0);
MATERIAL_FLAGS.put(Material.MOSSY_COBBLESTONE, 0);
MATERIAL_FLAGS.put(Material.OBSIDIAN, 0);
@ -117,37 +117,37 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.FIRE, 0);
MATERIAL_FLAGS.put(Material.MOB_SPAWNER, 0);
MATERIAL_FLAGS.put(Material.WOOD_STAIRS, 0);
MATERIAL_FLAGS.put(Material.CHEST, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.CHEST, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.REDSTONE_WIRE, 0);
MATERIAL_FLAGS.put(Material.DIAMOND_ORE, 0);
MATERIAL_FLAGS.put(Material.DIAMOND_BLOCK, 0);
MATERIAL_FLAGS.put(Material.WORKBENCH, 0);
MATERIAL_FLAGS.put(Material.CROPS, 0);
MATERIAL_FLAGS.put(Material.SOIL, 0);
MATERIAL_FLAGS.put(Material.FURNACE, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.BURNING_FURNACE, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.FURNACE, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.BURNING_FURNACE, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.SIGN_POST, 0);
MATERIAL_FLAGS.put(Material.WOODEN_DOOR, 0);
MATERIAL_FLAGS.put(Material.LADDER, 0);
MATERIAL_FLAGS.put(Material.RAILS, 0);
MATERIAL_FLAGS.put(Material.COBBLESTONE_STAIRS, 0);
MATERIAL_FLAGS.put(Material.WALL_SIGN, 0);
MATERIAL_FLAGS.put(Material.LEVER, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.LEVER, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.STONE_PLATE, 0);
MATERIAL_FLAGS.put(Material.IRON_DOOR_BLOCK, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.IRON_DOOR_BLOCK, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.WOOD_PLATE, 0);
MATERIAL_FLAGS.put(Material.REDSTONE_ORE, 0);
MATERIAL_FLAGS.put(Material.GLOWING_REDSTONE_ORE, 0);
MATERIAL_FLAGS.put(Material.REDSTONE_TORCH_OFF, 0);
MATERIAL_FLAGS.put(Material.REDSTONE_TORCH_ON, 0);
MATERIAL_FLAGS.put(Material.STONE_BUTTON, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.STONE_BUTTON, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.SNOW, 0);
MATERIAL_FLAGS.put(Material.ICE, 0);
MATERIAL_FLAGS.put(Material.SNOW_BLOCK, 0);
MATERIAL_FLAGS.put(Material.CACTUS, 0);
MATERIAL_FLAGS.put(Material.CLAY, 0);
MATERIAL_FLAGS.put(Material.SUGAR_CANE_BLOCK, 0);
MATERIAL_FLAGS.put(Material.JUKEBOX, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.JUKEBOX, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.FENCE, 0);
MATERIAL_FLAGS.put(Material.PUMPKIN, 0);
MATERIAL_FLAGS.put(Material.NETHERRACK, 0);
@ -155,11 +155,11 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.GLOWSTONE, 0);
MATERIAL_FLAGS.put(Material.PORTAL, 0);
MATERIAL_FLAGS.put(Material.JACK_O_LANTERN, 0);
MATERIAL_FLAGS.put(Material.CAKE_BLOCK, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.DIODE_BLOCK_OFF, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.DIODE_BLOCK_ON, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.CAKE_BLOCK, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.DIODE_BLOCK_OFF, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.DIODE_BLOCK_ON, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.STAINED_GLASS, 0);
MATERIAL_FLAGS.put(Material.TRAP_DOOR, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.TRAP_DOOR, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.MONSTER_EGGS, 0);
MATERIAL_FLAGS.put(Material.SMOOTH_BRICK, 0);
MATERIAL_FLAGS.put(Material.HUGE_MUSHROOM_1, 0);
@ -170,7 +170,7 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.PUMPKIN_STEM, 0);
MATERIAL_FLAGS.put(Material.MELON_STEM, 0);
MATERIAL_FLAGS.put(Material.VINE, 0);
MATERIAL_FLAGS.put(Material.FENCE_GATE, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.FENCE_GATE, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.BRICK_STAIRS, 0);
MATERIAL_FLAGS.put(Material.SMOOTH_STAIRS, 0);
MATERIAL_FLAGS.put(Material.MYCEL, 0);
@ -180,12 +180,12 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.NETHER_BRICK_STAIRS, 0);
MATERIAL_FLAGS.put(Material.NETHER_WARTS, 0);
MATERIAL_FLAGS.put(Material.ENCHANTMENT_TABLE, 0);
MATERIAL_FLAGS.put(Material.BREWING_STAND, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.CAULDRON, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.BREWING_STAND, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.CAULDRON, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.ENDER_PORTAL, 0);
MATERIAL_FLAGS.put(Material.ENDER_PORTAL_FRAME, 0);
MATERIAL_FLAGS.put(Material.ENDER_STONE, 0);
MATERIAL_FLAGS.put(Material.DRAGON_EGG, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.DRAGON_EGG, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.REDSTONE_LAMP_OFF, 0);
MATERIAL_FLAGS.put(Material.REDSTONE_LAMP_ON, 0);
MATERIAL_FLAGS.put(Material.WOOD_DOUBLE_STEP, 0);
@ -200,28 +200,28 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.SPRUCE_WOOD_STAIRS, 0);
MATERIAL_FLAGS.put(Material.BIRCH_WOOD_STAIRS, 0);
MATERIAL_FLAGS.put(Material.JUNGLE_WOOD_STAIRS, 0);
MATERIAL_FLAGS.put(Material.COMMAND, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.BEACON, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.COMMAND, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.BEACON, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.COBBLE_WALL, 0);
MATERIAL_FLAGS.put(Material.FLOWER_POT, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.FLOWER_POT, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.CARROT, 0);
MATERIAL_FLAGS.put(Material.POTATO, 0);
MATERIAL_FLAGS.put(Material.WOOD_BUTTON, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.WOOD_BUTTON, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.SKULL, 0);
MATERIAL_FLAGS.put(Material.ANVIL, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.TRAPPED_CHEST, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.ANVIL, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.TRAPPED_CHEST, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.GOLD_PLATE, 0);
MATERIAL_FLAGS.put(Material.IRON_PLATE, 0);
MATERIAL_FLAGS.put(Material.REDSTONE_COMPARATOR_OFF, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.REDSTONE_COMPARATOR_ON, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.DAYLIGHT_DETECTOR, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.REDSTONE_COMPARATOR_OFF, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.REDSTONE_COMPARATOR_ON, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.DAYLIGHT_DETECTOR, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.REDSTONE_BLOCK, 0);
MATERIAL_FLAGS.put(Material.QUARTZ_ORE, 0);
MATERIAL_FLAGS.put(Material.HOPPER, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.HOPPER, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.QUARTZ_BLOCK, 0);
MATERIAL_FLAGS.put(Material.QUARTZ_STAIRS, 0);
MATERIAL_FLAGS.put(Material.ACTIVATOR_RAIL, 0);
MATERIAL_FLAGS.put(Material.DROPPER, MODIFED_ON_CLICK);
MATERIAL_FLAGS.put(Material.DROPPER, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.STAINED_CLAY, 0);
MATERIAL_FLAGS.put(Material.STAINED_GLASS_PANE, 0);
MATERIAL_FLAGS.put(Material.LEAVES_2, 0);
@ -422,6 +422,30 @@ public static Material getRelatedMaterial(EntityType type) {
return ENTITY_ITEMS.get(type);
}
/**
* Get the material of the block placed by the given bucket, defaulting
* to water if the bucket type is not known.
*
* <p>If a non-bucket material is given, it will be assumed to be
* an unknown bucket type. If the given bucket doesn't have a block form
* (it can't be placed), then water will be returned (i.e. for milk).
* Be aware that either the stationary or non-stationary material may be
* returned.</p>
*
* @param type the bucket material
* @return the block material
*/
public static Material getBucketBlockMaterial(Material type) {
switch (type) {
case LAVA_BUCKET:
return Material.LAVA;
case MILK_BUCKET:
return Material.WATER;
default:
return Material.WATER;
}
}
/**
* Test whether the given material is a mushroom.
*
@ -442,6 +466,16 @@ public static boolean isLeaf(Material material) {
return material == Material.LEAVES || material == Material.LEAVES_2;
}
/**
* Test whether the given material is a liquid block.
*
* @param material the material
* @return true if a liquid block
*/
public static boolean isLiquid(Material material) {
return isWater(material) || isLava(material);
}
/**
* Test whether the given material is water.
*
@ -542,13 +576,13 @@ public static boolean isInventoryBlock(Material material) {
*/
public static boolean isBlockModifiedOnClick(Material material) {
Integer flags = MATERIAL_FLAGS.get(material);
return flags == null || (flags & MODIFED_ON_CLICK) == MODIFED_ON_CLICK;
return flags == null || (flags & MODIFIED_ON_CLICK) == MODIFIED_ON_CLICK;
}
/**
* Test whether the given item modifies a given block when right clicked.
*
* <p>This test is conservative, returning true for blocks that it is not
* <p>This test is conservative, returning true for items that it is not
* aware of or does not have the details for.</p>
*
* @param item the item

View File

@ -0,0 +1,78 @@
/*
* 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.util;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.metadata.MetadataValue;
import org.bukkit.metadata.Metadatable;
import javax.annotation.Nullable;
import java.util.List;
/**
* Utility methods for dealing with metadata on entities.
*
* <p>WorldGuard is placed as the owner of all values.</p>
*/
public final class WGMetadata {
private WGMetadata() {
}
/**
* Add some metadata to a target.
*
* @param target the target
* @param key the key
* @param value the value
*/
public static void put(Metadatable target, String key, Object value) {
target.setMetadata(key, new FixedMetadataValue(WorldGuardPlugin.inst(), value));
}
/**
* Get the (first) metadata value on the given target that has the given
* key and is of the given class type.
*
* @param target the target
* @param key the key
* @param expected the type of the value
* @param <T> the type of the value
* @return a value, or {@code null} if one does not exists
*/
@Nullable
@SuppressWarnings("unchecked")
public static <T> T getIfPresent(Metadatable target, String key, Class<T> expected) {
List<MetadataValue> values = target.getMetadata(key);
WorldGuardPlugin owner = WorldGuardPlugin.inst();
for (MetadataValue value : values) {
if (value.getOwningPlugin() == owner) {
Object v = value.value();
if (expected.isInstance(v)) {
return (T) v;
}
}
}
return null;
}
}

View File

@ -45,4 +45,9 @@ public Block get() {
return block;
}
@Override
public String toString() {
return block.toString();
}
}

View File

@ -90,7 +90,7 @@ public static List<? extends Cause<?>> create(Object ... cause) {
} else if (o instanceof Block) {
causes.add(new BlockCause((Block) o));
} else if (o instanceof Projectile) {
causes.addAll(create(o));
causes.addAll(create(((Projectile) o).getShooter()));
causes.add(new EntityCause((Entity) o));
} else if (o instanceof Entity) {
causes.add(new EntityCause((Entity) o));

View File

@ -45,4 +45,8 @@ public Entity get() {
return entity;
}
@Override
public String toString() {
return entity.toString();
}
}

View File

@ -45,4 +45,9 @@ public Player get() {
return player;
}
@Override
public String toString() {
return player.getName();
}
}

View File

@ -43,4 +43,8 @@ public Object get() {
return cause;
}
@Override
public String toString() {
return "unknown(" + cause + ")";
}
}