Skip to content

Commit

Permalink
Deny placement when deletion is queued (Slimefun#3911)
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel Walsh <[email protected]>
Co-authored-by: J3fftw <[email protected]>
  • Loading branch information
3 people authored Nov 24, 2023
1 parent 1aeb0e8 commit 0589b21
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -90,20 +90,34 @@ public void onBlockPlace(BlockPlaceEvent e) {
Slimefun.getProtectionManager().logAction(e.getPlayer(), e.getBlock(), Interaction.PLACE_BLOCK);
}
if (sfItem != null && !(sfItem instanceof NotPlaceable)) {
if (!sfItem.canUse(e.getPlayer(), true)) {
Player player = e.getPlayer();

if (!sfItem.canUse(player, true)) {
e.setCancelled(true);
} else {
SlimefunBlockPlaceEvent placeEvent = new SlimefunBlockPlaceEvent(e.getPlayer(), item, e.getBlock(), sfItem);
Block block = e.getBlockPlaced();

/*
* Resolves an issue when placing a block in a location currently in the deletion queue
* TODO This can be safely removed if/when the deletion no longer has a delay associated with it.
*/
if (Slimefun.getTickerTask().isDeletedSoon(block.getLocation())) {
Slimefun.getLocalization().sendMessage(player, "messages.await-deletion");
e.setCancelled(true);
return;
}

SlimefunBlockPlaceEvent placeEvent = new SlimefunBlockPlaceEvent(player, item, block, sfItem);
Bukkit.getPluginManager().callEvent(placeEvent);

if (placeEvent.isCancelled()) {
e.setCancelled(true);
} else {
if (Slimefun.getBlockDataService().isTileEntity(e.getBlock().getType())) {
Slimefun.getBlockDataService().setBlockData(e.getBlock(), sfItem.getId());
if (Slimefun.getBlockDataService().isTileEntity(block.getType())) {
Slimefun.getBlockDataService().setBlockData(block, sfItem.getId());
}

BlockStorage.addBlockInfo(e.getBlock(), "id", sfItem.getId(), true);
BlockStorage.addBlockInfo(block, "id", sfItem.getId(), true);
sfItem.callItemHandler(BlockPlaceHandler.class, handler -> handler.onPlayerPlace(e));
}
}
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/languages/en/messages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ messages:
bee-suit-slow-fall: '&eYour Bee Wings will help you to get back to the ground safe and slow'
deprecated-item: '&4This item has been deprecated and will be removed from Slimefun soon.'
researching-is-disabled: '&cResearching has been disabled on this server. Everything is unlocked by default!'
await-deletion: '&cYou cannot place a Slimefun block so soon after breaking one. Try again shortly.'

multi-tool:
mode-change: '&b%device% mode changed to: &9%mode%'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ void testEventIsFired() {
Player player = new PlayerMock(server, "SomePlayer");

World world = server.addSimpleWorld("my_world");
Block block = new BlockMock(Material.GREEN_TERRACOTTA, new Location(world, 1, 1, 1));
Block block = new BlockMock(Material.GREEN_TERRACOTTA, new Location(world, TestUtilities.randomInt(), 100, TestUtilities.randomInt()));

Slimefun.getRegistry().getWorlds().put("my_world", new BlockStorage(world));
BlockStorage.addBlockInfo(block, "id", "FOOD_COMPOSTER");
Expand All @@ -75,7 +75,7 @@ void testGetters() {
player.getInventory().setItemInMainHand(itemStack);

World world = server.addSimpleWorld("my_world");
Block block = new BlockMock(Material.GREEN_TERRACOTTA, new Location(world, 1, 1, 1));
Block block = new BlockMock(Material.GREEN_TERRACOTTA, new Location(world, TestUtilities.randomInt(), 100, TestUtilities.randomInt()));

Slimefun.getRegistry().getWorlds().put("my_world", new BlockStorage(world));
BlockStorage.addBlockInfo(block, "id", "FOOD_COMPOSTER");
Expand Down Expand Up @@ -106,7 +106,7 @@ public void onBlockBreak(SlimefunBlockBreakEvent event) {
player.getInventory().setItemInMainHand(itemStack);

World world = server.addSimpleWorld("my_world");
Block block = new BlockMock(Material.GREEN_TERRACOTTA, new Location(world, 1, 1, 1));
Block block = new BlockMock(Material.GREEN_TERRACOTTA, new Location(world, TestUtilities.randomInt(), 100, TestUtilities.randomInt()));

Slimefun.getRegistry().getWorlds().put("my_world", new BlockStorage(world));
BlockStorage.addBlockInfo(block, "id", "FOOD_COMPOSTER");
Expand All @@ -119,4 +119,24 @@ public void onBlockBreak(SlimefunBlockBreakEvent event) {
return true;
});
}

@Test
@DisplayName("Test that breaking a Slimefun block gets queued for deletion")
void testBlockBreaksGetQueuedForDeletion() {
Player player = new PlayerMock(server, "SomePlayer");
ItemStack itemStack = new ItemStack(Material.IRON_PICKAXE);
player.getInventory().setItemInMainHand(itemStack);

World world = server.addSimpleWorld("my_world");
Block block = new BlockMock(Material.GREEN_TERRACOTTA, new Location(world, TestUtilities.randomInt(), 100, TestUtilities.randomInt()));

Slimefun.getRegistry().getWorlds().put("my_world", new BlockStorage(world));
BlockStorage.addBlockInfo(block, "id", "FOOD_COMPOSTER");

BlockBreakEvent blockBreakEvent = new BlockBreakEvent(block, player);
server.getPluginManager().callEvent(blockBreakEvent);
server.getPluginManager().assertEventFired(SlimefunBlockBreakEvent.class, e -> true);

Assertions.assertTrue(Slimefun.getTickerTask().isDeletedSoon(block.getLocation()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
Expand Down Expand Up @@ -61,9 +62,10 @@ void testEventIsFired() {
player.getInventory().setItemInMainHand(itemStack);

World world = server.addSimpleWorld("my_world");
Block block = new BlockMock(Material.GREEN_TERRACOTTA, new Location(world, 1, 1, 1));
Block blockAgainst = new BlockMock(Material.GRASS, new Location(world, 1, 0, 1));
BlockStorage.clearBlockInfo(block);
int x = TestUtilities.randomInt();
int z = TestUtilities.randomInt();
Block block = new BlockMock(Material.GREEN_TERRACOTTA, new Location(world, x, 0, z));
Block blockAgainst = new BlockMock(Material.GRASS, new Location(world, x, 1, z));

Slimefun.getRegistry().getWorlds().put("my_world", new BlockStorage(world));

Expand All @@ -83,9 +85,10 @@ void testGetters() {
player.getInventory().setItemInMainHand(itemStack);

World world = server.addSimpleWorld("my_world");
Block block = new BlockMock(Material.GREEN_TERRACOTTA, new Location(world, 1, 1, 1));
Block blockAgainst = new BlockMock(Material.GRASS, new Location(world, 1, 0, 1));
BlockStorage.clearBlockInfo(block);
int x = TestUtilities.randomInt();
int z = TestUtilities.randomInt();
Block block = new BlockMock(Material.GREEN_TERRACOTTA, new Location(world, x, 0, z));
Block blockAgainst = new BlockMock(Material.GRASS, new Location(world, x, 1, z));

Slimefun.getRegistry().getWorlds().put("my_world", new BlockStorage(world));

Expand Down Expand Up @@ -119,9 +122,10 @@ public void onBlockPlace(SlimefunBlockPlaceEvent event) {
player.getInventory().setItemInMainHand(itemStack);

World world = server.addSimpleWorld("my_world");
Block block = new BlockMock(Material.GREEN_TERRACOTTA, new Location(world, 1, 1, 1));
Block blockAgainst = new BlockMock(Material.GRASS, new Location(world, 1, 0, 1));
BlockStorage.clearBlockInfo(block);
int x = TestUtilities.randomInt();
int z = TestUtilities.randomInt();
Block block = new BlockMock(Material.GREEN_TERRACOTTA, new Location(world, x, 0, z));
Block blockAgainst = new BlockMock(Material.GRASS, new Location(world, x, 1, z));

Slimefun.getRegistry().getWorlds().put("my_world", new BlockStorage(world));

Expand All @@ -136,4 +140,48 @@ public void onBlockPlace(SlimefunBlockPlaceEvent event) {
return true;
});
}

@Test
@DisplayName("Test that you cannot place before a SlimefunBlock is fully cleared")
void testBlockPlacementBeforeFullDeletion() {
Player player = new PlayerMock(server, "SomePlayer");
ItemStack itemStack = slimefunItem.getItem();
player.getInventory().setItemInMainHand(itemStack);

// Place first block
World world = server.addSimpleWorld("my_world");
int x = TestUtilities.randomInt();
int z = TestUtilities.randomInt();
Block firstBlock = new BlockMock(Material.GREEN_TERRACOTTA, new Location(world, x, 0, z));
Block firstBlockAgainst = new BlockMock(Material.GRASS, new Location(world, x, 1, z));

Slimefun.getRegistry().getWorlds().put("my_world", new BlockStorage(world));

BlockPlaceEvent firstBlockPlaceEvent = new BlockPlaceEvent(
firstBlock, firstBlock.getState(), firstBlockAgainst, itemStack, player, true, EquipmentSlot.HAND
);

server.getPluginManager().callEvent(firstBlockPlaceEvent);
server.getPluginManager().assertEventFired(SlimefunBlockPlaceEvent.class, e -> {
Assertions.assertFalse(e.isCancelled());
return true;
});

// Break block
server.getPluginManager().callEvent(new BlockBreakEvent(firstBlock, player));
server.getPluginManager().assertEventFired(SlimefunBlockBreakEvent.class, e -> true);

// Assert that the block is not fully deleted
Assertions.assertTrue(Slimefun.getTickerTask().isDeletedSoon(firstBlock.getLocation()));

// Place second block in the same location
Block secondBlock = new BlockMock(Material.GREEN_TERRACOTTA, new Location(world, x, 0, z));
Block secondBlockAgainst = new BlockMock(Material.GRASS, new Location(world, x, 1, z));

BlockPlaceEvent secondBlockPlaceEvent = new BlockPlaceEvent(
secondBlock, secondBlock.getState(), secondBlockAgainst, itemStack, player, true, EquipmentSlot.HAND
);
server.getPluginManager().callEvent(secondBlockPlaceEvent);
Assertions.assertTrue(secondBlockPlaceEvent.isCancelled());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static org.mockito.Mockito.when;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
Expand Down Expand Up @@ -30,6 +31,8 @@

public final class TestUtilities {

private static final Random random = new Random();

private TestUtilities() {}

@ParametersAreNonnullByDefault
Expand Down Expand Up @@ -76,4 +79,14 @@ private TestUtilities() {}
latch.await(2, TimeUnit.SECONDS);
return ref.get();
}

@ParametersAreNonnullByDefault
public static @Nonnull int randomInt() {
return random.nextInt(Integer.MAX_VALUE);
}

@ParametersAreNonnullByDefault
public static @Nonnull int randomInt(int upperBound) {
return random.nextInt(upperBound);
}
}

0 comments on commit 0589b21

Please sign in to comment.