2014-08-12 02:40:04 +02:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
2014-08-17 22:16:45 +02:00
|
|
|
import com.google.common.collect.Lists;
|
2014-08-22 22:37:02 +02:00
|
|
|
import com.sk89q.worldguard.bukkit.WorldConfiguration;
|
2014-08-12 02:40:04 +02:00
|
|
|
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
2014-08-13 04:48:20 +02:00
|
|
|
import com.sk89q.worldguard.bukkit.cause.Cause;
|
2015-01-05 04:54:34 +01:00
|
|
|
import com.sk89q.worldguard.bukkit.event.DelegateEvent;
|
2014-08-25 02:56:15 +02:00
|
|
|
import com.sk89q.worldguard.bukkit.event.DelegateEvents;
|
2014-08-12 02:51:00 +02:00
|
|
|
import com.sk89q.worldguard.bukkit.event.block.BreakBlockEvent;
|
|
|
|
import com.sk89q.worldguard.bukkit.event.block.PlaceBlockEvent;
|
|
|
|
import com.sk89q.worldguard.bukkit.event.block.UseBlockEvent;
|
2015-01-07 00:00:13 +01:00
|
|
|
import com.sk89q.worldguard.bukkit.event.entity.DamageEntityEvent;
|
|
|
|
import com.sk89q.worldguard.bukkit.event.entity.DestroyEntityEvent;
|
|
|
|
import com.sk89q.worldguard.bukkit.event.entity.SpawnEntityEvent;
|
|
|
|
import com.sk89q.worldguard.bukkit.event.entity.UseEntityEvent;
|
2014-08-12 02:51:00 +02:00
|
|
|
import com.sk89q.worldguard.bukkit.event.inventory.UseItemEvent;
|
2014-09-01 02:39:01 +02:00
|
|
|
import com.sk89q.worldguard.bukkit.listener.debounce.BlockPistonExtendKey;
|
|
|
|
import com.sk89q.worldguard.bukkit.listener.debounce.BlockPistonRetractKey;
|
|
|
|
import com.sk89q.worldguard.bukkit.listener.debounce.EventDebounce;
|
|
|
|
import com.sk89q.worldguard.bukkit.listener.debounce.legacy.AbstractEventDebounce.Entry;
|
|
|
|
import com.sk89q.worldguard.bukkit.listener.debounce.legacy.BlockEntityEventDebounce;
|
|
|
|
import com.sk89q.worldguard.bukkit.listener.debounce.legacy.EntityEntityEventDebounce;
|
|
|
|
import com.sk89q.worldguard.bukkit.listener.debounce.legacy.InventoryMoveItemEventDebounce;
|
2014-08-12 05:08:38 +02:00
|
|
|
import com.sk89q.worldguard.bukkit.util.Blocks;
|
|
|
|
import com.sk89q.worldguard.bukkit.util.Events;
|
|
|
|
import com.sk89q.worldguard.bukkit.util.Materials;
|
2015-01-07 00:00:13 +01:00
|
|
|
import com.sk89q.worldguard.protection.flags.DefaultFlag;
|
2015-01-05 03:20:33 +01:00
|
|
|
import org.bukkit.*;
|
2015-01-05 04:43:55 +01:00
|
|
|
import org.bukkit.block.*;
|
2015-01-05 03:20:33 +01:00
|
|
|
import org.bukkit.entity.*;
|
2014-08-12 05:08:38 +02:00
|
|
|
import org.bukkit.event.Cancellable;
|
|
|
|
import org.bukkit.event.Event;
|
2014-08-12 02:40:04 +02:00
|
|
|
import org.bukkit.event.Event.Result;
|
|
|
|
import org.bukkit.event.EventHandler;
|
2015-01-05 04:43:55 +01:00
|
|
|
import org.bukkit.event.block.*;
|
|
|
|
import org.bukkit.event.entity.*;
|
2014-08-12 02:40:04 +02:00
|
|
|
import org.bukkit.event.hanging.HangingBreakByEntityEvent;
|
|
|
|
import org.bukkit.event.hanging.HangingBreakEvent;
|
|
|
|
import org.bukkit.event.hanging.HangingPlaceEvent;
|
2014-08-25 00:24:52 +02:00
|
|
|
import org.bukkit.event.inventory.InventoryMoveItemEvent;
|
2015-01-11 09:05:07 +01:00
|
|
|
import org.bukkit.event.inventory.InventoryOpenEvent;
|
2015-01-05 04:43:55 +01:00
|
|
|
import org.bukkit.event.player.*;
|
2014-08-12 02:40:04 +02:00
|
|
|
import org.bukkit.event.vehicle.VehicleDamageEvent;
|
|
|
|
import org.bukkit.event.vehicle.VehicleDestroyEvent;
|
2014-08-17 22:16:45 +02:00
|
|
|
import org.bukkit.event.world.StructureGrowEvent;
|
2014-08-25 00:24:52 +02:00
|
|
|
import org.bukkit.inventory.InventoryHolder;
|
2014-08-12 02:40:04 +02:00
|
|
|
import org.bukkit.inventory.ItemStack;
|
2014-08-12 05:08:38 +02:00
|
|
|
import org.bukkit.material.Dispenser;
|
|
|
|
import org.bukkit.material.MaterialData;
|
2014-08-25 01:26:15 +02:00
|
|
|
import org.bukkit.material.SpawnEgg;
|
2015-01-05 03:20:33 +01:00
|
|
|
import org.bukkit.projectiles.ProjectileSource;
|
2014-08-17 22:16:45 +02:00
|
|
|
import org.bukkit.util.Vector;
|
2014-08-12 02:40:04 +02:00
|
|
|
|
|
|
|
import javax.annotation.Nullable;
|
2014-08-19 06:37:41 +02:00
|
|
|
import java.util.ArrayList;
|
2014-08-17 22:16:45 +02:00
|
|
|
import java.util.List;
|
2014-08-12 02:40:04 +02:00
|
|
|
|
2014-08-13 04:48:20 +02:00
|
|
|
import static com.sk89q.worldguard.bukkit.cause.Cause.create;
|
2014-08-12 02:40:04 +02:00
|
|
|
|
2014-08-22 22:37:02 +02:00
|
|
|
public class EventAbstractionListener extends AbstractListener {
|
2014-08-12 02:40:04 +02:00
|
|
|
|
2014-08-23 02:21:49 +02:00
|
|
|
private final BlockEntityEventDebounce interactDebounce = new BlockEntityEventDebounce(10000);
|
2014-08-23 02:30:18 +02:00
|
|
|
private final EntityEntityEventDebounce pickupDebounce = new EntityEntityEventDebounce(10000);
|
2014-08-24 21:36:17 +02:00
|
|
|
private final BlockEntityEventDebounce entityBreakBlockDebounce = new BlockEntityEventDebounce(10000);
|
2014-08-25 00:24:52 +02:00
|
|
|
private final InventoryMoveItemEventDebounce moveItemDebounce = new InventoryMoveItemEventDebounce(30000);
|
2014-09-01 02:39:01 +02:00
|
|
|
private final EventDebounce<BlockPistonRetractKey> pistonRetractDebounce = EventDebounce.create(5000);
|
|
|
|
private final EventDebounce<BlockPistonExtendKey> pistonExtendDebounce = EventDebounce.create(5000);
|
2014-08-23 02:21:49 +02:00
|
|
|
|
2014-08-22 22:37:02 +02:00
|
|
|
/**
|
|
|
|
* Construct the listener.
|
|
|
|
*
|
|
|
|
* @param plugin an instance of WorldGuardPlugin
|
|
|
|
*/
|
2014-08-12 02:51:00 +02:00
|
|
|
public EventAbstractionListener(WorldGuardPlugin plugin) {
|
2014-08-22 22:37:02 +02:00
|
|
|
super(plugin);
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
// Block break / place
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onBlockBreak(BlockBreakEvent event) {
|
|
|
|
Events.fireToCancel(event, new BreakBlockEvent(event, create(event.getPlayer()), event.getBlock()));
|
2014-08-25 09:28:26 +02:00
|
|
|
|
|
|
|
if (event.isCancelled()) {
|
2014-09-01 04:00:45 +02:00
|
|
|
playDenyEffect(event.getPlayer(), event.getBlock().getLocation().add(0.5, 1, 0.5));
|
2014-08-25 09:28:26 +02:00
|
|
|
}
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onBlockPlace(BlockPlaceEvent event) {
|
2014-08-12 05:08:38 +02:00
|
|
|
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()));
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
if (!event.isCancelled()) {
|
|
|
|
ItemStack itemStack = new ItemStack(event.getBlockPlaced().getType(), 1);
|
|
|
|
Events.fireToCancel(event, new UseItemEvent(event, create(event.getPlayer()), event.getPlayer().getWorld(), itemStack));
|
|
|
|
}
|
2014-08-24 22:45:39 +02:00
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
if (!event.isCancelled()) {
|
|
|
|
Events.fireToCancel(event, new PlaceBlockEvent(event, create(event.getPlayer()), event.getBlock()));
|
|
|
|
}
|
2014-08-25 09:28:26 +02:00
|
|
|
|
|
|
|
if (event.isCancelled()) {
|
|
|
|
playDenyEffect(event.getPlayer(), event.getBlockPlaced().getLocation().add(0.5, 0.5, 0.5));
|
|
|
|
}
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onBlockBurn(BlockBurnEvent event) {
|
2014-08-24 21:25:29 +02:00
|
|
|
Block target = event.getBlock();
|
|
|
|
|
|
|
|
Block[] adjacent = new Block[] {
|
|
|
|
target.getRelative(BlockFace.NORTH),
|
|
|
|
target.getRelative(BlockFace.SOUTH),
|
|
|
|
target.getRelative(BlockFace.WEST),
|
|
|
|
target.getRelative(BlockFace.EAST),
|
|
|
|
target.getRelative(BlockFace.UP),
|
|
|
|
target.getRelative(BlockFace.DOWN)};
|
|
|
|
|
|
|
|
int found = 0;
|
|
|
|
boolean allowed = false;
|
|
|
|
|
|
|
|
for (Block source : adjacent) {
|
|
|
|
if (source.getType() == Material.FIRE) {
|
|
|
|
found++;
|
|
|
|
if (Events.fireAndTestCancel(new BreakBlockEvent(event, create(source), target))) {
|
|
|
|
source.setType(Material.AIR);
|
|
|
|
} else {
|
|
|
|
allowed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found > 0 && !allowed) {
|
|
|
|
event.setCancelled(true);
|
|
|
|
}
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-17 22:16:45 +02:00
|
|
|
public void onStructureGrowEvent(StructureGrowEvent event) {
|
2014-09-01 03:08:13 +02:00
|
|
|
int originalCount = event.getBlocks().size();
|
2014-08-17 22:16:45 +02:00
|
|
|
List<Block> blockList = Lists.transform(event.getBlocks(), new BlockStateAsBlockFunction());
|
2014-09-01 02:52:03 +02:00
|
|
|
|
|
|
|
Player player = event.getPlayer();
|
|
|
|
if (player != null) {
|
|
|
|
Events.fireBulkEventToCancel(event, new PlaceBlockEvent(event, create(player), event.getLocation().getWorld(), blockList, Material.AIR));
|
|
|
|
} else {
|
|
|
|
Events.fireBulkEventToCancel(event, new PlaceBlockEvent(event, create(event.getLocation().getBlock()), event.getLocation().getWorld(), blockList, Material.AIR));
|
|
|
|
}
|
2014-09-01 03:08:13 +02:00
|
|
|
|
|
|
|
if (!event.isCancelled() && event.getBlocks().size() != originalCount) {
|
|
|
|
event.getLocation().getBlock().setType(Material.AIR);
|
|
|
|
}
|
2014-08-17 22:16:45 +02:00
|
|
|
}
|
|
|
|
|
2014-08-12 02:40:04 +02:00
|
|
|
// TODO: Handle EntityCreatePortalEvent?
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onEntityChangeBlock(EntityChangeBlockEvent event) {
|
2014-08-12 05:08:38 +02:00
|
|
|
Block block = event.getBlock();
|
|
|
|
Entity entity = event.getEntity();
|
|
|
|
Material to = event.getTo();
|
|
|
|
|
2014-08-25 02:56:15 +02:00
|
|
|
// Forget about Redstone ore, especially since we handle it in INTERACT
|
|
|
|
if (Materials.isRedstoneOre(block.getType()) && Materials.isRedstoneOre(to)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-12 02:40:04 +02:00
|
|
|
// Fire two events: one as BREAK and one as PLACE
|
|
|
|
if (event.getTo() != Material.AIR && event.getBlock().getType() != Material.AIR) {
|
2014-08-12 05:08:38 +02:00
|
|
|
Events.fireToCancel(event, new BreakBlockEvent(event, create(entity), block));
|
|
|
|
Events.fireToCancel(event, new PlaceBlockEvent(event, create(entity), block.getLocation(), to));
|
2014-08-12 02:40:04 +02:00
|
|
|
} else {
|
|
|
|
if (event.getTo() == Material.AIR) {
|
2014-08-12 05:08:38 +02:00
|
|
|
// Track the source so later we can create a proper chain of causes
|
|
|
|
if (entity instanceof FallingBlock) {
|
2014-08-15 10:43:37 +02:00
|
|
|
Cause.trackParentCause(entity, block);
|
2014-08-12 05:08:38 +02:00
|
|
|
|
|
|
|
// Switch around the event
|
|
|
|
Events.fireToCancel(event, new SpawnEntityEvent(event, create(block), entity));
|
|
|
|
} else {
|
2014-08-24 21:36:17 +02:00
|
|
|
entityBreakBlockDebounce.debounce(
|
|
|
|
event.getBlock(), event.getEntity(), event, new BreakBlockEvent(event, create(entity), event.getBlock()));
|
2014-08-12 05:08:38 +02:00
|
|
|
}
|
2014-08-12 02:40:04 +02:00
|
|
|
} else {
|
2014-08-17 22:16:45 +02:00
|
|
|
boolean wasCancelled = event.isCancelled();
|
2014-08-15 10:43:37 +02:00
|
|
|
Cause cause = create(entity);
|
2014-08-12 05:08:38 +02:00
|
|
|
|
2014-08-13 04:48:20 +02:00
|
|
|
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, event.getBlock().getLocation(), to));
|
2014-08-17 22:16:45 +02:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-15 10:43:37 +02:00
|
|
|
public void onEntityExplode(EntityExplodeEvent event) {
|
|
|
|
Entity entity = event.getEntity();
|
|
|
|
|
|
|
|
Events.fireBulkEventToCancel(event, new BreakBlockEvent(event, create(entity), event.getLocation().getWorld(), event.blockList(), Material.AIR));
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-19 06:37:41 +02:00
|
|
|
public void onBlockPistonRetract(BlockPistonRetractEvent event) {
|
|
|
|
if (event.isSticky()) {
|
2014-09-01 02:39:01 +02:00
|
|
|
EventDebounce.Entry entry = pistonRetractDebounce.getIfNotPresent(new BlockPistonRetractKey(event), event);
|
|
|
|
if (entry != null) {
|
|
|
|
Cause cause = create(event.getBlock());
|
|
|
|
Events.fireToCancel(event, new BreakBlockEvent(event, cause, event.getRetractLocation(), Material.AIR));
|
|
|
|
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, event.getBlock().getRelative(event.getDirection())));
|
|
|
|
entry.setCancelled(event.isCancelled());
|
|
|
|
|
|
|
|
if (event.isCancelled()) {
|
|
|
|
playDenyEffect(event.getBlock().getLocation().add(0.5, 1, 0.5));
|
|
|
|
}
|
|
|
|
}
|
2014-08-19 06:37:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-19 06:37:41 +02:00
|
|
|
public void onBlockPistonExtend(BlockPistonExtendEvent event) {
|
2014-09-01 02:39:01 +02:00
|
|
|
EventDebounce.Entry entry = pistonExtendDebounce.getIfNotPresent(new BlockPistonExtendKey(event), event);
|
|
|
|
if (entry != null) {
|
|
|
|
// A hack for now
|
|
|
|
List<Block> blocks = new ArrayList<Block>(event.getBlocks());
|
|
|
|
Block lastBlock = event.getBlock().getRelative(event.getDirection(), event.getLength() + 1);
|
|
|
|
blocks.add(lastBlock);
|
|
|
|
int originalLength = blocks.size();
|
|
|
|
Events.fireBulkEventToCancel(event, new PlaceBlockEvent(event, create(event.getBlock()), event.getBlock().getWorld(), blocks, Material.STONE));
|
|
|
|
if (blocks.size() != originalLength) {
|
|
|
|
event.setCancelled(true);
|
|
|
|
}
|
|
|
|
entry.setCancelled(event.isCancelled());
|
|
|
|
|
|
|
|
if (event.isCancelled()) {
|
|
|
|
playDenyEffect(event.getBlock().getLocation().add(0.5, 1, 0.5));
|
|
|
|
}
|
2014-08-19 06:37:41 +02:00
|
|
|
}
|
|
|
|
}
|
2014-08-12 02:40:04 +02:00
|
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
// Block external interaction
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onPlayerInteract(PlayerInteractEvent event) {
|
|
|
|
Player player = event.getPlayer();
|
|
|
|
@Nullable ItemStack item = player.getItemInHand();
|
2014-08-12 05:08:38 +02:00
|
|
|
Block clicked = event.getClickedBlock();
|
|
|
|
Block placed;
|
2014-08-25 02:56:15 +02:00
|
|
|
boolean silent = false;
|
2014-08-13 04:48:20 +02:00
|
|
|
Cause cause = create(player);
|
2014-08-12 02:40:04 +02:00
|
|
|
|
|
|
|
switch (event.getAction()) {
|
|
|
|
case PHYSICAL:
|
2014-08-25 02:56:15 +02:00
|
|
|
// Forget about Redstone ore
|
2014-08-25 09:05:44 +02:00
|
|
|
if (Materials.isRedstoneOre(clicked.getType()) || clicked.getType() == Material.SOIL) {
|
2014-08-25 02:56:15 +02:00
|
|
|
silent = true;
|
|
|
|
}
|
|
|
|
|
2015-01-05 03:05:50 +01:00
|
|
|
if (!hasInteractBypass(clicked)) {
|
|
|
|
interactDebounce.debounce(clicked, event.getPlayer(), event, DelegateEvents.setSilent(new UseBlockEvent(event, cause, clicked), silent));
|
|
|
|
}
|
2014-08-12 02:40:04 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RIGHT_CLICK_BLOCK:
|
2014-08-12 05:08:38 +02:00
|
|
|
placed = clicked.getRelative(event.getBlockFace());
|
2014-08-12 02:40:04 +02:00
|
|
|
|
2014-08-12 05:08:38 +02:00
|
|
|
// Re-used for dispensers
|
|
|
|
handleBlockRightClick(event, create(event.getPlayer()), item, clicked, event.getBlockFace(), placed);
|
2014-08-12 02:40:04 +02:00
|
|
|
|
|
|
|
case LEFT_CLICK_BLOCK:
|
2014-08-12 05:08:38 +02:00
|
|
|
placed = clicked.getRelative(event.getBlockFace());
|
2014-08-12 02:40:04 +02:00
|
|
|
|
2014-08-25 09:29:37 +02:00
|
|
|
// Only fire events for blocks that are modified when right clicked
|
2014-09-01 04:17:05 +02:00
|
|
|
if (isBlockModifiedOnClick(clicked) || (item != null && isItemAppliedToBlock(item, clicked))) {
|
2014-08-25 09:29:37 +02:00
|
|
|
if (Events.fireAndTestCancel(new UseBlockEvent(event, cause, clicked))) {
|
|
|
|
event.setUseInteractedBlock(Result.DENY);
|
|
|
|
}
|
2014-08-12 02:40:04 +02:00
|
|
|
|
2014-08-25 09:29:37 +02:00
|
|
|
// 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;
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Special handling of putting out fires
|
2014-08-12 05:08:38 +02:00
|
|
|
if (event.getAction() == Action.LEFT_CLICK_BLOCK && placed.getType() == Material.FIRE) {
|
|
|
|
if (Events.fireAndTestCancel(new BreakBlockEvent(event, create(event.getPlayer()), placed))) {
|
2014-08-12 02:40:04 +02:00
|
|
|
event.setUseInteractedBlock(Result.DENY);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-25 09:28:26 +02:00
|
|
|
if (event.isCancelled()) {
|
|
|
|
playDenyEffect(event.getPlayer(), clicked.getLocation().add(0.5, 1, 0.5));
|
|
|
|
}
|
|
|
|
|
2014-08-12 02:40:04 +02:00
|
|
|
case LEFT_CLICK_AIR:
|
|
|
|
case RIGHT_CLICK_AIR:
|
2014-08-13 04:48:20 +02:00
|
|
|
if (item != null && !item.getType().isBlock() && Events.fireAndTestCancel(new UseItemEvent(event, cause, player.getWorld(), item))) {
|
2014-08-12 02:40:04 +02:00
|
|
|
event.setUseItemInHand(Result.DENY);
|
2014-12-31 11:30:58 +01:00
|
|
|
event.setCancelled(true); // The line above does not appear to work with spawn eggs
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
|
2014-09-01 04:30:14 +02:00
|
|
|
// Check for items that the administrator has configured to
|
|
|
|
// emit a "use block here" event where the player is
|
|
|
|
// standing, which is a hack to protect items that don't
|
|
|
|
// throw events
|
|
|
|
if (item != null && getWorldConfig(player.getWorld()).blockUseAtFeet.test(item)) {
|
|
|
|
if (Events.fireAndTestCancel(new UseBlockEvent(event, cause, player.getLocation().getBlock()))) {
|
|
|
|
event.setCancelled(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-12 02:40:04 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onEntityInteract(org.bukkit.event.entity.EntityInteractEvent event) {
|
2015-01-05 03:05:50 +01:00
|
|
|
if (!hasInteractBypass(event.getBlock())) {
|
|
|
|
interactDebounce.debounce(event.getBlock(), event.getEntity(), event, new UseBlockEvent(event, create(event.getEntity()), event.getBlock()));
|
|
|
|
}
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onBlockIgnite(BlockIgniteEvent event) {
|
2014-08-12 05:08:38 +02:00
|
|
|
Block block = event.getBlock();
|
2014-08-24 21:25:29 +02:00
|
|
|
Material type = block.getType();
|
2014-08-13 04:48:20 +02:00
|
|
|
Cause cause;
|
2014-08-12 02:40:04 +02:00
|
|
|
|
|
|
|
// Find the cause
|
|
|
|
if (event.getPlayer() != null) {
|
2014-08-13 04:48:20 +02:00
|
|
|
cause = create(event.getPlayer());
|
2014-08-12 02:40:04 +02:00
|
|
|
} else if (event.getIgnitingEntity() != null) {
|
2014-08-13 04:48:20 +02:00
|
|
|
cause = create(event.getIgnitingEntity());
|
2014-08-12 02:40:04 +02:00
|
|
|
} else if (event.getIgnitingBlock() != null) {
|
2014-08-13 04:48:20 +02:00
|
|
|
cause = create(event.getIgnitingBlock());
|
2014-08-12 02:40:04 +02:00
|
|
|
} else {
|
2014-08-13 04:48:20 +02:00
|
|
|
cause = Cause.unknown();
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
|
2014-08-24 21:25:29 +02:00
|
|
|
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, block.getLocation(), Material.FIRE));
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onSignChange(SignChangeEvent event) {
|
|
|
|
Events.fireToCancel(event, new UseBlockEvent(event, create(event.getPlayer()), event.getBlock()));
|
2014-09-01 04:00:45 +02:00
|
|
|
|
|
|
|
if (event.isCancelled()) {
|
|
|
|
playDenyEffect(event.getPlayer(), event.getBlock().getLocation().add(0.5, 0.5, 0.5));
|
|
|
|
}
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onBedEnter(PlayerBedEnterEvent event) {
|
|
|
|
Events.fireToCancel(event, new UseBlockEvent(event, create(event.getPlayer()), event.getBed()));
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
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);
|
2014-08-12 05:08:38 +02:00
|
|
|
Material blockMaterial = Materials.getBucketBlockMaterial(event.getBucket());
|
|
|
|
Events.fireToCancel(event, new PlaceBlockEvent(event, create(player), blockAffected.getLocation(), blockMaterial));
|
2014-08-12 02:40:04 +02:00
|
|
|
Events.fireToCancel(event, new UseItemEvent(event, create(player), player.getWorld(), item));
|
|
|
|
}
|
2014-08-25 09:28:26 +02:00
|
|
|
|
|
|
|
playDenyEffect(event.getPlayer(), blockAffected.getLocation().add(0.5, 0.5, 0.5));
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
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));
|
|
|
|
}
|
2014-08-25 09:28:26 +02:00
|
|
|
|
|
|
|
playDenyEffect(event.getPlayer(), blockAffected.getLocation().add(0.5, 1, 0.5));
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Handle EntityPortalEnterEvent
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
// Block self-interaction
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onBlockFromTo(BlockFromToEvent event) {
|
2014-08-22 22:37:02 +02:00
|
|
|
WorldConfiguration config = getWorldConfig(event.getBlock().getWorld());
|
|
|
|
|
|
|
|
// This only applies to regions but nothing else cares about high
|
|
|
|
// frequency events at the moment
|
|
|
|
if (!config.useRegions || (!config.highFreqFlags && !config.checkLiquidFlow)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-17 22:16:45 +02:00
|
|
|
Block from = event.getBlock();
|
|
|
|
Block to = event.getToBlock();
|
2014-08-18 19:40:09 +02:00
|
|
|
Material fromType = from.getType();
|
|
|
|
Material toType = to.getType();
|
2014-08-12 05:08:38 +02:00
|
|
|
|
2014-08-17 22:16:45 +02:00
|
|
|
// Liquids pass this event when flowing to solid blocks
|
2014-08-18 19:40:09 +02:00
|
|
|
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))) {
|
2014-08-17 22:16:45 +02:00
|
|
|
return;
|
|
|
|
}
|
2014-08-12 05:08:38 +02:00
|
|
|
|
2014-08-17 22:16:45 +02:00
|
|
|
Cause cause = create(from);
|
2014-08-12 05:08:38 +02:00
|
|
|
|
2014-08-18 19:40:09 +02:00
|
|
|
// Disable since it's probably not needed
|
|
|
|
/*if (from.getType() != Material.AIR) {
|
2014-08-17 22:16:45 +02:00
|
|
|
Events.fireToCancel(event, new BreakBlockEvent(event, cause, to));
|
2014-08-18 19:40:09 +02:00
|
|
|
}*/
|
2014-08-17 22:16:45 +02:00
|
|
|
|
|
|
|
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, to.getLocation(), from.getType()));
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
// Entity break / place
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 05:08:38 +02:00
|
|
|
public void onCreatureSpawn(CreatureSpawnEvent event) {
|
2014-08-25 00:53:45 +02:00
|
|
|
switch (event.getSpawnReason()) {
|
|
|
|
case DISPENSE_EGG:
|
|
|
|
case EGG:
|
|
|
|
case SPAWNER_EGG:
|
|
|
|
if (getWorldConfig(event.getEntity().getWorld()).strictEntitySpawn) {
|
|
|
|
Events.fireToCancel(event, new SpawnEntityEvent(event, Cause.unknown(), event.getEntity()));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NATURAL:
|
|
|
|
case JOCKEY:
|
|
|
|
case CHUNK_GEN:
|
|
|
|
case SPAWNER:
|
|
|
|
case LIGHTNING:
|
|
|
|
case BUILD_SNOWMAN:
|
|
|
|
case BUILD_IRONGOLEM:
|
|
|
|
case BUILD_WITHER:
|
|
|
|
case VILLAGE_DEFENSE:
|
|
|
|
case VILLAGE_INVASION:
|
|
|
|
case BREEDING:
|
|
|
|
case SLIME_SPLIT:
|
|
|
|
case REINFORCEMENTS:
|
|
|
|
case NETHER_PORTAL:
|
|
|
|
case INFECTION:
|
|
|
|
case CURED:
|
|
|
|
case OCELOT_BABY:
|
|
|
|
case SILVERFISH_BLOCK:
|
|
|
|
case MOUNT:
|
|
|
|
case CUSTOM:
|
|
|
|
case DEFAULT:
|
|
|
|
}
|
2014-08-12 05:08:38 +02:00
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onHangingPlace(HangingPlaceEvent event) {
|
|
|
|
Events.fireToCancel(event, new SpawnEntityEvent(event, create(event.getPlayer()), event.getEntity()));
|
2014-09-01 04:00:45 +02:00
|
|
|
|
|
|
|
if (event.isCancelled()) {
|
|
|
|
Block effectBlock = event.getBlock().getRelative(event.getBlockFace());
|
|
|
|
playDenyEffect(event.getPlayer(), effectBlock.getLocation().add(0.5, 0.5, 0.5));
|
|
|
|
}
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onHangingBreak(HangingBreakEvent event) {
|
|
|
|
if (event instanceof HangingBreakByEntityEvent) {
|
2014-09-01 04:00:45 +02:00
|
|
|
Entity remover = ((HangingBreakByEntityEvent) event).getRemover();
|
|
|
|
Events.fireToCancel(event, new DestroyEntityEvent(event, create(remover), event.getEntity()));
|
|
|
|
|
|
|
|
if (event.isCancelled() && remover instanceof Player) {
|
|
|
|
playDenyEffect((Player) remover, event.getEntity().getLocation());
|
|
|
|
}
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onVehicleDestroy(VehicleDestroyEvent event) {
|
|
|
|
Events.fireToCancel(event, new DestroyEntityEvent(event, create(event.getAttacker()), event.getVehicle()));
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-19 03:56:07 +02:00
|
|
|
public void onBlockExp(BlockExpEvent event) {
|
2014-08-19 08:33:45 +02:00
|
|
|
if (event.getExpToDrop() > 0) { // Event is raised even where no XP is being dropped
|
|
|
|
if (Events.fireAndTestCancel(new SpawnEntityEvent(event, create(event.getBlock()), event.getBlock().getLocation(), EntityType.EXPERIENCE_ORB))) {
|
|
|
|
event.setExpToDrop(0);
|
|
|
|
}
|
2014-08-19 03:56:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-19 08:56:39 +02:00
|
|
|
public void onPlayerFish(PlayerFishEvent event) {
|
2014-08-25 23:18:26 +02:00
|
|
|
if (Events.fireAndTestCancel(new SpawnEntityEvent(event, create(event.getPlayer(), event.getHook()), event.getHook().getLocation(), EntityType.EXPERIENCE_ORB))) {
|
2014-08-19 08:56:39 +02:00
|
|
|
event.setExpToDrop(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-19 08:56:39 +02:00
|
|
|
public void onExpBottle(ExpBottleEvent event) {
|
|
|
|
if (Events.fireAndTestCancel(new SpawnEntityEvent(event, create(event.getEntity()), event.getEntity().getLocation(), EntityType.EXPERIENCE_ORB))) {
|
|
|
|
event.setExperience(0);
|
2015-01-05 03:20:33 +01:00
|
|
|
|
|
|
|
// Give the player back his or her XP bottle
|
|
|
|
ProjectileSource shooter = event.getEntity().getShooter();
|
|
|
|
if (shooter instanceof Player) {
|
|
|
|
Player player = (Player) shooter;
|
|
|
|
if (player.getGameMode() != GameMode.CREATIVE) {
|
|
|
|
player.getInventory().addItem(new ItemStack(Material.EXP_BOTTLE, 1));
|
|
|
|
}
|
|
|
|
}
|
2014-08-19 08:56:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-19 08:56:39 +02:00
|
|
|
public void onEntityDeath(EntityDeathEvent event) {
|
|
|
|
if (event.getDroppedExp() > 0) {
|
|
|
|
if (Events.fireAndTestCancel(new SpawnEntityEvent(event, create(event.getEntity()), event.getEntity().getLocation(), EntityType.EXPERIENCE_ORB))) {
|
|
|
|
event.setDroppedExp(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-08-12 05:08:38 +02:00
|
|
|
|
2014-08-12 02:40:04 +02:00
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
// Entity external interaction
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onEntityDamage(EntityDamageEvent event) {
|
|
|
|
if (event instanceof EntityDamageByBlockEvent) {
|
2014-08-22 21:47:06 +02:00
|
|
|
Events.fireToCancel(event, new DamageEntityEvent(event, create(((EntityDamageByBlockEvent) event).getDamager()), event.getEntity()));
|
2014-08-12 02:40:04 +02:00
|
|
|
|
|
|
|
} else if (event instanceof EntityDamageByEntityEvent) {
|
|
|
|
EntityDamageByEntityEvent entityEvent = (EntityDamageByEntityEvent) event;
|
|
|
|
Entity damager = entityEvent.getDamager();
|
2014-08-22 21:47:06 +02:00
|
|
|
Events.fireToCancel(event, new DamageEntityEvent(event, create(damager), event.getEntity()));
|
2014-08-12 02:40:04 +02:00
|
|
|
|
|
|
|
// 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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onEntityCombust(EntityCombustEvent event) {
|
|
|
|
if (event instanceof EntityCombustByBlockEvent) {
|
2014-08-22 21:47:06 +02:00
|
|
|
Events.fireToCancel(event, new DamageEntityEvent(event, create(((EntityCombustByBlockEvent) event).getCombuster()), event.getEntity()));
|
2014-08-12 02:40:04 +02:00
|
|
|
|
|
|
|
} else if (event instanceof EntityCombustByEntityEvent) {
|
2014-08-22 21:47:06 +02:00
|
|
|
Events.fireToCancel(event, new DamageEntityEvent(event, create(((EntityCombustByEntityEvent) event).getCombuster()), event.getEntity()));
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
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?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onEntityTame(EntityTameEvent event) {
|
|
|
|
Events.fireToCancel(event, new UseEntityEvent(event, create(event.getOwner()), event.getEntity()));
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onPlayerShearEntity(PlayerShearEntityEvent event) {
|
|
|
|
Events.fireToCancel(event, new UseEntityEvent(event, create(event.getPlayer()), event.getEntity()));
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onPlayerPickupItem(PlayerPickupItemEvent event) {
|
2014-08-22 22:54:59 +02:00
|
|
|
Item item = event.getItem();
|
2014-08-23 02:30:18 +02:00
|
|
|
pickupDebounce.debounce(event.getPlayer(), item, event, new DestroyEntityEvent(event, create(event.getPlayer()), event.getItem()));
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onPlayerDropItem(PlayerDropItemEvent event) {
|
|
|
|
Events.fireToCancel(event, new SpawnEntityEvent(event, create(event.getPlayer()), event.getItemDrop()));
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onVehicleDamage(VehicleDamageEvent event) {
|
2014-09-01 04:00:45 +02:00
|
|
|
Entity attacker = event.getAttacker();
|
|
|
|
Events.fireToCancel(event, new DestroyEntityEvent(event, create(attacker), event.getVehicle()));
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onVehicleEnter(VehicleDamageEvent event) {
|
|
|
|
Events.fireToCancel(event, new UseEntityEvent(event, create(event.getAttacker()), event.getVehicle()));
|
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
// Composite events
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
2015-01-05 04:43:55 +01:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
public void onPlayerItemConsume(PlayerItemConsumeEvent event) {
|
|
|
|
Events.fireToCancel(event, new UseItemEvent(event, create(event.getPlayer()), event.getPlayer().getWorld(), event.getItem()));
|
|
|
|
}
|
|
|
|
|
2015-01-11 09:05:07 +01:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
public void onInventoryOpen(InventoryOpenEvent event) {
|
|
|
|
InventoryHolder holder = event.getInventory().getHolder();
|
|
|
|
if (holder instanceof BlockState) {
|
|
|
|
Events.fireToCancel(event, new UseBlockEvent(event, create(event.getPlayer()), ((BlockState) holder).getBlock()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-25 00:24:52 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
public void onInventoryMoveItem(InventoryMoveItemEvent event) {
|
2014-08-25 02:06:13 +02:00
|
|
|
final InventoryHolder causeHolder = event.getInitiator().getHolder();
|
2014-08-25 00:24:52 +02:00
|
|
|
InventoryHolder sourceHolder = event.getSource().getHolder();
|
|
|
|
InventoryHolder targetHolder = event.getDestination().getHolder();
|
|
|
|
|
|
|
|
Entry entry;
|
|
|
|
|
|
|
|
if ((entry = moveItemDebounce.tryDebounce(event)) != null) {
|
|
|
|
Cause cause;
|
|
|
|
|
|
|
|
if (causeHolder instanceof Entity) {
|
|
|
|
cause = create(causeHolder);
|
|
|
|
} else if (causeHolder instanceof BlockState) {
|
|
|
|
cause = create(((BlockState) causeHolder).getBlock());
|
|
|
|
} else {
|
|
|
|
cause = Cause.unknown();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!causeHolder.equals(sourceHolder)) {
|
|
|
|
handleInventoryHolderUse(event, cause, sourceHolder);
|
|
|
|
}
|
|
|
|
|
|
|
|
handleInventoryHolderUse(event, cause, targetHolder);
|
|
|
|
|
2014-08-25 00:40:00 +02:00
|
|
|
if (event.isCancelled() && causeHolder instanceof Hopper) {
|
2014-08-25 02:06:13 +02:00
|
|
|
Bukkit.getScheduler().scheduleSyncDelayedTask(getPlugin(), new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
((Hopper) causeHolder).getBlock().breakNaturally();
|
|
|
|
}
|
|
|
|
});
|
2014-08-25 00:40:00 +02:00
|
|
|
} else {
|
|
|
|
entry.setCancelled(event.isCancelled());
|
|
|
|
}
|
2014-08-25 00:24:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onPotionSplash(PotionSplashEvent event) {
|
|
|
|
Entity entity = event.getEntity();
|
|
|
|
ThrownPotion potion = event.getPotion();
|
|
|
|
World world = entity.getWorld();
|
2015-01-07 00:00:13 +01:00
|
|
|
Cause cause = create(potion);
|
2014-08-12 02:40:04 +02:00
|
|
|
|
|
|
|
// Fire item interaction event
|
2014-08-13 04:48:20 +02:00
|
|
|
Events.fireToCancel(event, new UseItemEvent(event, cause, world, potion.getItem()));
|
2014-08-12 02:40:04 +02:00
|
|
|
|
|
|
|
// Fire entity interaction event
|
|
|
|
if (!event.isCancelled()) {
|
|
|
|
int blocked = 0;
|
2015-01-05 04:54:34 +01:00
|
|
|
boolean hasDamageEffect = Materials.hasDamageEffect(potion.getEffects());
|
2014-08-12 02:40:04 +02:00
|
|
|
|
|
|
|
for (LivingEntity affected : event.getAffectedEntities()) {
|
2015-01-05 04:54:34 +01:00
|
|
|
DelegateEvent delegate = hasDamageEffect
|
|
|
|
? new DamageEntityEvent(event, cause, affected) :
|
|
|
|
new UseEntityEvent(event, cause, affected);
|
|
|
|
|
2015-01-07 00:00:13 +01:00
|
|
|
// Consider the potion splash flag
|
|
|
|
delegate.getRelevantFlags().add(DefaultFlag.POTION_SPLASH);
|
|
|
|
|
2015-01-05 04:54:34 +01:00
|
|
|
if (Events.fireAndTestCancel(delegate)) {
|
2014-08-12 02:40:04 +02:00
|
|
|
event.setIntensity(affected, 0);
|
|
|
|
blocked++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (blocked == event.getAffectedEntities().size()) {
|
|
|
|
event.setCancelled(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-24 23:39:44 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2014-08-12 02:40:04 +02:00
|
|
|
public void onBlockDispense(BlockDispenseEvent event) {
|
2014-08-13 04:48:20 +02:00
|
|
|
Cause cause = create(event.getBlock());
|
2014-08-12 05:08:38 +02:00
|
|
|
Block dispenserBlock = event.getBlock();
|
|
|
|
ItemStack item = event.getItem();
|
|
|
|
MaterialData materialData = dispenserBlock.getState().getData();
|
|
|
|
|
2014-08-13 04:48:20 +02:00
|
|
|
Events.fireToCancel(event, new UseItemEvent(event, cause, dispenserBlock.getWorld(), item));
|
2014-08-12 05:08:38 +02:00
|
|
|
|
|
|
|
// 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());
|
2014-08-13 04:48:20 +02:00
|
|
|
handleBlockRightClick(event, cause, item, clicked, dispenser.getFacing().getOppositeFace(), placed);
|
2014-08-12 05:08:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle the right click of a block while an item is held.
|
|
|
|
*
|
|
|
|
* @param event the original event
|
2014-08-13 04:48:20 +02:00
|
|
|
* @param cause the list of cause
|
2014-08-12 05:08:38 +02:00
|
|
|
* @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
|
|
|
|
*/
|
2014-08-13 04:48:20 +02:00
|
|
|
private static <T extends Event & Cancellable> void handleBlockRightClick(T event, Cause cause, @Nullable ItemStack item, Block clicked, BlockFace faceClicked, Block placed) {
|
2014-08-12 05:08:38 +02:00
|
|
|
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)
|
2014-08-13 04:48:20 +02:00
|
|
|
Events.fireToCancel(event, new UseBlockEvent(event, cause, clicked.getLocation(), Material.TNT));
|
2014-08-12 05:08:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Handle created Minecarts
|
|
|
|
if (item != null && Materials.isMinecart(item.getType())) {
|
|
|
|
// TODO: Give a more specific Minecart type
|
2014-08-13 04:48:20 +02:00
|
|
|
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), EntityType.MINECART));
|
2014-08-12 05:08:38 +02:00
|
|
|
}
|
|
|
|
|
2014-09-01 04:36:39 +02:00
|
|
|
// Handle created boats
|
|
|
|
if (item != null && item.getType() == Material.BOAT) {
|
|
|
|
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), EntityType.BOAT));
|
|
|
|
}
|
|
|
|
|
2014-08-25 01:26:15 +02:00
|
|
|
// Handle created spawn eggs
|
|
|
|
if (item != null && item.getType() == Material.MONSTER_EGG) {
|
|
|
|
MaterialData data = item.getData();
|
|
|
|
if (data instanceof SpawnEgg) {
|
2014-11-11 09:02:54 +01:00
|
|
|
@Nullable EntityType type = ((SpawnEgg) data).getSpawnedType();
|
|
|
|
if (type == null) {
|
|
|
|
type = EntityType.SHEEP; // Haven't investigated why it's sometimes null
|
|
|
|
}
|
|
|
|
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), type));
|
2014-08-25 01:26:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-12 05:08:38 +02:00
|
|
|
// 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)) {
|
2014-08-13 04:48:20 +02:00
|
|
|
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, placed.getLocation(), Material.COCOA));
|
2014-08-12 05:08:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Workaround for http://leaky.bukkit.org/issues/1034
|
|
|
|
if (item != null && item.getType() == Material.TNT) {
|
2014-08-13 04:48:20 +02:00
|
|
|
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, placed.getLocation(), Material.TNT));
|
2014-08-12 05:08:38 +02:00
|
|
|
}
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|
|
|
|
|
2014-08-25 00:24:52 +02:00
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
private static <T extends Event & Cancellable> void handleInventoryHolderUse(T originalEvent, Cause cause, InventoryHolder holder) {
|
|
|
|
if (originalEvent.isCancelled()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (holder instanceof Entity) {
|
|
|
|
Events.fireToCancel(originalEvent, new UseEntityEvent(originalEvent, cause, (Entity) holder));
|
|
|
|
} else if (holder instanceof BlockState) {
|
|
|
|
Events.fireToCancel(originalEvent, new UseBlockEvent(originalEvent, cause, ((BlockState) holder).getBlock()));
|
|
|
|
} else if (holder instanceof DoubleChest) {
|
|
|
|
Events.fireToCancel(originalEvent, new UseBlockEvent(originalEvent, cause, ((BlockState) ((DoubleChest) holder).getLeftSide()).getBlock()));
|
|
|
|
Events.fireToCancel(originalEvent, new UseBlockEvent(originalEvent, cause, ((BlockState) ((DoubleChest) holder).getRightSide()).getBlock()));
|
|
|
|
}
|
|
|
|
}
|
2014-08-12 02:40:04 +02:00
|
|
|
|
2015-01-05 03:05:50 +01:00
|
|
|
private boolean hasInteractBypass(Block block) {
|
|
|
|
return getWorldConfig(block.getWorld()).allowAllInteract.test(block);
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean hasInteractBypass(World world, ItemStack item) {
|
|
|
|
return getWorldConfig(world).allowAllInteract.test(item);
|
|
|
|
}
|
|
|
|
|
2014-09-01 04:17:05 +02:00
|
|
|
private boolean isBlockModifiedOnClick(Block block) {
|
2015-01-05 03:05:50 +01:00
|
|
|
return Materials.isBlockModifiedOnClick(block.getType()) && !hasInteractBypass(block);
|
2014-09-01 04:17:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private boolean isItemAppliedToBlock(ItemStack item, Block clicked) {
|
|
|
|
return Materials.isItemAppliedToBlock(item.getType(), clicked.getType())
|
2015-01-05 03:05:50 +01:00
|
|
|
&& !hasInteractBypass(clicked)
|
|
|
|
&& !hasInteractBypass(clicked.getWorld(), item);
|
2014-09-01 04:17:05 +02:00
|
|
|
}
|
|
|
|
|
2014-08-25 09:28:26 +02:00
|
|
|
private void playDenyEffect(Player player, Location location) {
|
|
|
|
//player.playSound(location, Sound.SUCCESSFUL_HIT, 0.2f, 0.4f);
|
|
|
|
player.playEffect(location, Effect.SMOKE, BlockFace.UP);
|
|
|
|
}
|
|
|
|
|
2014-09-01 02:39:01 +02:00
|
|
|
private void playDenyEffect(Location location) {
|
|
|
|
location.getWorld().playEffect(location, Effect.SMOKE, BlockFace.UP);
|
|
|
|
}
|
|
|
|
|
2014-08-12 02:40:04 +02:00
|
|
|
}
|