mirror of
https://github.com/EngineHub/WorldGuard.git
synced 2025-02-02 13:31:38 +01:00
Make use of BlockFertilizeEvent, various BlockState lists.
Only mostly tested to work. BlockFertilize unfortunately doesn't let us cancel the preceding stuff like StructureGrow and item use. Also workaround Bukkit sending 2 events for trampling.
This commit is contained in:
parent
5fca3b3c3d
commit
20db92541b
@ -19,6 +19,7 @@
|
||||
|
||||
package com.sk89q.worldguard.bukkit.event.block;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldguard.bukkit.cause.Cause;
|
||||
@ -28,12 +29,15 @@
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.event.Event;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@ -44,7 +48,8 @@
|
||||
abstract class AbstractBlockEvent extends DelegateEvent implements BulkEvent {
|
||||
|
||||
private final World world;
|
||||
private final List<Block> blocks;
|
||||
private List<Block> blocks;
|
||||
private final List<BlockState> blockStates;
|
||||
private final Material effectiveMaterial;
|
||||
|
||||
protected AbstractBlockEvent(@Nullable Event originalEvent, Cause cause, World world, List<Block> blocks, Material effectiveMaterial) {
|
||||
@ -55,6 +60,18 @@ protected AbstractBlockEvent(@Nullable Event originalEvent, Cause cause, World w
|
||||
this.world = world;
|
||||
this.blocks = blocks;
|
||||
this.effectiveMaterial = effectiveMaterial;
|
||||
this.blockStates = null;
|
||||
}
|
||||
|
||||
protected AbstractBlockEvent(@Nullable Event originalEvent, Cause cause, World world, List<BlockState> blocks) {
|
||||
super(originalEvent, cause);
|
||||
checkNotNull(world);
|
||||
checkNotNull(blocks);
|
||||
checkArgument(!blocks.isEmpty());
|
||||
this.world = world;
|
||||
this.blockStates = blocks;
|
||||
this.blocks = null;
|
||||
this.effectiveMaterial = blocks.get(0).getType();
|
||||
}
|
||||
|
||||
protected AbstractBlockEvent(@Nullable Event originalEvent, Cause cause, Block block) {
|
||||
@ -86,6 +103,9 @@ public World getWorld() {
|
||||
* @return a list of affected block
|
||||
*/
|
||||
public List<Block> getBlocks() {
|
||||
if (blocks == null) { // be lazy here because we often don't call getBlocks internally, just filter
|
||||
blocks = blockStates.stream().map(BlockState::getBlock).collect(Collectors.toList());
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
@ -99,15 +119,21 @@ public List<Block> getBlocks() {
|
||||
* @return true if one or more blocks were filtered out
|
||||
*/
|
||||
public boolean filter(Predicate<Location> predicate, boolean cancelEventOnFalse) {
|
||||
boolean hasRemoval = false;
|
||||
return blocks == null
|
||||
? filterInternal(blockStates, BlockState::getLocation, predicate, cancelEventOnFalse)
|
||||
: filterInternal(blocks, Block::getLocation, predicate, cancelEventOnFalse);
|
||||
}
|
||||
|
||||
Iterator<Block> it = blocks.iterator();
|
||||
private <B> boolean filterInternal(List<B> blockList, Function<B, Location> locFunc,
|
||||
Predicate<Location> predicate, boolean cancelEventOnFalse) {
|
||||
boolean hasRemoval = false;
|
||||
Iterator<B> it = blockList.iterator();
|
||||
while (it.hasNext()) {
|
||||
if (!predicate.test(it.next().getLocation())) {
|
||||
if (!predicate.test(locFunc.apply(it.next()))) {
|
||||
hasRemoval = true;
|
||||
|
||||
if (cancelEventOnFalse) {
|
||||
getBlocks().clear();
|
||||
blockList.clear();
|
||||
setCancelled(true);
|
||||
break;
|
||||
} else {
|
||||
@ -115,7 +141,6 @@ public boolean filter(Predicate<Location> predicate, boolean cancelEventOnFalse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hasRemoval;
|
||||
}
|
||||
|
||||
@ -147,7 +172,7 @@ public Material getEffectiveMaterial() {
|
||||
|
||||
@Override
|
||||
public Result getResult() {
|
||||
if (blocks.isEmpty()) {
|
||||
if (blocks == null ? blockStates.isEmpty() : blocks.isEmpty()) {
|
||||
return Result.DENY;
|
||||
}
|
||||
return super.getResult();
|
||||
|
@ -24,6 +24,7 @@
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
@ -40,6 +41,10 @@ public class PlaceBlockEvent extends AbstractBlockEvent {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
public PlaceBlockEvent(@Nullable Event originalEvent, Cause cause, World world, List<BlockState> blocks) {
|
||||
super(originalEvent, cause, world, blocks);
|
||||
}
|
||||
|
||||
public PlaceBlockEvent(@Nullable Event originalEvent, Cause cause, World world, List<Block> blocks, Material effectiveMaterial) {
|
||||
super(originalEvent, cause, world, blocks, effectiveMaterial);
|
||||
}
|
||||
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.bukkit.listener;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
final class BlockStateAsBlockFunction {
|
||||
private BlockStateAsBlockFunction() {
|
||||
}
|
||||
|
||||
static Block apply(@Nullable BlockState blockState) {
|
||||
return blockState != null ? blockState.getBlock() : null;
|
||||
}
|
||||
|
||||
}
|
@ -86,6 +86,7 @@
|
||||
import org.bukkit.event.block.BlockDispenseEvent;
|
||||
import org.bukkit.event.block.BlockExpEvent;
|
||||
import org.bukkit.event.block.BlockExplodeEvent;
|
||||
import org.bukkit.event.block.BlockFertilizeEvent;
|
||||
import org.bukkit.event.block.BlockFromToEvent;
|
||||
import org.bukkit.event.block.BlockIgniteEvent;
|
||||
import org.bukkit.event.block.BlockMultiPlaceEvent;
|
||||
@ -176,9 +177,8 @@ public void onBlockBreak(BlockBreakEvent event) {
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onBlockMultiPlace(BlockMultiPlaceEvent event) {
|
||||
List<Block> blocks = event.getReplacedBlockStates().stream().map(BlockStateAsBlockFunction::apply).collect(Collectors.toList());
|
||||
Events.fireToCancel(event, new PlaceBlockEvent(event, create(event.getPlayer()),
|
||||
event.getBlock().getWorld(), blocks, event.getBlock().getType()));
|
||||
event.getBlock().getWorld(), event.getReplacedBlockStates()));
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
@ -239,14 +239,11 @@ public void onBlockBurn(BlockBurnEvent event) {
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onStructureGrowEvent(StructureGrowEvent event) {
|
||||
int originalCount = event.getBlocks().size();
|
||||
List<Block> blockList = event.getBlocks().stream().map(BlockStateAsBlockFunction::apply).collect(Collectors.toList());
|
||||
|
||||
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));
|
||||
}
|
||||
Events.fireBulkEventToCancel(event, new PlaceBlockEvent(event,
|
||||
create(player == null ? event.getLocation() : player),
|
||||
event.getLocation().getWorld(), event.getBlocks()));
|
||||
|
||||
if (!event.isCancelled() && event.getBlocks().size() != originalCount) {
|
||||
event.getLocation().getBlock().setType(Material.AIR);
|
||||
@ -257,20 +254,26 @@ public void onStructureGrowEvent(StructureGrowEvent event) {
|
||||
public void onEntityChangeBlock(EntityChangeBlockEvent event) {
|
||||
Block block = event.getBlock();
|
||||
Entity entity = event.getEntity();
|
||||
Material to = event.getTo();
|
||||
|
||||
// Forget about Redstone ore, especially since we handle it in INTERACT
|
||||
if (block.getType() == Material.REDSTONE_ORE && to == Material.REDSTONE_ORE) {
|
||||
return;
|
||||
}
|
||||
Material toType = event.getTo();
|
||||
Material fromType = block.getType();
|
||||
Cause cause = create(entity);
|
||||
|
||||
// Fire two events: one as BREAK and one as PLACE
|
||||
if (to != Material.AIR && block.getType() != Material.AIR) {
|
||||
if (!Events.fireToCancel(event, new BreakBlockEvent(event, create(entity), block))) {
|
||||
Events.fireToCancel(event, new PlaceBlockEvent(event, create(entity), block.getLocation(), to));
|
||||
if (toType != Material.AIR && fromType != Material.AIR) {
|
||||
boolean trample = fromType == Material.FARMLAND && toType == Material.DIRT;
|
||||
BreakBlockEvent breakDelagate = new BreakBlockEvent(event, cause, block);
|
||||
if (trample) {
|
||||
breakDelagate.getRelevantFlags().add(Flags.TRAMPLE_BLOCKS);
|
||||
}
|
||||
if (!Events.fireToCancel(event, breakDelagate)) {
|
||||
PlaceBlockEvent placeDelegate = new PlaceBlockEvent(event, cause, block.getLocation(), toType);
|
||||
if (trample) {
|
||||
placeDelegate.getRelevantFlags().add(Flags.TRAMPLE_BLOCKS);
|
||||
}
|
||||
Events.fireToCancel(event, placeDelegate);
|
||||
}
|
||||
} else {
|
||||
if (to == Material.AIR) {
|
||||
if (toType == Material.AIR) {
|
||||
// Track the source so later we can create a proper chain of causes
|
||||
if (entity instanceof FallingBlock) {
|
||||
Cause.trackParentCause(entity, block);
|
||||
@ -279,13 +282,12 @@ public void onEntityChangeBlock(EntityChangeBlockEvent event) {
|
||||
Events.fireToCancel(event, new SpawnEntityEvent(event, create(block), entity));
|
||||
} else {
|
||||
entityBreakBlockDebounce.debounce(
|
||||
block, event.getEntity(), event, new BreakBlockEvent(event, create(entity), block));
|
||||
block, event.getEntity(), event, new BreakBlockEvent(event, cause, block));
|
||||
}
|
||||
} else {
|
||||
boolean wasCancelled = event.isCancelled();
|
||||
Cause cause = create(entity);
|
||||
|
||||
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, block.getLocation(), to));
|
||||
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, block.getLocation(), toType));
|
||||
|
||||
if (event.isCancelled() && !wasCancelled && entity instanceof FallingBlock) {
|
||||
FallingBlock fallingBlock = (FallingBlock) entity;
|
||||
@ -491,6 +493,12 @@ public void onEntityInteract(EntityInteractEvent event) {
|
||||
event.getBlock()).setAllowed(hasInteractBypass(event.getBlock())));
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onBlockFertilize(BlockFertilizeEvent event) {
|
||||
Cause cause = create(event.getPlayer(), event.getBlock());
|
||||
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, event.getBlock().getWorld(), event.getBlocks()));
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onBlockIgnite(BlockIgniteEvent event) {
|
||||
Block block = event.getBlock();
|
||||
|
Loading…
Reference in New Issue
Block a user