1
mirror of https://github.com/StarWishsama/Slimefun4.git synced 2024-09-19 19:25:48 +00:00

Deny placement when deletion is queued (#3911)

Co-authored-by: Daniel Walsh <walshydev@gmail.com>
Co-authored-by: J3fftw <44972470+J3fftw1@users.noreply.github.com>
This commit is contained in:
Sefiraat 2023-11-24 21:40:19 +00:00 committed by GitHub
parent 1aeb0e8f65
commit 0589b21af3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 113 additions and 17 deletions

View File

@ -90,20 +90,34 @@ public class BlockListener implements Listener {
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));
}
}

View File

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

View File

@ -58,7 +58,7 @@ class TestSlimefunBlockBreakEvent {
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");
@ -75,7 +75,7 @@ class TestSlimefunBlockBreakEvent {
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");
@ -106,7 +106,7 @@ class TestSlimefunBlockBreakEvent {
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");
@ -119,4 +119,24 @@ class TestSlimefunBlockBreakEvent {
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()));
}
}

View File

@ -16,6 +16,7 @@ import org.bukkit.block.Block;
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;
@ -61,9 +62,10 @@ public class TestSlimefunBlockPlaceEvent {
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));
@ -83,9 +85,10 @@ public class TestSlimefunBlockPlaceEvent {
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));
@ -119,9 +122,10 @@ public class TestSlimefunBlockPlaceEvent {
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));
@ -136,4 +140,48 @@ public class TestSlimefunBlockPlaceEvent {
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());
}
}

View File

@ -2,6 +2,7 @@ package io.github.thebusybiscuit.slimefun4.test;
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;
@ -30,6 +31,8 @@ import io.github.thebusybiscuit.slimefun4.test.mocks.MockSlimefunItem;
public final class TestUtilities {
private static final Random random = new Random();
private TestUtilities() {}
@ParametersAreNonnullByDefault
@ -76,4 +79,14 @@ public final class 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);
}
}