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 ;
2018-07-25 07:18:41 +02:00
import static com.sk89q.worldguard.bukkit.cause.Cause.create ;
2018-07-22 05:06:01 +02:00
import com.sk89q.worldedit.bukkit.BukkitAdapter ;
import com.sk89q.worldguard.WorldGuard ;
2018-07-19 16:06:02 +02:00
import com.sk89q.worldguard.bukkit.BukkitWorldConfiguration ;
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-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 ;
2016-06-11 07:22:40 +02:00
import com.sk89q.worldguard.bukkit.util.Entities ;
2014-08-12 05:08:38 +02:00
import com.sk89q.worldguard.bukkit.util.Events ;
import com.sk89q.worldguard.bukkit.util.Materials ;
2018-12-26 06:19:23 +01:00
import com.sk89q.worldguard.config.WorldConfiguration ;
2018-07-19 16:06:02 +02:00
import com.sk89q.worldguard.protection.flags.Flags ;
2018-07-25 07:18:41 +02:00
import org.bukkit.Bukkit ;
import org.bukkit.Effect ;
import org.bukkit.GameMode ;
import org.bukkit.Location ;
import org.bukkit.Material ;
import org.bukkit.World ;
2016-02-20 18:40:16 +01:00
import org.bukkit.block.Block ;
import org.bukkit.block.BlockFace ;
import org.bukkit.block.BlockState ;
import org.bukkit.block.Chest ;
2019-04-06 20:24:01 +02:00
import org.bukkit.block.Container ;
2016-02-20 18:40:16 +01:00
import org.bukkit.block.DoubleChest ;
2019-04-06 20:24:01 +02:00
import org.bukkit.block.Dropper ;
2016-02-20 18:40:16 +01:00
import org.bukkit.block.Hopper ;
2019-03-21 02:49:45 +01:00
import org.bukkit.block.PistonMoveReaction ;
2019-06-02 18:12:57 +02:00
import org.bukkit.block.data.type.Dispenser ;
2018-07-25 07:18:41 +02:00
import org.bukkit.entity.AreaEffectCloud ;
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 ;
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 ;
2018-07-25 07:18:41 +02:00
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.BlockExpEvent ;
import org.bukkit.event.block.BlockExplodeEvent ;
import org.bukkit.event.block.BlockFromToEvent ;
import org.bukkit.event.block.BlockIgniteEvent ;
import org.bukkit.event.block.BlockMultiPlaceEvent ;
import org.bukkit.event.block.BlockPistonExtendEvent ;
import org.bukkit.event.block.BlockPistonRetractEvent ;
import org.bukkit.event.block.BlockPlaceEvent ;
import org.bukkit.event.block.EntityBlockFormEvent ;
import org.bukkit.event.block.SignChangeEvent ;
2019-04-18 02:09:07 +02:00
import org.bukkit.event.entity.AreaEffectCloudApplyEvent ;
2018-07-25 07:18:41 +02:00
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.EntityDeathEvent ;
import org.bukkit.event.entity.EntityExplodeEvent ;
2019-04-18 02:09:07 +02:00
import org.bukkit.event.entity.EntityInteractEvent ;
2018-07-25 07:18:41 +02:00
import org.bukkit.event.entity.EntityTameEvent ;
import org.bukkit.event.entity.EntityUnleashEvent ;
import org.bukkit.event.entity.ExpBottleEvent ;
import org.bukkit.event.entity.LingeringPotionSplashEvent ;
import org.bukkit.event.entity.PotionSplashEvent ;
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 ;
2018-07-25 07:18:41 +02:00
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.PlayerFishEvent ;
import org.bukkit.event.player.PlayerInteractAtEntityEvent ;
import org.bukkit.event.player.PlayerInteractEntityEvent ;
import org.bukkit.event.player.PlayerInteractEvent ;
import org.bukkit.event.player.PlayerItemConsumeEvent ;
import org.bukkit.event.player.PlayerPickupItemEvent ;
import org.bukkit.event.player.PlayerShearEntityEvent ;
2019-05-21 05:48:50 +02:00
import org.bukkit.event.player.PlayerTakeLecternBookEvent ;
2018-07-25 07:18:41 +02:00
import org.bukkit.event.player.PlayerUnleashEntityEvent ;
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 ;
2019-04-18 02:09:07 +02:00
import org.bukkit.inventory.EquipmentSlot ;
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 ;
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
2014-08-19 06:37:41 +02:00
import java.util.ArrayList ;
2014-08-17 22:16:45 +02:00
import java.util.List ;
2019-05-21 05:48:50 +02:00
import java.util.stream.Collectors ;
2014-08-12 02:40:04 +02:00
2018-07-25 07:18:41 +02:00
import javax.annotation.Nullable ;
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
}
2016-05-20 22:48:44 +02:00
@EventHandler ( ignoreCancelled = true )
public void onBlockMultiPlace ( BlockMultiPlaceEvent event ) {
2019-05-21 05:48:50 +02:00
List < Block > blocks = event . getReplacedBlockStates ( ) . stream ( ) . map ( BlockStateAsBlockFunction : : apply ) . collect ( Collectors . toList ( ) ) ;
2016-05-20 22:48:44 +02:00
Events . fireToCancel ( event , new PlaceBlockEvent ( event , create ( event . getPlayer ( ) ) ,
event . getBlock ( ) . getWorld ( ) , blocks , event . getBlock ( ) . getType ( ) ) ) ;
}
2014-08-24 23:39:44 +02:00
@EventHandler ( ignoreCancelled = true )
2014-08-12 02:40:04 +02:00
public void onBlockPlace ( BlockPlaceEvent event ) {
2016-05-20 22:48:44 +02:00
if ( event instanceof BlockMultiPlaceEvent ) return ;
2014-08-12 05:08:38 +02:00
BlockState previousState = event . getBlockReplacedState ( ) ;
// Some blocks, like tall grass and fire, get replaced
2019-05-21 05:48:50 +02:00
if ( previousState . getType ( ) ! = Material . AIR & & previousState . getType ( ) ! = event . getBlockReplacedState ( ) . getType ( ) ) {
2014-08-12 05:08:38 +02:00
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 ( ) ;
2019-04-18 02:09:07 +02:00
Block [ ] adjacent = {
2014-08-24 21:25:29 +02:00
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 ( ) ;
2019-05-21 05:48:50 +02:00
List < Block > blockList = event . getBlocks ( ) . stream ( ) . map ( BlockStateAsBlockFunction : : apply ) . collect ( Collectors . toList ( ) ) ;
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-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
2018-07-21 18:03:32 +02:00
if ( block . getType ( ) = = Material . REDSTONE_ORE & & to = = Material . REDSTONE_ORE ) {
2014-08-25 02:56:15 +02:00
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 ) {
2019-05-21 05:48:50 +02:00
if ( ! 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 ;
2018-07-22 05:06:01 +02:00
ItemStack itemStack = new ItemStack ( fallingBlock . getBlockData ( ) . getMaterial ( ) , 1 ) ;
2014-08-17 22:16:45 +02:00
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 ) {
2015-06-04 08:46:14 +02:00
Block piston = event . getBlock ( ) ;
Cause cause = create ( piston ) ;
BlockFace direction = event . getDirection ( ) ;
2015-08-02 23:00:06 +02:00
2019-04-18 02:09:07 +02:00
ArrayList < Block > blocks = new ArrayList < > ( event . getBlocks ( ) ) ;
2015-08-02 23:00:06 +02:00
int originalSize = blocks . size ( ) ;
Events . fireBulkEventToCancel ( event , new BreakBlockEvent ( event , cause , event . getBlock ( ) . getWorld ( ) , blocks , Material . AIR ) ) ;
if ( originalSize ! = blocks . size ( ) ) {
event . setCancelled ( true ) ;
}
2016-06-11 17:39:58 +02:00
for ( Block b : blocks ) {
2015-08-02 23:00:06 +02:00
Location loc = b . getRelative ( direction ) . getLocation ( ) ;
Events . fireToCancel ( event , new PlaceBlockEvent ( event , cause , loc , b . getType ( ) ) ) ;
2015-06-04 08:46:14 +02:00
}
2014-09-01 02:39:01 +02:00
entry . setCancelled ( event . isCancelled ( ) ) ;
if ( event . isCancelled ( ) ) {
2015-06-04 08:46:14 +02:00
playDenyEffect ( piston . getLocation ( ) . add ( 0 . 5 , 1 , 0 . 5 ) ) ;
2014-09-01 02:39:01 +02:00
}
}
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 ) {
2018-07-21 18:03:32 +02:00
List < Block > blocks = new ArrayList < > ( event . getBlocks ( ) ) ;
2014-09-01 02:39:01 +02:00
int originalLength = blocks . size ( ) ;
2015-08-02 23:00:06 +02:00
BlockFace dir = event . getDirection ( ) ;
for ( int i = 0 ; i < blocks . size ( ) ; i + + ) {
2019-03-21 02:49:45 +01:00
Block existing = blocks . get ( i ) ;
if ( existing . getPistonMoveReaction ( ) = = PistonMoveReaction . MOVE
| | existing . getPistonMoveReaction ( ) = = PistonMoveReaction . PUSH_ONLY ) {
blocks . set ( i , existing . getRelative ( dir ) ) ;
}
2015-08-02 23:00:06 +02:00
}
2014-09-01 02:39:01 +02:00
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
2018-07-21 18:03:32 +02:00
if ( target . getType ( ) = = Material . CAKE ) {
2014-08-12 02:40:04 +02:00
Events . fireToCancel ( event , new UseBlockEvent ( event , create ( event . getPlayer ( ) ) , target ) ) ;
}
}
2019-05-23 00:21:37 +02:00
@EventHandler
2014-08-12 02:40:04 +02:00
public void onPlayerInteract ( PlayerInteractEvent event ) {
Player player = event . getPlayer ( ) ;
2016-05-20 20:49:09 +02:00
@Nullable ItemStack item = event . getItem ( ) ;
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 ;
2015-01-17 00:43:13 +01:00
boolean modifiesWorld ;
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 :
2019-05-23 00:21:37 +02:00
if ( event . useInteractedBlock ( ) ! = Result . DENY ) {
DelegateEvent firedEvent = new UseBlockEvent ( event , cause , clicked ) . setAllowed ( hasInteractBypass ( clicked ) ) ;
if ( clicked . getType ( ) = = Material . REDSTONE_ORE ) {
silent = true ;
}
if ( clicked . getType ( ) = = Material . FARMLAND | | clicked . getType ( ) = = Material . TURTLE_EGG ) {
silent = true ;
firedEvent . getRelevantFlags ( ) . add ( Flags . TRAMPLE_BLOCKS ) ;
}
firedEvent . setSilent ( silent ) ;
interactDebounce . debounce ( clicked , event . getPlayer ( ) , event , firedEvent ) ;
2014-08-25 02:56:15 +02:00
}
2014-08-12 02:40:04 +02:00
break ;
case RIGHT_CLICK_BLOCK :
2019-05-23 00:21:37 +02:00
if ( event . useInteractedBlock ( ) ! = Result . DENY ) {
placed = clicked . getRelative ( event . getBlockFace ( ) ) ;
2014-08-12 02:40:04 +02:00
2019-05-23 00:21:37 +02:00
// Re-used for dispensers
2019-06-02 18:12:57 +02:00
handleBlockRightClick ( event , create ( event . getPlayer ( ) ) , item , clicked , placed ) ;
2019-05-23 00:21:37 +02:00
}
2014-08-12 02:40:04 +02:00
case LEFT_CLICK_BLOCK :
2019-05-23 00:21:37 +02:00
if ( event . useInteractedBlock ( ) ! = Result . DENY ) {
placed = clicked . getRelative ( event . getBlockFace ( ) ) ;
2014-08-12 02:40:04 +02:00
2019-05-23 00:21:37 +02:00
// Only fire events for blocks that are modified when right clicked
2019-06-07 01:23:46 +02:00
final boolean hasItemInteraction = item ! = null & & isItemAppliedToBlock ( item , clicked )
& & event . getAction ( ) = = Action . RIGHT_CLICK_BLOCK ;
2019-06-03 01:33:42 +02:00
modifiesWorld = isBlockModifiedOnClick ( clicked , event . getAction ( ) = = Action . RIGHT_CLICK_BLOCK )
| | hasItemInteraction ;
2015-01-17 00:43:13 +01:00
2019-05-23 00:21:37 +02:00
if ( Events . fireAndTestCancel ( new UseBlockEvent ( event , cause , clicked ) . setAllowed ( ! modifiesWorld ) ) ) {
2015-01-17 00:43:13 +01:00
event . setUseInteractedBlock ( Result . DENY ) ;
2014-08-12 02:40:04 +02:00
}
2019-05-23 00:21: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 ) . setAllowed ( ! modifiesWorld ) ) ) {
event . setUseInteractedBlock ( Result . DENY ) ;
break ;
}
2014-08-12 02:40:04 +02:00
}
2019-06-03 01:33:42 +02:00
if ( hasItemInteraction ) {
if ( Events . fireAndTestCancel ( new PlaceBlockEvent ( event , cause , clicked . getLocation ( ) , clicked . getType ( ) ) ) ) {
event . setUseItemInHand ( Result . DENY ) ;
2019-07-03 15:50:42 +02:00
event . setUseInteractedBlock ( Result . DENY ) ;
2019-06-03 01:33:42 +02:00
}
}
2019-05-23 00:21:37 +02:00
// 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 ;
}
}
if ( event . isCancelled ( ) ) {
playDenyEffect ( event . getPlayer ( ) , clicked . getLocation ( ) . add ( 0 . 5 , 1 , 0 . 5 ) ) ;
}
2014-08-25 09:28:26 +02:00
}
2014-08-12 02:40:04 +02:00
case LEFT_CLICK_AIR :
case RIGHT_CLICK_AIR :
2019-05-23 00:21:37 +02:00
if ( event . useItemInHand ( ) ! = Result . DENY ) {
if ( item ! = null & & ! item . getType ( ) . isBlock ( ) & & Events . fireAndTestCancel ( new UseItemEvent ( event , cause , player . getWorld ( ) , item ) ) ) {
event . setUseItemInHand ( Result . DENY ) ;
}
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
2018-12-26 06:19:23 +01:00
if ( item ! = null & & ( ( BukkitWorldConfiguration ) getWorldConfig ( BukkitAdapter . adapt ( player . getWorld ( ) ) ) ) . blockUseAtFeet . test ( item ) ) {
2014-09-01 04:30:14 +02:00
if ( Events . fireAndTestCancel ( new UseBlockEvent ( event , cause , player . getLocation ( ) . getBlock ( ) ) ) ) {
2019-05-23 00:21:37 +02:00
event . setUseInteractedBlock ( Result . DENY ) ;
2014-09-01 04:30:14 +02:00
}
}
2014-08-12 02:40:04 +02:00
break ;
}
}
2016-05-20 20:49:09 +02:00
@EventHandler ( ignoreCancelled = true )
public void onEntityBlockForm ( EntityBlockFormEvent event ) {
2019-04-18 03:23:29 +02:00
entityBreakBlockDebounce . debounce ( event . getBlock ( ) , event . getEntity ( ) , event ,
new PlaceBlockEvent ( event , create ( event . getEntity ( ) ) ,
event . getBlock ( ) . getLocation ( ) , event . getNewState ( ) . getType ( ) ) ) ;
2016-05-20 20:49:09 +02:00
}
2014-08-24 23:39:44 +02:00
@EventHandler ( ignoreCancelled = true )
2019-04-18 02:09:07 +02:00
public void onEntityInteract ( EntityInteractEvent event ) {
2015-01-17 00:43:13 +01:00
interactDebounce . debounce ( event . getBlock ( ) , event . getEntity ( ) , event ,
2019-04-18 03:23:29 +02:00
new UseBlockEvent ( event , create ( event . getEntity ( ) ) ,
event . getBlock ( ) ) . setAllowed ( hasInteractBypass ( 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-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 ( ) ) ;
2015-01-17 00:43:13 +01:00
boolean allowed = false ;
2014-08-12 02:40:04 +02:00
// Milk buckets can't be emptied as of writing
2015-01-17 00:43:13 +01:00
if ( event . getBucket ( ) = = Material . MILK_BUCKET ) {
allowed = true ;
2014-08-12 02:40:04 +02:00
}
2014-08-25 09:28:26 +02:00
2015-01-17 00:43:13 +01:00
ItemStack item = new ItemStack ( event . getBucket ( ) , 1 ) ;
Material blockMaterial = Materials . getBucketBlockMaterial ( event . getBucket ( ) ) ;
Events . fireToCancel ( event , new PlaceBlockEvent ( event , create ( player ) , blockAffected . getLocation ( ) , blockMaterial ) . setAllowed ( allowed ) ) ;
Events . fireToCancel ( event , new UseItemEvent ( event , create ( player ) , player . getWorld ( ) , item ) . setAllowed ( allowed ) ) ;
2015-04-05 21:44:43 +02:00
if ( event . isCancelled ( ) ) {
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 ( ) ) ;
2015-01-17 00:43:13 +01:00
boolean allowed = false ;
2014-08-12 02:40:04 +02:00
2015-01-17 00:43:13 +01:00
// Milk buckets can't be emptied as of writing
2015-06-19 23:02:09 +02:00
if ( event . getItemStack ( ) . getType ( ) = = Material . MILK_BUCKET ) {
2015-01-17 00:43:13 +01:00
allowed = true ;
2014-08-12 02:40:04 +02:00
}
2014-08-25 09:28:26 +02:00
2015-01-17 00:43:13 +01:00
ItemStack item = new ItemStack ( event . getBucket ( ) , 1 ) ;
Events . fireToCancel ( event , new BreakBlockEvent ( event , create ( player ) , blockAffected ) . setAllowed ( allowed ) ) ;
Events . fireToCancel ( event , new UseItemEvent ( event , create ( player ) , player . getWorld ( ) , item ) . setAllowed ( allowed ) ) ;
2015-04-05 21:44:43 +02:00
if ( event . isCancelled ( ) ) {
playDenyEffect ( event . getPlayer ( ) , blockAffected . getLocation ( ) . add ( 0 . 5 , 0 . 5 , 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 ) {
2018-12-26 06:19:23 +01:00
WorldConfiguration config = getWorldConfig ( BukkitAdapter . adapt ( event . getBlock ( ) . getWorld ( ) ) ) ;
2014-08-22 22:37:02 +02:00
// 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 :
2018-07-22 05:06:01 +02:00
if ( getWorldConfig ( BukkitAdapter . adapt ( event . getEntity ( ) . getWorld ( ) ) ) . strictEntitySpawn ) {
2014-08-25 00:53:45 +02:00
Events . fireToCancel ( event , new SpawnEntityEvent ( event , Cause . unknown ( ) , event . getEntity ( ) ) ) ;
}
break ;
2019-05-21 05:48:50 +02:00
default :
2014-08-25 00:53:45 +02:00
}
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 ) {
2019-02-26 05:46:31 +01:00
if ( event . getState ( ) = = PlayerFishEvent . State . FISHING ) {
if ( Events . fireAndTestCancel ( new UseItemEvent ( event , create ( event . getPlayer ( ) , event . getHook ( ) ) ,
event . getPlayer ( ) . getWorld ( ) , event . getPlayer ( ) . getInventory ( ) . getItemInMainHand ( ) ) ) ) {
event . setCancelled ( true ) ;
}
} else if ( event . getState ( ) = = PlayerFishEvent . State . CAUGHT_FISH ) {
2016-06-11 07:22:40 +02:00
if ( Events . fireAndTestCancel ( new SpawnEntityEvent ( event , create ( event . getPlayer ( ) , event . getHook ( ) ) , event . getHook ( ) . getLocation ( ) , EntityType . EXPERIENCE_ORB ) ) ) {
event . setExpToDrop ( 0 ) ;
}
} else if ( event . getState ( ) = = PlayerFishEvent . State . CAUGHT_ENTITY ) {
Entity caught = event . getCaught ( ) ;
if ( caught = = null ) return ;
if ( caught instanceof Item ) {
Events . fireToCancel ( event , new DestroyEntityEvent ( event , create ( event . getPlayer ( ) , event . getHook ( ) ) , caught ) ) ;
} else if ( Entities . isConsideredBuildingIfUsed ( caught ) ) {
Events . fireToCancel ( event , new UseEntityEvent ( event , create ( event . getPlayer ( ) , event . getHook ( ) ) , caught ) ) ;
2016-06-14 03:28:54 +02:00
} else if ( Entities . isNonHostile ( caught ) | | caught instanceof Player ) {
2016-06-11 07:22:40 +02:00
Events . fireToCancel ( event , new DamageEntityEvent ( event , create ( event . getPlayer ( ) , event . getHook ( ) ) , caught ) ) ;
}
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 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 ) {
2018-07-22 05:06:01 +02:00
player . getInventory ( ) . addItem ( new ItemStack ( Material . EXPERIENCE_BOTTLE , 1 ) ) ;
2015-01-05 03:20:33 +01:00
}
}
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 ( ) ;
2019-04-18 02:09:07 +02:00
ItemStack item = event . getHand ( ) = = EquipmentSlot . OFF_HAND
? player . getInventory ( ) . getItemInOffHand ( ) : player . getInventory ( ) . getItemInMainHand ( ) ;
2014-08-12 02:40:04 +02:00
Entity entity = event . getRightClicked ( ) ;
Events . fireToCancel ( event , new UseItemEvent ( event , create ( player ) , world , item ) ) ;
2019-07-06 17:02:36 +02:00
final UseEntityEvent useEntityEvent = new UseEntityEvent ( event , create ( player ) , entity ) ;
Material matchingItem = Materials . getRelatedMaterial ( entity . getType ( ) ) ;
if ( matchingItem ! = null & & hasInteractBypass ( world , matchingItem ) ) {
useEntityEvent . setAllowed ( true ) ;
}
Events . fireToCancel ( event , useEntityEvent ) ;
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 onEntityDamage ( EntityDamageEvent event ) {
if ( event instanceof EntityDamageByBlockEvent ) {
2015-01-28 10:26:50 +01:00
@Nullable Block attacker = ( ( EntityDamageByBlockEvent ) event ) . getDamager ( ) ;
// The attacker should NOT be null, but sometimes it is
// See WORLDGUARD-3350
if ( attacker ! = null ) {
Events . fireToCancel ( event , new DamageEntityEvent ( event , create ( attacker ) , 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 ) {
2019-04-18 02:09:07 +02:00
// this event doesn't tell us which hand the weapon was in
ItemStack item = ( ( Player ) damager ) . getInventory ( ) . getItemInMainHand ( ) ;
2014-08-12 02:40:04 +02:00
2019-04-18 02:09:07 +02:00
if ( item . getType ( ) ! = Material . AIR ) {
2014-08-12 02:40:04 +02:00
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 ) {
2016-11-20 08:32:42 +01:00
// at the time of writing, spigot is throwing null for the event's combuster. this causes lots of issues downstream.
// whenever (i mean if ever) it is fixed, use getCombuster again instead of the current block
Events . fireToCancel ( event , new DamageEntityEvent ( event , create ( event . getEntity ( ) . getLocation ( ) . getBlock ( ) ) , 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 ( ) ) ) ;
2019-05-21 05:48:50 +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 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 ( ) ;
2015-05-28 23:03:58 +02:00
Events . fireToCancel ( event , new DamageEntityEvent ( event , create ( attacker ) , event . getVehicle ( ) ) ) ;
2014-08-12 02:40:04 +02:00
}
//-------------------------------------------------------------------------
// 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 ( ) ;
2019-07-06 17:02:36 +02:00
if ( holder instanceof Entity & & holder = = event . getPlayer ( ) ) return ;
handleInventoryHolderUse ( event , create ( event . getPlayer ( ) ) , holder ) ;
2015-01-11 09:05:07 +01:00
}
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 ( ) ;
2019-04-06 20:24:01 +02:00
if ( ( causeHolder instanceof Hopper | | causeHolder instanceof Dropper )
& & ( ( BukkitWorldConfiguration ) WorldGuard . getInstance ( ) . getPlatform ( ) . getGlobalStateManager ( ) . get (
BukkitAdapter . adapt ( ( ( Container ) causeHolder ) . getWorld ( ) ) ) ) . ignoreHopperMoveEvents ) {
2017-10-14 20:41:58 +02:00
return ;
}
2014-08-25 00:24:52 +02:00
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 ( ) ;
}
2019-04-06 20:24:01 +02:00
if ( causeHolder ! = null & & ! causeHolder . equals ( sourceHolder ) ) {
2014-08-25 00:24:52 +02:00
handleInventoryHolderUse ( event , cause , sourceHolder ) ;
}
handleInventoryHolderUse ( event , cause , targetHolder ) ;
2014-08-25 00:40:00 +02:00
if ( event . isCancelled ( ) & & causeHolder instanceof Hopper ) {
2019-04-06 20:24:01 +02:00
Bukkit . getScheduler ( ) . scheduleSyncDelayedTask ( getPlugin ( ) ,
( ) - > ( ( 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 ;
2016-11-16 03:20:49 +01:00
int affectedSize = event . getAffectedEntities ( ) . size ( ) ;
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
2018-07-19 16:06:02 +02:00
delegate . getRelevantFlags ( ) . add ( Flags . POTION_SPLASH ) ;
2015-01-07 00:00:13 +01:00
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 + + ;
}
}
2016-11-16 03:20:49 +01:00
if ( blocked = = affectedSize ) { // server does weird things with this if the event is modified, so use cached number
2014-08-12 02:40:04 +02:00
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 ( ) ;
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
2019-04-18 02:09:07 +02:00
if ( dispenserBlock . getBlockData ( ) instanceof Dispenser ) {
Dispenser dispenser = ( Dispenser ) dispenserBlock . getBlockData ( ) ;
2014-08-12 05:08:38 +02:00
Block placed = dispenserBlock . getRelative ( dispenser . getFacing ( ) ) ;
Block clicked = placed . getRelative ( dispenser . getFacing ( ) ) ;
2019-06-02 18:12:57 +02:00
handleBlockRightClick ( event , cause , item , clicked , placed ) ;
2014-08-12 05:08:38 +02:00
}
}
2018-12-26 06:19:23 +01:00
@EventHandler ( ignoreCancelled = true )
public void onLingeringSplash ( LingeringPotionSplashEvent event ) {
AreaEffectCloud aec = event . getAreaEffectCloud ( ) ;
2019-06-12 02:16:16 +02:00
ThrownPotion potion = event . getEntity ( ) ;
2018-12-26 06:19:23 +01:00
World world = potion . getWorld ( ) ;
Cause cause = create ( event . getEntity ( ) ) ;
// Fire item interaction event
Events . fireToCancel ( event , new UseItemEvent ( event , cause , world , potion . getItem ( ) ) ) ;
// Fire entity spawn event
if ( ! event . isCancelled ( ) ) {
// radius unfortunately doesn't go through with this, so only a single location is tested
Events . fireToCancel ( event , new SpawnEntityEvent ( event , cause , aec . getLocation ( ) . add ( 0 . 5 , 0 , 0 . 5 ) , EntityType . AREA_EFFECT_CLOUD ) ) ;
}
}
2019-04-18 02:09:07 +02:00
@EventHandler ( ignoreCancelled = true )
public void onLingeringApply ( AreaEffectCloudApplyEvent event ) {
if ( ! Materials . hasDamageEffect ( event . getEntity ( ) . getCustomEffects ( ) ) ) {
return ;
}
Cause cause = create ( event . getEntity ( ) ) ;
event . getAffectedEntities ( )
. removeIf ( victim - > Events . fireAndTestCancel ( new DamageEntityEvent ( event , cause , victim ) ) ) ;
}
@EventHandler ( ignoreCancelled = true )
public void onPlayerInteractAtEntity ( PlayerInteractAtEntityEvent event ) {
onPlayerInteractEntity ( event ) ;
}
@EventHandler ( ignoreCancelled = true )
public void onBlockExplode ( BlockExplodeEvent event ) {
2019-05-12 06:17:34 +02:00
final BreakBlockEvent eventToFire = new BreakBlockEvent ( event , create ( event . getBlock ( ) ) ,
event . getBlock ( ) . getLocation ( ) . getWorld ( ) , event . blockList ( ) , Material . AIR ) ;
eventToFire . getRelevantFlags ( ) . add ( Flags . OTHER_EXPLOSION ) ;
Events . fireBulkEventToCancel ( event , eventToFire ) ;
2019-04-18 02:09:07 +02:00
}
2019-05-21 05:48:50 +02:00
@EventHandler ( ignoreCancelled = true )
public void onTakeLecternBook ( PlayerTakeLecternBookEvent event ) {
final UseBlockEvent useEvent = new UseBlockEvent ( event , create ( event . getPlayer ( ) ) , event . getLectern ( ) . getBlock ( ) ) ;
useEvent . getRelevantFlags ( ) . add ( Flags . CHEST_ACCESS ) ;
Events . fireToCancel ( event , useEvent ) ;
}
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 placed the placed block
* @param < T > the event type
* /
2019-06-02 18:12:57 +02:00
private static < T extends Event & Cancellable > void handleBlockRightClick ( T event , Cause cause , @Nullable ItemStack item , Block clicked , 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
2019-06-02 18:12:57 +02:00
// (not sure if this actually still happens) -- note Jun 2019 - happens with dispensers still, tho not players
2014-08-13 04:48:20 +02:00
Events . fireToCancel ( event , new UseBlockEvent ( event , cause , clicked . getLocation ( ) , Material . TNT ) ) ;
2016-08-08 16:39:40 +02:00
// Workaround for http://leaky.bukkit.org/issues/1034
Events . fireToCancel ( event , new PlaceBlockEvent ( event , cause , placed . getLocation ( ) , Material . TNT ) ) ;
return ;
2014-08-12 05:08:38 +02:00
}
// Handle created Minecarts
if ( item ! = null & & Materials . isMinecart ( item . getType ( ) ) ) {
2019-07-06 17:02:36 +02:00
EntityType entityType = Materials . getRelatedEntity ( item . getType ( ) ) ;
if ( entityType = = null ) {
entityType = EntityType . MINECART ;
}
Events . fireToCancel ( event , new SpawnEntityEvent ( event , cause , placed . getLocation ( ) . add ( 0 . 5 , 0 , 0 . 5 ) , entityType ) ) ;
2016-08-08 16:39:40 +02:00
return ;
2014-08-12 05:08:38 +02:00
}
2014-09-01 04:36:39 +02:00
// Handle created boats
2016-05-20 20:49:09 +02:00
if ( item ! = null & & Materials . isBoat ( item . getType ( ) ) ) {
2014-09-01 04:36:39 +02:00
Events . fireToCancel ( event , new SpawnEntityEvent ( event , cause , placed . getLocation ( ) . add ( 0 . 5 , 0 , 0 . 5 ) , EntityType . BOAT ) ) ;
2016-08-08 16:39:40 +02:00
return ;
2014-09-01 04:36:39 +02:00
}
2015-01-24 23:02:55 +01:00
// Handle created armor stands
2017-09-16 22:48:38 +02:00
if ( item ! = null & & item . getType ( ) = = Material . ARMOR_STAND ) {
2015-01-28 10:11:36 +01:00
Events . fireToCancel ( event , new SpawnEntityEvent ( event , cause , placed . getLocation ( ) . add ( 0 . 5 , 0 , 0 . 5 ) , EntityType . ARMOR_STAND ) ) ;
2016-08-08 16:39:40 +02:00
return ;
}
2017-09-16 22:48:38 +02:00
if ( item ! = null & & item . getType ( ) = = Material . END_CRYSTAL ) { /*&& placed.getType() == Material.BEDROCK) {*/ // in vanilla you can only place them on bedrock but who knows what plugins will add
2016-08-08 16:39:40 +02:00
// may be overprotective as a result, but better than being underprotective
Events . fireToCancel ( event , new SpawnEntityEvent ( event , cause , placed . getLocation ( ) . add ( 0 . 5 , 0 , 0 . 5 ) , EntityType . ENDER_CRYSTAL ) ) ;
return ;
2015-01-28 10:11:36 +01:00
}
2015-01-24 23:02:55 +01:00
2014-08-25 01:26:15 +02:00
// Handle created spawn eggs
2018-07-22 05:06:01 +02:00
if ( item ! = null & & Materials . isSpawnEgg ( item . getType ( ) ) ) {
2018-07-25 07:18:41 +02:00
Events . fireToCancel ( event , new SpawnEntityEvent ( event , cause , placed . getLocation ( ) . add ( 0 . 5 , 0 , 0 . 5 ) , Materials . getEntitySpawnEgg ( item . getType ( ) ) ) ) ;
2016-08-08 16:39:40 +02:00
return ;
2014-08-25 01:26:15 +02:00
}
2014-08-12 02:40:04 +02:00
}
2014-08-25 00:24:52 +02:00
private static < T extends Event & Cancellable > void handleInventoryHolderUse ( T originalEvent , Cause cause , InventoryHolder holder ) {
if ( originalEvent . isCancelled ( ) ) {
return ;
}
if ( holder instanceof Entity ) {
2019-07-06 17:02:36 +02:00
Entity entity = ( Entity ) holder ;
Material mat = Materials . getRelatedMaterial ( ( entity ) . getType ( ) ) ;
UseEntityEvent useEntityEvent = new UseEntityEvent ( originalEvent , cause , entity ) ;
if ( hasInteractBypass ( ( entity ) . getWorld ( ) , mat ) ) {
useEntityEvent . setAllowed ( true ) ;
2017-05-22 19:56:46 +02:00
}
2019-07-06 17:02:36 +02:00
Events . fireToCancel ( originalEvent , useEntityEvent ) ;
} else {
if ( holder instanceof BlockState ) {
final BlockState block = ( BlockState ) holder ;
final UseBlockEvent useBlockEvent = new UseBlockEvent ( originalEvent , cause , block . getBlock ( ) ) ;
if ( hasInteractBypass ( block . getWorld ( ) , block . getType ( ) ) ) {
useBlockEvent . setAllowed ( true ) ;
}
Events . fireToCancel ( originalEvent , useBlockEvent ) ;
} else if ( holder instanceof DoubleChest ) {
InventoryHolder left = ( ( DoubleChest ) holder ) . getLeftSide ( ) ;
InventoryHolder right = ( ( DoubleChest ) holder ) . getRightSide ( ) ;
if ( left instanceof Chest ) {
Events . fireToCancel ( originalEvent , new UseBlockEvent ( originalEvent , cause , ( ( Chest ) left ) . getBlock ( ) ) ) ;
}
if ( right instanceof Chest ) {
Events . fireToCancel ( originalEvent , new UseBlockEvent ( originalEvent , cause , ( ( Chest ) right ) . getBlock ( ) ) ) ;
}
2017-05-22 19:56:46 +02:00
}
2014-08-25 00:24:52 +02:00
}
}
2014-08-12 02:40:04 +02:00
2019-07-06 17:02:36 +02:00
private static boolean hasInteractBypass ( Block block ) {
2018-12-26 06:19:23 +01:00
return ( ( BukkitWorldConfiguration ) getWorldConfig ( BukkitAdapter . adapt ( block . getWorld ( ) ) ) ) . allowAllInteract . test ( block ) ;
2015-01-05 03:05:50 +01:00
}
2019-07-06 17:02:36 +02:00
private static boolean hasInteractBypass ( World world , Material material ) {
return ( ( BukkitWorldConfiguration ) getWorldConfig ( BukkitAdapter . adapt ( world ) ) ) . allowAllInteract . test ( material ) ;
}
private static boolean hasInteractBypass ( World world , ItemStack item ) {
2018-12-26 06:19:23 +01:00
return ( ( BukkitWorldConfiguration ) getWorldConfig ( BukkitAdapter . adapt ( world ) ) ) . allowAllInteract . test ( item ) ;
2015-01-05 03:05:50 +01:00
}
2019-07-06 17:02:36 +02:00
private static boolean isBlockModifiedOnClick ( Block block , boolean rightClick ) {
2015-01-11 11:05:31 +01:00
return Materials . isBlockModifiedOnClick ( block . getType ( ) , rightClick ) & & ! hasInteractBypass ( block ) ;
2014-09-01 04:17:05 +02:00
}
2019-07-06 17:02:36 +02:00
private static boolean isItemAppliedToBlock ( ItemStack item , Block clicked ) {
2014-09-01 04:17:05 +02:00
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
}
2019-07-06 17:02:36 +02:00
private static void playDenyEffect ( Player player , Location location ) {
2014-08-25 09:28:26 +02:00
//player.playSound(location, Sound.SUCCESSFUL_HIT, 0.2f, 0.4f);
2018-09-28 04:15:50 +02:00
if ( WorldGuard . getInstance ( ) . getPlatform ( ) . getGlobalStateManager ( ) . particleEffects ) {
player . playEffect ( location , Effect . SMOKE , BlockFace . UP ) ;
}
2014-08-25 09:28:26 +02:00
}
2019-07-06 17:02:36 +02:00
private static void playDenyEffect ( Location location ) {
2018-09-28 04:15:50 +02:00
if ( WorldGuard . getInstance ( ) . getPlatform ( ) . getGlobalStateManager ( ) . particleEffects ) {
location . getWorld ( ) . playEffect ( location , Effect . SMOKE , BlockFace . UP ) ;
}
2014-09-01 02:39:01 +02:00
}
2014-08-12 02:40:04 +02:00
}