mirror of
https://github.com/EngineHub/WorldGuard.git
synced 2024-09-16 00:56:41 +02:00
600 lines
26 KiB
Java
600 lines
26 KiB
Java
/*
|
|
* 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.listener;
|
|
|
|
import com.google.common.collect.Lists;
|
|
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;
|
|
import com.sk89q.worldguard.bukkit.event.entity.DestroyEntityEvent;
|
|
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.BlockStateAsBlockFunction;
|
|
import com.sk89q.worldguard.bukkit.util.Blocks;
|
|
import com.sk89q.worldguard.bukkit.util.Events;
|
|
import com.sk89q.worldguard.bukkit.util.Materials;
|
|
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.Item;
|
|
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;
|
|
import org.bukkit.event.block.Action;
|
|
import org.bukkit.event.block.BlockBreakEvent;
|
|
import org.bukkit.event.block.BlockBurnEvent;
|
|
import org.bukkit.event.block.BlockDamageEvent;
|
|
import org.bukkit.event.block.BlockDispenseEvent;
|
|
import org.bukkit.event.block.BlockFromToEvent;
|
|
import org.bukkit.event.block.BlockIgniteEvent;
|
|
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;
|
|
import org.bukkit.event.entity.EntityCombustEvent;
|
|
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;
|
|
import org.bukkit.event.hanging.HangingBreakByEntityEvent;
|
|
import org.bukkit.event.hanging.HangingBreakEvent;
|
|
import org.bukkit.event.hanging.HangingPlaceEvent;
|
|
import org.bukkit.event.player.PlayerBedEnterEvent;
|
|
import org.bukkit.event.player.PlayerBucketEmptyEvent;
|
|
import org.bukkit.event.player.PlayerBucketFillEvent;
|
|
import org.bukkit.event.player.PlayerDropItemEvent;
|
|
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
|
import org.bukkit.event.player.PlayerInteractEvent;
|
|
import org.bukkit.event.player.PlayerPickupItemEvent;
|
|
import org.bukkit.event.player.PlayerShearEntityEvent;
|
|
import org.bukkit.event.player.PlayerUnleashEntityEvent;
|
|
import org.bukkit.event.vehicle.VehicleDamageEvent;
|
|
import org.bukkit.event.vehicle.VehicleDestroyEvent;
|
|
import org.bukkit.event.world.StructureGrowEvent;
|
|
import org.bukkit.inventory.ItemStack;
|
|
import org.bukkit.material.Dispenser;
|
|
import org.bukkit.material.MaterialData;
|
|
import org.bukkit.util.Vector;
|
|
|
|
import javax.annotation.Nullable;
|
|
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 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 final WorldGuardPlugin plugin;
|
|
|
|
public EventAbstractionListener(WorldGuardPlugin plugin) {
|
|
this.plugin = plugin;
|
|
}
|
|
|
|
public void registerEvents() {
|
|
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Block break / place
|
|
//-------------------------------------------------------------------------
|
|
|
|
@EventHandler
|
|
public void onBlockBreak(BlockBreakEvent event) {
|
|
Events.fireToCancel(event, new BreakBlockEvent(event, create(event.getPlayer()), event.getBlock()));
|
|
}
|
|
|
|
@EventHandler
|
|
public void onBlockPlace(BlockPlaceEvent event) {
|
|
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
|
|
public void onBlockBurn(BlockBurnEvent event) {
|
|
Events.fireToCancel(event, new UseBlockEvent(event, Cause.unknown(), event.getBlock()));
|
|
}
|
|
|
|
@EventHandler
|
|
public void onStructureGrowEvent(StructureGrowEvent event) {
|
|
List<Block> blockList = Lists.transform(event.getBlocks(), new BlockStateAsBlockFunction());
|
|
Events.fireBulkEventToCancel(event, new PlaceBlockEvent(event, create(event.getPlayer()), event.getLocation().getWorld(), blockList, Material.AIR));
|
|
}
|
|
|
|
// TODO: Handle EntityCreatePortalEvent?
|
|
|
|
@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(entity), block));
|
|
Events.fireToCancel(event, new PlaceBlockEvent(event, create(entity), block.getLocation(), to));
|
|
} else {
|
|
if (event.getTo() == Material.AIR) {
|
|
// Track the source so later we can create a proper chain of causes
|
|
if (entity instanceof FallingBlock) {
|
|
Cause.trackParentCause(entity, 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 {
|
|
boolean wasCancelled = event.isCancelled();
|
|
Cause cause = create(entity);
|
|
|
|
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, event.getBlock().getLocation(), to));
|
|
|
|
if (event.isCancelled() && !wasCancelled && entity instanceof FallingBlock) {
|
|
FallingBlock fallingBlock = (FallingBlock) entity;
|
|
ItemStack itemStack = new ItemStack(fallingBlock.getMaterial(), 1, fallingBlock.getBlockData());
|
|
Item item = block.getWorld().dropItem(fallingBlock.getLocation(), itemStack);
|
|
item.setVelocity(new Vector());
|
|
if (Events.fireAndTestCancel(new SpawnEntityEvent(event, create(block, entity), item))) {
|
|
item.remove();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@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
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Block external interaction
|
|
//-------------------------------------------------------------------------
|
|
|
|
@EventHandler
|
|
public void onBlockDamage(BlockDamageEvent event) {
|
|
Block target = event.getBlock();
|
|
|
|
// Previously, and perhaps still, the only way to catch cake eating
|
|
// events was through here
|
|
if (target.getType() == Material.CAKE_BLOCK) {
|
|
Events.fireToCancel(event, new UseBlockEvent(event, create(event.getPlayer()), target));
|
|
}
|
|
}
|
|
|
|
@EventHandler
|
|
public void onPlayerInteract(PlayerInteractEvent event) {
|
|
Player player = event.getPlayer();
|
|
@Nullable ItemStack item = player.getItemInHand();
|
|
Block clicked = event.getClickedBlock();
|
|
Block placed;
|
|
Cause cause = create(player);
|
|
|
|
switch (event.getAction()) {
|
|
case PHYSICAL:
|
|
if (Events.fireAndTestCancel(new UseBlockEvent(event, cause, clicked))) {
|
|
event.setUseInteractedBlock(Result.DENY);
|
|
event.setCancelled(true);
|
|
}
|
|
break;
|
|
|
|
case RIGHT_CLICK_BLOCK:
|
|
placed = clicked.getRelative(event.getBlockFace());
|
|
|
|
// Re-used for dispensers
|
|
handleBlockRightClick(event, create(event.getPlayer()), item, clicked, event.getBlockFace(), placed);
|
|
|
|
case LEFT_CLICK_BLOCK:
|
|
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(clicked.getType()) || (item != null && isItemAppliedToBlock(item.getType(), clicked.getType()))) {
|
|
if (Events.fireAndTestCancel(new UseBlockEvent(event, cause, clicked))) {
|
|
event.setUseInteractedBlock(Result.DENY);
|
|
}
|
|
|
|
// Handle connected blocks (i.e. beds, chests)
|
|
for (Block connected : Blocks.getConnected(clicked)) {
|
|
if (Events.fireAndTestCancel(new UseBlockEvent(event, create(event.getPlayer()), connected))) {
|
|
event.setUseInteractedBlock(Result.DENY);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Special handling of putting out fires
|
|
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;
|
|
}
|
|
}
|
|
|
|
case LEFT_CLICK_AIR:
|
|
case RIGHT_CLICK_AIR:
|
|
if (item != null && !item.getType().isBlock() && Events.fireAndTestCancel(new UseItemEvent(event, cause, player.getWorld(), item))) {
|
|
event.setUseItemInHand(Result.DENY);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
@EventHandler
|
|
public void onEntityInteract(org.bukkit.event.entity.EntityInteractEvent event) {
|
|
Events.fireToCancel(event, new UseBlockEvent(event, create(event.getEntity()), event.getBlock()));
|
|
}
|
|
|
|
@EventHandler
|
|
public void onBlockIgnite(BlockIgniteEvent event) {
|
|
Block block = event.getBlock();
|
|
Cause cause;
|
|
|
|
// Find the cause
|
|
if (event.getPlayer() != null) {
|
|
cause = create(event.getPlayer());
|
|
} else if (event.getIgnitingEntity() != null) {
|
|
cause = create(event.getIgnitingEntity());
|
|
} else if (event.getIgnitingBlock() != null) {
|
|
cause = create(event.getIgnitingBlock());
|
|
} else {
|
|
cause = Cause.unknown();
|
|
}
|
|
|
|
if (block.getType() != Material.AIR) {
|
|
Events.fireToCancel(event, new BreakBlockEvent(event, cause, event.getBlock()));
|
|
}
|
|
|
|
// This is also handled in the PlayerInteractEvent listener
|
|
if (event.getCause() == IgniteCause.FLINT_AND_STEEL || event.getCause() == IgniteCause.FIREBALL) {
|
|
// TODO: Test location of block
|
|
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, event.getBlock().getLocation(), Material.FIRE));
|
|
}
|
|
}
|
|
|
|
@EventHandler
|
|
public void onSignChange(SignChangeEvent event) {
|
|
Events.fireToCancel(event, new UseBlockEvent(event, create(event.getPlayer()), event.getBlock()));
|
|
}
|
|
|
|
@EventHandler
|
|
public void onBedEnter(PlayerBedEnterEvent event) {
|
|
Events.fireToCancel(event, new UseBlockEvent(event, create(event.getPlayer()), event.getBed()));
|
|
}
|
|
|
|
@EventHandler
|
|
public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) {
|
|
Player player = event.getPlayer();
|
|
Block blockAffected = event.getBlockClicked().getRelative(event.getBlockFace());
|
|
|
|
// Milk buckets can't be emptied as of writing
|
|
if (event.getBucket() != Material.MILK_BUCKET) {
|
|
ItemStack item = new ItemStack(event.getBucket(), 1);
|
|
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));
|
|
}
|
|
}
|
|
|
|
@EventHandler
|
|
public void onPlayerBucketFill(PlayerBucketFillEvent event) {
|
|
Player player = event.getPlayer();
|
|
Block blockAffected = event.getBlockClicked().getRelative(event.getBlockFace());
|
|
|
|
// Milk buckets can't be filled by right clicking the ground as of writing
|
|
if (event.getBucket() != Material.MILK_BUCKET) {
|
|
ItemStack item = new ItemStack(event.getBucket(), 1);
|
|
Events.fireToCancel(event, new BreakBlockEvent(event, create(player), blockAffected));
|
|
Events.fireToCancel(event, new UseItemEvent(event, create(player), player.getWorld(), item));
|
|
}
|
|
}
|
|
|
|
// TODO: Handle EntityPortalEnterEvent
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Block self-interaction
|
|
//-------------------------------------------------------------------------
|
|
|
|
@EventHandler
|
|
public void onBlockFromTo(BlockFromToEvent event) {
|
|
Block from = event.getBlock();
|
|
Block to = event.getToBlock();
|
|
Material fromType = from.getType();
|
|
Material toType = to.getType();
|
|
|
|
// Liquids pass this event when flowing to solid blocks
|
|
if (toType.isSolid() && Materials.isLiquid(fromType)) {
|
|
return;
|
|
}
|
|
|
|
// This significantly reduces the number of events without having
|
|
// too much effect. Unfortunately it appears that even if this
|
|
// check didn't exist, you can raise the level of some liquid
|
|
// flow and the from/to data may not be correct.
|
|
if ((Materials.isWater(fromType) && Materials.isWater(toType)) || (Materials.isLava(fromType) && Materials.isLava(toType))) {
|
|
return;
|
|
}
|
|
|
|
Cause cause = create(from);
|
|
|
|
// Disable since it's probably not needed
|
|
/*if (from.getType() != Material.AIR) {
|
|
Events.fireToCancel(event, new BreakBlockEvent(event, cause, to));
|
|
}*/
|
|
|
|
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, to.getLocation(), from.getType()));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Entity break / place
|
|
//-------------------------------------------------------------------------
|
|
|
|
@EventHandler
|
|
public void onCreatureSpawn(CreatureSpawnEvent event) {
|
|
Events.fireToCancel(event, new SpawnEntityEvent(event, Cause.unknown(), event.getEntity()));
|
|
}
|
|
|
|
@EventHandler
|
|
public void onHangingPlace(HangingPlaceEvent event) {
|
|
Events.fireToCancel(event, new SpawnEntityEvent(event, create(event.getPlayer()), event.getEntity()));
|
|
}
|
|
|
|
@EventHandler
|
|
public void onHangingBreak(HangingBreakEvent event) {
|
|
if (event instanceof HangingBreakByEntityEvent) {
|
|
Events.fireToCancel(event, new DestroyEntityEvent(event, create(((HangingBreakByEntityEvent) event).getRemover()), event.getEntity()));
|
|
} else {
|
|
Events.fireToCancel(event, new DestroyEntityEvent(event, Cause.unknown(), event.getEntity()));
|
|
}
|
|
}
|
|
|
|
@EventHandler
|
|
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
|
|
//-------------------------------------------------------------------------
|
|
|
|
@EventHandler
|
|
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
|
|
Player player = event.getPlayer();
|
|
World world = player.getWorld();
|
|
ItemStack item = player.getItemInHand();
|
|
Entity entity = event.getRightClicked();
|
|
|
|
Events.fireToCancel(event, new UseItemEvent(event, create(player), world, item));
|
|
Events.fireToCancel(event, new UseEntityEvent(event, create(player), entity));
|
|
}
|
|
|
|
@EventHandler
|
|
public void onEntityDamage(EntityDamageEvent event) {
|
|
if (event instanceof EntityDamageByBlockEvent) {
|
|
Events.fireToCancel(event, new UseEntityEvent(event, create(((EntityDamageByBlockEvent) event).getDamager()), event.getEntity()));
|
|
|
|
} else if (event instanceof EntityDamageByEntityEvent) {
|
|
EntityDamageByEntityEvent entityEvent = (EntityDamageByEntityEvent) event;
|
|
Entity damager = entityEvent.getDamager();
|
|
Events.fireToCancel(event, new UseEntityEvent(event, create(damager), event.getEntity()));
|
|
|
|
// Item use event with the item in hand
|
|
// Older blacklist handler code used this, although it suffers from
|
|
// race problems
|
|
if (damager instanceof Player) {
|
|
ItemStack item = ((Player) damager).getItemInHand();
|
|
|
|
if (item != null) {
|
|
Events.fireToCancel(event, new UseItemEvent(event, create(damager), event.getEntity().getWorld(), item));
|
|
}
|
|
}
|
|
|
|
} else {
|
|
Events.fireToCancel(event, new UseEntityEvent(event, Cause.unknown(), event.getEntity()));
|
|
}
|
|
}
|
|
|
|
@EventHandler
|
|
public void onEntityCombust(EntityCombustEvent event) {
|
|
if (event instanceof EntityCombustByBlockEvent) {
|
|
Events.fireToCancel(event, new UseEntityEvent(event, create(((EntityCombustByBlockEvent) event).getCombuster()), event.getEntity()));
|
|
|
|
} else if (event instanceof EntityCombustByEntityEvent) {
|
|
Events.fireToCancel(event, new UseEntityEvent(event, create(((EntityCombustByEntityEvent) event).getCombuster()), event.getEntity()));
|
|
|
|
} else {
|
|
Events.fireToCancel(event, new UseEntityEvent(event, Cause.unknown(), event.getEntity()));
|
|
}
|
|
}
|
|
|
|
@EventHandler
|
|
public void onEntityUnleash(EntityUnleashEvent event) {
|
|
if (event instanceof PlayerUnleashEntityEvent) {
|
|
PlayerUnleashEntityEvent playerEvent = (PlayerUnleashEntityEvent) event;
|
|
Events.fireToCancel(playerEvent, new UseEntityEvent(playerEvent, create(playerEvent.getPlayer()), event.getEntity()));
|
|
} else {
|
|
// TODO: Raise anyway?
|
|
}
|
|
}
|
|
|
|
@EventHandler
|
|
public void onEntityTame(EntityTameEvent event) {
|
|
Events.fireToCancel(event, new UseEntityEvent(event, create(event.getOwner()), event.getEntity()));
|
|
}
|
|
|
|
@EventHandler
|
|
public void onPlayerShearEntity(PlayerShearEntityEvent event) {
|
|
Events.fireToCancel(event, new UseEntityEvent(event, create(event.getPlayer()), event.getEntity()));
|
|
}
|
|
|
|
@EventHandler
|
|
public void onPlayerPickupItem(PlayerPickupItemEvent event) {
|
|
Events.fireToCancel(event, new DestroyEntityEvent(event, create(event.getPlayer()), event.getItem()));
|
|
}
|
|
|
|
@EventHandler
|
|
public void onPlayerDropItem(PlayerDropItemEvent event) {
|
|
Events.fireToCancel(event, new SpawnEntityEvent(event, create(event.getPlayer()), event.getItemDrop()));
|
|
}
|
|
|
|
@EventHandler
|
|
public void onVehicleDamage(VehicleDamageEvent event) {
|
|
Events.fireToCancel(event, new DestroyEntityEvent(event, create(event.getAttacker()), event.getVehicle()));
|
|
}
|
|
|
|
@EventHandler
|
|
public void onVehicleEnter(VehicleDamageEvent event) {
|
|
Events.fireToCancel(event, new UseEntityEvent(event, create(event.getAttacker()), event.getVehicle()));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Composite events
|
|
//-------------------------------------------------------------------------
|
|
|
|
@EventHandler
|
|
public void onPotionSplash(PotionSplashEvent event) {
|
|
Entity entity = event.getEntity();
|
|
ThrownPotion potion = event.getPotion();
|
|
World world = entity.getWorld();
|
|
Cause cause = create(potion.getShooter());
|
|
|
|
// Fire item interaction event
|
|
Events.fireToCancel(event, new UseItemEvent(event, cause, world, potion.getItem()));
|
|
|
|
// Fire entity interaction event
|
|
if (!event.isCancelled()) {
|
|
int blocked = 0;
|
|
|
|
for (LivingEntity affected : event.getAffectedEntities()) {
|
|
if (Events.fireAndTestCancel(new UseEntityEvent(event, cause, affected))) {
|
|
event.setIntensity(affected, 0);
|
|
blocked++;
|
|
}
|
|
}
|
|
|
|
if (blocked == event.getAffectedEntities().size()) {
|
|
event.setCancelled(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
@EventHandler
|
|
public void onBlockDispense(BlockDispenseEvent event) {
|
|
Cause cause = create(event.getBlock());
|
|
Block dispenserBlock = event.getBlock();
|
|
ItemStack item = event.getItem();
|
|
MaterialData materialData = dispenserBlock.getState().getData();
|
|
|
|
Events.fireToCancel(event, new UseItemEvent(event, cause, 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, cause, item, clicked, dispenser.getFacing().getOppositeFace(), placed);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle the right click of a block while an item is held.
|
|
*
|
|
* @param event the original event
|
|
* @param cause the list of cause
|
|
* @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, Cause cause, @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, cause, 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, cause, 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, cause, 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, cause, placed.getLocation(), Material.TNT));
|
|
}
|
|
}
|
|
|
|
// TODO: Inventory events?
|
|
|
|
}
|