Implements HARVEST and CROP_PLANTING protection flags

Requested by #2113
This commit is contained in:
tastybento 2023-04-07 20:51:59 +01:00
parent ba19b08f4c
commit b4737f104c
6 changed files with 166 additions and 10 deletions

View File

@ -2,6 +2,7 @@ package world.bentobox.bentobox.listeners.flags.protection;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.AbstractArrow;
import org.bukkit.entity.ArmorStand;
@ -31,7 +32,26 @@ public class BreakBlocksListener extends FlagListener {
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onBlockBreak(final BlockBreakEvent e) {
checkIsland(e, e.getPlayer(), e.getBlock().getLocation(), Flags.BREAK_BLOCKS);
Player p = e.getPlayer();
Location l = e.getBlock().getLocation();
Material m = e.getBlock().getType();
switch (m)
{
case MELON -> this.checkIsland(e, p, l, Flags.HARVEST);
case PUMPKIN -> this.checkIsland(e, p, l, Flags.HARVEST);
default -> {
// Crops
if (Tag.CROPS.isTagged(m)
&& !m.equals(Material.MELON_STEM)
&& !m.equals(Material.PUMPKIN_STEM)
&& !m.equals(Material.ATTACHED_MELON_STEM)
&& !m.equals(Material.ATTACHED_PUMPKIN_STEM)) {
this.checkIsland(e, p, l, Flags.HARVEST);
} else {
checkIsland(e, p, l, Flags.BREAK_BLOCKS);
}
}
}
}
/**
@ -64,11 +84,10 @@ public class BreakBlocksListener extends FlagListener {
{
return;
}
Player p = e.getPlayer();
Location l = e.getClickedBlock().getLocation();
switch (e.getClickedBlock().getType())
Material m = e.getClickedBlock().getType();
switch (m)
{
case CAKE -> this.checkIsland(e, p, l, Flags.BREAK_BLOCKS);
case SPAWNER -> this.checkIsland(e, p, l, Flags.BREAK_SPAWNERS);

View File

@ -1,5 +1,7 @@
package world.bentobox.bentobox.listeners.flags.protection;
import java.util.Set;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
@ -12,6 +14,7 @@ import org.bukkit.event.hanging.HangingPlaceEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.flags.FlagListener;
import world.bentobox.bentobox.lists.Flags;
@ -20,6 +23,7 @@ import world.bentobox.bentobox.lists.Flags;
*/
public class PlaceBlocksListener extends FlagListener
{
public static final Set<Material> SEEDS = Set.of(Material.BEETROOT_SEEDS, Material.MELON_SEEDS, Material.WHEAT_SEEDS);
/**
* Check blocks being placed in general
*
@ -28,7 +32,9 @@ public class PlaceBlocksListener extends FlagListener
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onBlockPlace(final BlockPlaceEvent e)
{
if (e.getBlock().getType().equals(Material.FIRE) ||
Material m = e.getBlock().getType();
Material against = e.getBlockAgainst().getType();
if (m.equals(Material.FIRE) ||
e.getItemInHand() == null || // Note that this should never happen officially, but it's possible for other plugins to cause it to happen
e.getItemInHand().getType().equals(Material.WRITABLE_BOOK) ||
e.getItemInHand().getType().equals(Material.WRITTEN_BOOK))
@ -36,8 +42,12 @@ public class PlaceBlocksListener extends FlagListener
// Books can only be placed on lecterns and as such are protected by the LECTERN flag.
return;
}
this.checkIsland(e, e.getPlayer(), e.getBlock().getLocation(), Flags.PLACE_BLOCKS);
// Crops
if (against.equals(Material.FARMLAND) && SEEDS.contains(e.getItemInHand().getType())) {
this.checkIsland(e, e.getPlayer(), e.getBlock().getLocation(), Flags.CROP_PLANTING);
} else {
this.checkIsland(e, e.getPlayer(), e.getBlock().getLocation(), Flags.PLACE_BLOCKS);
}
}
@ -61,6 +71,7 @@ public class PlaceBlocksListener extends FlagListener
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerHitItemFrame(PlayerInteractEntityEvent e)
{
BentoBox.getInstance().logDebug(e.getEventName());
if (e.getRightClicked().getType().equals(EntityType.ITEM_FRAME) ||
e.getRightClicked().getType().equals(EntityType.GLOW_ITEM_FRAME))
{

View File

@ -288,12 +288,12 @@ public final class Flags {
public static final Flag SHEARING = new Flag.Builder("SHEARING", Material.SHEARS).listener(new ShearingListener()).mode(Flag.Mode.ADVANCED).build();
// Item pickup or drop
public static final Flag ITEM_DROP = new Flag.Builder("ITEM_DROP", Material.DIAMOND).defaultSetting(true).listener(new ItemDropPickUpListener()).mode(Flag.Mode.BASIC).build();
public static final Flag ITEM_PICKUP = new Flag.Builder("ITEM_PICKUP", Material.SUGAR_CANE).mode(Flag.Mode.BASIC).build();
public static final Flag ITEM_DROP = new Flag.Builder("ITEM_DROP", Material.DIAMOND).defaultRank(RanksManager.VISITOR_RANK).listener(new ItemDropPickUpListener()).mode(Flag.Mode.BASIC).build();
public static final Flag ITEM_PICKUP = new Flag.Builder("ITEM_PICKUP", Material.SUGAR_CANE).mode(Flag.Mode.BASIC).defaultRank(RanksManager.VISITOR_RANK).build();
// Experience
public static final Flag EXPERIENCE_PICKUP = new Flag.Builder("EXPERIENCE_PICKUP", Material.EXPERIENCE_BOTTLE)
.listener(Util.isPaper() ? new PaperExperiencePickupListener() : new ExperiencePickupListener()).mode(Flag.Mode.ADVANCED).build();
.listener(Util.isPaper() ? new PaperExperiencePickupListener() : new ExperiencePickupListener()).mode(Flag.Mode.ADVANCED).defaultRank(RanksManager.VISITOR_RANK).build();
// Command ranks
public static final Flag COMMAND_RANKS = new Flag.Builder("COMMAND_RANKS", Material.PLAYER_HEAD)
@ -648,6 +648,21 @@ public final class Flags {
*/
public static final Flag ENTITY_PORTAL_TELEPORT = new Flag.Builder("ENTITY_PORTAL_TELEPORT", Material.ENDER_EYE).type(Type.WORLD_SETTING).defaultSetting(false).build();
/**
* Harvest Setting
* Controls who gets to harvest any crop related contents. e.g. Wheat, Sugar Cane, melon blocks, not stems, pumpkin blocks, etc.
* @since 1.23.0
*/
public static final Flag HARVEST = new Flag.Builder("HARVEST", Material.PUMPKIN).type(Type.PROTECTION).build();
/**
* Crop Planting
* Controls who gets to plant crops on tilled soil.
* @since 1.23.0
*/
public static final Flag CROP_PLANTING = new Flag.Builder("CROP_PLANTING", Material.PUMPKIN_SEEDS).type(Type.PROTECTION).build();
/**
* Provides a list of all the Flag instances contained in this class using reflection.
* Deprecated Flags are ignored.

View File

@ -933,6 +933,11 @@ protection:
&a by island visitor.
name: "Creeper griefing protection"
hint: "Creeper griefing disabled"
CROP_PLANTING:
description: |-
&a Set who can plant seeds.
name: "Crop planting"
hint: "Crop planting disabled"
CROP_TRAMPLE:
description: "Toggle crop trampling"
name: "Trample crops"
@ -1041,6 +1046,13 @@ protection:
&a outside protected
&a island space
name: "&e Limit mobs to island"
HARVEST:
description: |-
&a Set who can harvest crops.
&a Don't forget to allow item
&a pickup too!
name: "Crop harvesting"
hint: "Crop harvesting disabled"
HIVE:
description: |-
&a Toggle hive harvesting.

View File

@ -80,6 +80,7 @@ public class BreakBlocksListenerTest extends AbstractCommonSetup {
public void testOnBlockBreakAllowed() {
Block block = mock(Block.class);
when(block.getLocation()).thenReturn(location);
when(block.getType()).thenReturn(Material.DIRT);
BlockBreakEvent e = new BlockBreakEvent(block, player);
bbl.onBlockBreak(e);
assertFalse(e.isCancelled());
@ -92,12 +93,43 @@ public class BreakBlocksListenerTest extends AbstractCommonSetup {
public void testOnBlockBreakNotAllowed() {
when(island.isAllowed(any(), any())).thenReturn(false);
Block block = mock(Block.class);
when(block.getType()).thenReturn(Material.DIRT);
when(block.getLocation()).thenReturn(location);
BlockBreakEvent e = new BlockBreakEvent(block, player);
bbl.onBlockBreak(e);
assertTrue(e.isCancelled());
verify(notifier).notify(any(), eq("protection.protected"));
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.protection.BreakBlocksListener#onBlockBreak(org.bukkit.event.block.BlockBreakEvent)}.
*/
@Test
public void testOnBlockHarvestNotAllowed() {
when(island.isAllowed(any(), eq(Flags.HARVEST))).thenReturn(false);
Block block = mock(Block.class);
when(block.getType()).thenReturn(Material.PUMPKIN);
when(block.getLocation()).thenReturn(location);
BlockBreakEvent e = new BlockBreakEvent(block, player);
bbl.onBlockBreak(e);
assertTrue(e.isCancelled());
verify(notifier).notify(any(), eq("protection.protected"));
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.protection.BreakBlocksListener#onBlockBreak(org.bukkit.event.block.BlockBreakEvent)}.
*/
@Test
public void testOnBlockHarvestAllowed() {
when(island.isAllowed(any(), eq(Flags.BREAK_BLOCKS))).thenReturn(false);
when(island.isAllowed(any(), eq(Flags.HARVEST))).thenReturn(true);
Block block = mock(Block.class);
when(block.getType()).thenReturn(Material.PUMPKIN);
when(block.getLocation()).thenReturn(location);
BlockBreakEvent e = new BlockBreakEvent(block, player);
bbl.onBlockBreak(e);
assertFalse(e.isCancelled());
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.protection.BreakBlocksListener#onBreakHanging(org.bukkit.event.hanging.HangingBreakByEntityEvent)}.

View File

@ -89,6 +89,7 @@ public class PlaceBlocksListenerTest extends AbstractCommonSetup {
when(placedBlock.getLocation()).thenReturn(location);
BlockState replacedBlockState = mock(BlockState.class);
Block placedAgainst = mock(Block.class);
when(placedAgainst.getType()).thenReturn(Material.STONE);
ItemStack itemInHand = mock(ItemStack.class);
when(itemInHand.getType()).thenReturn(Material.STONE);
EquipmentSlot hand = EquipmentSlot.HAND;
@ -153,6 +154,7 @@ public class PlaceBlocksListenerTest extends AbstractCommonSetup {
when(placedBlock.getLocation()).thenReturn(location);
BlockState replacedBlockState = mock(BlockState.class);
Block placedAgainst = mock(Block.class);
when(placedAgainst.getType()).thenReturn(Material.STONE);
ItemStack itemInHand = mock(ItemStack.class);
when(itemInHand.getType()).thenReturn(Material.STONE);
EquipmentSlot hand = EquipmentSlot.HAND;
@ -161,6 +163,71 @@ public class PlaceBlocksListenerTest extends AbstractCommonSetup {
assertTrue(e.isCancelled());
verify(notifier).notify(any(), eq("protection.protected"));
}
/**
* Test method for {@link PlaceBlocksListener#onBlockPlace(org.bukkit.event.block.BlockPlaceEvent)}.
*/
@Test
public void testOnBlockCropsAllowed() {
when(island.isAllowed(any(), eq(Flags.PLACE_BLOCKS))).thenReturn(false);
when(island.isAllowed(any(), eq(Flags.CROP_PLANTING))).thenReturn(true);
Block placedBlock = mock(Block.class);
when(placedBlock.getType()).thenReturn(Material.WHEAT);
when(placedBlock.getLocation()).thenReturn(location);
BlockState replacedBlockState = mock(BlockState.class);
Block placedAgainst = mock(Block.class);
when(placedAgainst.getType()).thenReturn(Material.FARMLAND);
ItemStack itemInHand = mock(ItemStack.class);
when(itemInHand.getType()).thenReturn(Material.WHEAT_SEEDS);
EquipmentSlot hand = EquipmentSlot.HAND;
BlockPlaceEvent e = new BlockPlaceEvent(placedBlock, replacedBlockState, placedAgainst, itemInHand, player, true, hand);
pbl.onBlockPlace(e);
assertFalse(e.isCancelled());
}
/**
* Test method for {@link PlaceBlocksListener#onBlockPlace(org.bukkit.event.block.BlockPlaceEvent)}.
*/
@Test
public void testOnBlockCropsAllowedNotCrop() {
when(island.isAllowed(any(), eq(Flags.PLACE_BLOCKS))).thenReturn(false);
when(island.isAllowed(any(), eq(Flags.CROP_PLANTING))).thenReturn(true);
Block placedBlock = mock(Block.class);
when(placedBlock.getType()).thenReturn(Material.DIRT);
when(placedBlock.getLocation()).thenReturn(location);
BlockState replacedBlockState = mock(BlockState.class);
Block placedAgainst = mock(Block.class);
when(placedAgainst.getType()).thenReturn(Material.FARMLAND);
ItemStack itemInHand = mock(ItemStack.class);
when(itemInHand.getType()).thenReturn(Material.DIRT);
EquipmentSlot hand = EquipmentSlot.HAND;
BlockPlaceEvent e = new BlockPlaceEvent(placedBlock, replacedBlockState, placedAgainst, itemInHand, player, true, hand);
pbl.onBlockPlace(e);
assertTrue(e.isCancelled());
verify(notifier).notify(any(), eq("protection.protected"));
}
/**
* Test method for {@link PlaceBlocksListener#onBlockPlace(org.bukkit.event.block.BlockPlaceEvent)}.
*/
@Test
public void testOnBlockCropsNotAllowed() {
when(island.isAllowed(any(), eq(Flags.PLACE_BLOCKS))).thenReturn(false);
when(island.isAllowed(any(), eq(Flags.CROP_PLANTING))).thenReturn(false);
Block placedBlock = mock(Block.class);
when(placedBlock.getType()).thenReturn(Material.WHEAT);
when(placedBlock.getLocation()).thenReturn(location);
BlockState replacedBlockState = mock(BlockState.class);
Block placedAgainst = mock(Block.class);
when(placedAgainst.getType()).thenReturn(Material.FARMLAND);
ItemStack itemInHand = mock(ItemStack.class);
when(itemInHand.getType()).thenReturn(Material.WHEAT_SEEDS);
EquipmentSlot hand = EquipmentSlot.HAND;
BlockPlaceEvent e = new BlockPlaceEvent(placedBlock, replacedBlockState, placedAgainst, itemInHand, player, true, hand);
pbl.onBlockPlace(e);
assertTrue(e.isCancelled());
verify(notifier).notify(any(), eq("protection.protected"));
}
/**
* Test method for {@link PlaceBlocksListener#onBlockPlace(org.bukkit.event.block.BlockPlaceEvent)}.