Skip to content
Permalink
Browse files

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.
  • Loading branch information...
wizjany committed Sep 18, 2019
1 parent 5fca3b3 commit 20db92541b5336446f71378a44e29462572af034
@@ -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,23 +119,28 @@ public World getWorld() {
* @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 {
it.remove();
}
}
}

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 @@

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);
}

This file was deleted.

@@ -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();

0 comments on commit 20db925

Please sign in to comment.
You can’t perform that action at this time.