Implement new 1.19 materials and entities (#1990)

* Update to Spigot and Paper API 1.19 and Java 17

* Set minimal version to 1.18.

* Add breeding protection for Axolotl and Goats (1.18)
Add breeding protection for Frog and Allay (1.19)

* Clean up switch statement in BlockInteractionListener

* Add chest boat support to BreakBlocksListener.

Part of #1987

* Add powdered snow pickup with bucket protection.

* Add glow ink sac protection on signs.
Switch to SheepDyeWoolEvent as it now contains player variable.

* Clean up Hurting Listener

* Mark 1.16.5, 1.17 and 1.17.1 as incompatible.
Mark 1.18, 1.18.1 and 1.18.2 as supported.

Add 1.19 as compatible.
Part of 1987

* Add ChestBoat inventory protection.
Part of #1987

* Clean up LockAndBanListener

* Add MANGROVE_PRESSURE_PLATE protection.
Part of #1987

* Add Glow Item Frame protection to player interact event.

* Clean up MobSpawnListener

* Clean up ChestDamageListener

* Change from custom method to Tag.PRESSURE_PLATES to detect pressure plates.
Part of #1987

* Implement proper chest boat protection.
Part of #1987

* Move to 1.19 R1 world regenerator.
Part of #1987

* Add allay to the animal entity list.
Part of #1987

* Add axolotl and other fish scooping protection.
Part of #1987

* Fixes Bucket and Glass Bottle filling.

Buckets and bottles were not working since cauldron splitting by type. This change fixes that.

It also protects from filling bottles with water from water sources or waterlogged blocks.

* Remove 1.17.1 compatibility check for biome adapter.
Add cheezee 1.19.1 compatibility version.

* Fixes chest boat interactions.

Part of #1987

* Implement Allay protection.
New flag ALLAY is required to interact with allays.

Part of #1987

* Prevent visitors for being targeted by entities if ENTITY_ATTACK is enabled.

* Implement Sculk Sensor and Shrieker activation protection setting.

Part of #1987

* Add music discs to the LangUtilsHook
Part of #1987

* Fixes failing unit-tests.
This commit is contained in:
BONNe 2022-06-14 00:38:53 +03:00 committed by GitHub
parent 6f2a9929c0
commit 85b52f4bfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 955 additions and 527 deletions

10
pom.xml
View File

@ -63,15 +63,15 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>16</java.version>
<java.version>17</java.version>
<!-- Non-minecraft related dependencies -->
<powermock.version>2.0.9</powermock.version>
<mongodb.version>3.12.8</mongodb.version>
<!-- More visible way to change dependency versions -->
<spigot.version>1.18.2-R0.1-SNAPSHOT</spigot.version>
<spigot.version>1.19-R0.1-SNAPSHOT</spigot.version>
<!-- Might differ from the last Spigot release for short periods
of time -->
<paper.version>1.16.5-R0.1-SNAPSHOT</paper.version>
<paper.version>1.19-R0.1-SNAPSHOT</paper.version>
<bstats.version>2.2.1</bstats.version>
<vault.version>1.7</vault.version>
<placeholderapi.version>2.10.9</placeholderapi.version>
@ -164,7 +164,7 @@
</repository>
<repository>
<id>papermc</id>
<url>https://papermc.io/repo/repository/maven-public/</url>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<repository>
<!-- This is a temporary reference as the Maven Shade plugin
@ -188,7 +188,7 @@
</dependency>
<!-- Paper API -->
<dependency>
<groupId>com.destroystokyo.paper</groupId>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>${paper.version}</version>
<scope>provided</scope>

View File

@ -56,7 +56,7 @@ public class BentoboxTypeAdapterFactory implements TypeAdapterFactory {
if (Location.class.isAssignableFrom(rawType)) {
// Use our current location adapter for backward compatibility
return (TypeAdapter<T>) new LocationTypeAdapter();
} else if (Biome.class.isAssignableFrom(rawType) && !ServerCompatibility.getInstance().isVersion(ServerCompatibility.ServerVersion.V1_17_1)) { // TODO: Any better way ?
} else if (Biome.class.isAssignableFrom(rawType)) {
return (TypeAdapter<T>) new BiomeTypeAdapter();
} else if (Enum.class.isAssignableFrom(rawType)) {
return new EnumTypeAdapter(rawType);

View File

@ -626,6 +626,8 @@ public class LangUtilsHook extends Hook {
case MUSIC_DISC_11 -> "C418 - 11";
case MUSIC_DISC_WAIT -> "C418 - wait";
case MUSIC_DISC_PIGSTEP -> "Lena Raine - Pigstep";
case MUSIC_DISC_5 -> "Samuel Åberg - 5";
case MUSIC_DISC_OTHERSIDE -> "Lena Raine - otherside";
default -> null;
};
}

View File

@ -1,12 +1,15 @@
package world.bentobox.bentobox.listeners.flags.protection;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import org.bukkit.FluidCollisionMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
@ -26,236 +29,269 @@ import world.bentobox.bentobox.lists.Flags;
* Handle interaction with blocks
* @author tastybento
*/
public class BlockInteractionListener extends FlagListener {
public class BlockInteractionListener extends FlagListener
{
/**
* These cover materials in another server version.
* This avoids run time errors due to unknown enum values, at the expense of a string comparison
* These cover materials in another server version. This avoids run time errors due to unknown enum values, at the
* expense of a string comparison
*/
private final static Map<String, String> stringFlags;
static {
stringFlags = Map.of("RESPAWN_ANCHOR", "PLACE_BLOCKS");
static
{
stringFlags = Map.of(
"ACACIA_CHEST_BOAT", "CHEST",
"BIRCH_CHEST_BOAT", "CHEST",
"JUNGLE_CHEST_BOAT", "CHEST",
"DARK_OAK_CHEST_BOAT", "CHEST",
"MANGROVE_CHEST_BOAT", "CHEST",
"OAK_CHEST_BOAT", "CHEST",
"SPRUCE_CHEST_BOAT", "CHEST");
}
/**
* Handle interaction with blocks
*
* @param e - event
*/
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerInteract(final PlayerInteractEvent e) {
public void onPlayerInteract(final PlayerInteractEvent e)
{
// We only care about the RIGHT_CLICK_BLOCK action.
if (!e.getAction().equals(Action.RIGHT_CLICK_BLOCK) || e.getClickedBlock() == null) {
if (!e.getAction().equals(Action.RIGHT_CLICK_BLOCK) || e.getClickedBlock() == null)
{
return;
}
// Check clicked block
checkClickedBlock(e, e.getPlayer(), e.getClickedBlock().getLocation(), e.getClickedBlock().getType());
this.checkClickedBlock(e, e.getPlayer(), e.getClickedBlock().getLocation(), e.getClickedBlock().getType());
// Now check for in-hand items
if (e.getItem() != null && !e.getItem().getType().equals(Material.AIR)) {
if (e.getItem() != null && !e.getItem().getType().equals(Material.AIR))
{
// Boats
if (e.getItem().getType().name().endsWith("_BOAT")) {
checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.BOAT);
if (e.getItem().getType().name().endsWith("BOAT"))
{
this.checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.BOAT);
}
// Spawn eggs
else if (e.getItem().getType().name().endsWith("_SPAWN_EGG")) {
checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.SPAWN_EGGS);
else if (e.getItem().getType().name().endsWith("_SPAWN_EGG"))
{
this.checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.SPAWN_EGGS);
}
// Now check for in-hand items
if (e.getItem() != null) {
if (e.getItem().getType().name().contains("BOAT")) {
checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.PLACE_BLOCKS);
return;
}
switch (e.getItem().getType()) {
case ENDER_PEARL:
checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.ENDER_PEARL);
break;
case BONE_MEAL:
checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.PLACE_BLOCKS);
break;
default:
break;
else if (e.getItem().getType() == Material.ENDER_PEARL)
{
this.checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.ENDER_PEARL);
}
else if (e.getItem().getType() == Material.BONE_MEAL)
{
this.checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.PLACE_BLOCKS);
}
else if (e.getItem().getType() == Material.GLASS_BOTTLE)
{
Block targetedBlock = e.getPlayer().getTargetBlockExact(5, FluidCollisionMode.ALWAYS);
// Check if player is clicking on water or waterlogged block with a bottle.
if (targetedBlock != null && (Material.WATER.equals(targetedBlock.getType()) ||
targetedBlock.getBlockData() instanceof Waterlogged))
{
this.checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.BREWING);
}
}
}
}
/**
* Check if an action can occur on a clicked block
*
* @param e - event called
* @param player - player
* @param loc - location of clicked block
* @param type - material type of clicked block
*/
private void checkClickedBlock(Event e, Player player, Location loc, Material type) {
private void checkClickedBlock(Event e, Player player, Location loc, Material type)
{
// Handle pots
if (type.name().startsWith("POTTED")) {
checkIsland(e, player, loc, Flags.FLOWER_POT);
return;
}
if (Tag.ANVIL.isTagged(type)) {
checkIsland(e, player, loc, Flags.ANVIL);
return;
}
if (Tag.BUTTONS.isTagged(type)) {
checkIsland(e, player, loc, Flags.BUTTON);
return;
}
if (Tag.BEDS.isTagged(type)) {
checkIsland(e, player, loc, Flags.BED);
return;
}
if (Tag.DOORS.isTagged(type)) {
checkIsland(e, player, loc, Flags.DOOR);
return;
}
if (Tag.SHULKER_BOXES.isTagged(type)) {
checkIsland(e, player, loc, Flags.SHULKER_BOX);
return;
}
if (Tag.TRAPDOORS.isTagged(type)) {
checkIsland(e, player, loc, Flags.TRAPDOOR);
if (type.name().startsWith("POTTED"))
{
this.checkIsland(e, player, loc, Flags.FLOWER_POT);
return;
}
switch (type) {
case BEACON:
checkIsland(e, player, loc, Flags.BEACON);
break;
case BREWING_STAND:
case CAULDRON:
checkIsland(e, player, loc, Flags.BREWING);
break;
case BEEHIVE:
case BEE_NEST:
checkIsland(e, player, loc, Flags.HIVE);
break;
case BARREL:
checkIsland(e, player, loc, Flags.BARREL);
break;
case CHEST:
case CHEST_MINECART:
checkIsland(e, player, loc, Flags.CHEST);
break;
case TRAPPED_CHEST:
checkIsland(e, player, loc, Flags.TRAPPED_CHEST);
break;
case FLOWER_POT:
checkIsland(e, player, loc, Flags.FLOWER_POT);
break;
case COMPOSTER:
checkIsland(e, player, loc, Flags.COMPOSTER);
break;
case DISPENSER:
checkIsland(e, player, loc, Flags.DISPENSER);
break;
case DROPPER:
checkIsland(e, player, loc, Flags.DROPPER);
break;
case HOPPER:
case HOPPER_MINECART:
checkIsland(e, player, loc, Flags.HOPPER);
break;
case BLAST_FURNACE:
case CAMPFIRE:
case FURNACE_MINECART:
case FURNACE:
case SMOKER:
checkIsland(e, player, loc, Flags.FURNACE);
break;
case ENCHANTING_TABLE:
checkIsland(e, player, loc, Flags.ENCHANTING);
break;
case ENDER_CHEST:
checkIsland(e, player, loc, Flags.ENDER_CHEST);
break;
case JUKEBOX:
checkIsland(e, player, loc, Flags.JUKEBOX);
break;
case NOTE_BLOCK:
checkIsland(e, player, loc, Flags.NOTE_BLOCK);
break;
case CRAFTING_TABLE:
case CARTOGRAPHY_TABLE:
case GRINDSTONE:
case STONECUTTER:
case LOOM:
checkIsland(e, player, loc, Flags.CRAFTING);
break;
case LEVER:
checkIsland(e, player, loc, Flags.LEVER);
break;
case REDSTONE_WIRE:
case REPEATER:
case COMPARATOR:
case DAYLIGHT_DETECTOR:
checkIsland(e, player, loc, Flags.REDSTONE);
break;
case DRAGON_EGG:
checkIsland(e, player, loc, Flags.DRAGON_EGG);
break;
case END_PORTAL_FRAME:
checkIsland(e, player, loc, Flags.PLACE_BLOCKS);
break;
case GLOW_ITEM_FRAME:
case ITEM_FRAME:
checkIsland(e, player, loc, Flags.ITEM_FRAME);
break;
case SWEET_BERRY_BUSH:
checkIsland(e, player, loc, Flags.BREAK_BLOCKS);
break;
case CAKE:
checkIsland(e, player, loc, Flags.CAKE);
break;
case OAK_FENCE_GATE:
case SPRUCE_FENCE_GATE:
case BIRCH_FENCE_GATE:
case JUNGLE_FENCE_GATE:
case DARK_OAK_FENCE_GATE:
case ACACIA_FENCE_GATE:
case CRIMSON_FENCE_GATE:
case WARPED_FENCE_GATE:
checkIsland(e, player, loc, Flags.GATE);
break;
default:
if (stringFlags.containsKey(type.name())) {
Optional<Flag> f = BentoBox.getInstance().getFlagsManager().getFlag(stringFlags.get(type.name()));
f.ifPresent(flag -> checkIsland(e, player, loc, flag));
if (Tag.ANVIL.isTagged(type))
{
this.checkIsland(e, player, loc, Flags.ANVIL);
return;
}
if (Tag.BUTTONS.isTagged(type))
{
this.checkIsland(e, player, loc, Flags.BUTTON);
return;
}
if (Tag.BEDS.isTagged(type))
{
this.checkIsland(e, player, loc, Flags.BED);
return;
}
if (Tag.DOORS.isTagged(type))
{
this.checkIsland(e, player, loc, Flags.DOOR);
return;
}
if (Tag.SHULKER_BOXES.isTagged(type))
{
this.checkIsland(e, player, loc, Flags.SHULKER_BOX);
return;
}
if (Tag.TRAPDOORS.isTagged(type))
{
this.checkIsland(e, player, loc, Flags.TRAPDOOR);
return;
}
if (Tag.FENCE_GATES.isTagged(type))
{
this.checkIsland(e, player, loc, Flags.GATE);
}
// TODO: 1.18 compatibility
// if (Tag.ITEMS_CHEST_BOATS.isTagged(type)) {
// this.checkIsland(e, player, loc, Flags.CHEST);
// }
switch (type)
{
case BEACON -> this.checkIsland(e, player, loc, Flags.BEACON);
case BREWING_STAND -> this.checkIsland(e, player, loc, Flags.BREWING);
case BEEHIVE, BEE_NEST -> this.checkIsland(e, player, loc, Flags.HIVE);
case BARREL -> this.checkIsland(e, player, loc, Flags.BARREL);
case CHEST, CHEST_MINECART -> this.checkIsland(e, player, loc, Flags.CHEST);
case TRAPPED_CHEST -> this.checkIsland(e, player, loc, Flags.TRAPPED_CHEST);
case FLOWER_POT -> this.checkIsland(e, player, loc, Flags.FLOWER_POT);
case COMPOSTER -> this.checkIsland(e, player, loc, Flags.COMPOSTER);
case DISPENSER -> this.checkIsland(e, player, loc, Flags.DISPENSER);
case DROPPER -> this.checkIsland(e, player, loc, Flags.DROPPER);
case HOPPER, HOPPER_MINECART -> this.checkIsland(e, player, loc, Flags.HOPPER);
case BLAST_FURNACE, CAMPFIRE, FURNACE_MINECART, FURNACE, SMOKER ->
this.checkIsland(e, player, loc, Flags.FURNACE);
case ENCHANTING_TABLE -> this.checkIsland(e, player, loc, Flags.ENCHANTING);
case ENDER_CHEST -> this.checkIsland(e, player, loc, Flags.ENDER_CHEST);
case JUKEBOX -> this.checkIsland(e, player, loc, Flags.JUKEBOX);
case NOTE_BLOCK -> this.checkIsland(e, player, loc, Flags.NOTE_BLOCK);
case CRAFTING_TABLE, CARTOGRAPHY_TABLE, GRINDSTONE, STONECUTTER, LOOM ->
this.checkIsland(e, player, loc, Flags.CRAFTING);
case LEVER -> this.checkIsland(e, player, loc, Flags.LEVER);
case REDSTONE_WIRE, REPEATER, COMPARATOR, DAYLIGHT_DETECTOR -> this.checkIsland(e, player, loc, Flags.REDSTONE);
case DRAGON_EGG -> this.checkIsland(e, player, loc, Flags.DRAGON_EGG);
case END_PORTAL_FRAME, RESPAWN_ANCHOR -> this.checkIsland(e, player, loc, Flags.PLACE_BLOCKS);
case GLOW_ITEM_FRAME, ITEM_FRAME -> this.checkIsland(e, player, loc, Flags.ITEM_FRAME);
case SWEET_BERRY_BUSH -> this.checkIsland(e, player, loc, Flags.BREAK_BLOCKS);
case CAKE -> this.checkIsland(e, player, loc, Flags.CAKE);
case LAVA_CAULDRON ->
{
if (BlockInteractionListener.holds(player, Material.BUCKET))
{
this.checkIsland(e, player, loc, Flags.COLLECT_LAVA);
}
}
case WATER_CAULDRON ->
{
if (BlockInteractionListener.holds(player, Material.BUCKET))
{
this.checkIsland(e, player, loc, Flags.COLLECT_WATER);
}
else if (BlockInteractionListener.holds(player, Material.GLASS_BOTTLE) ||
BlockInteractionListener.holds(player, Material.POTION))
{
this.checkIsland(e, player, loc, Flags.BREWING);
}
}
case POWDER_SNOW_CAULDRON ->
{
if (BlockInteractionListener.holds(player, Material.BUCKET))
{
this.checkIsland(e, player, loc, Flags.COLLECT_POWDERED_SNOW);
}
}
case CAULDRON ->
{
if (BlockInteractionListener.holds(player, Material.WATER_BUCKET) ||
BlockInteractionListener.holds(player, Material.LAVA_BUCKET) ||
BlockInteractionListener.holds(player, Material.POWDER_SNOW_BUCKET))
{
this.checkIsland(e, player, loc, Flags.BUCKET);
}
else if (BlockInteractionListener.holds(player, Material.POTION))
{
this.checkIsland(e, player, loc, Flags.BREWING);
}
}
default ->
{
if (stringFlags.containsKey(type.name()))
{
Optional<Flag> f = BentoBox.getInstance().getFlagsManager().getFlag(stringFlags.get(type.name()));
f.ifPresent(flag -> this.checkIsland(e, player, loc, flag));
}
}
}
}
/**
* When breaking blocks is allowed, this protects
* specific blocks from being broken, which would bypass the protection.
* For example, player enables break blocks, but chests are still protected
* Fires after the BreakBlocks check.
* When breaking blocks is allowed, this protects specific blocks from being broken, which would bypass the
* protection. For example, player enables break blocks, but chests are still protected Fires after the BreakBlocks
* check.
*
* @param e - event
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onBlockBreak(final BlockBreakEvent e) {
checkClickedBlock(e, e.getPlayer(), e.getBlock().getLocation(), e.getBlock().getType());
public void onBlockBreak(final BlockBreakEvent e)
{
this.checkClickedBlock(e, e.getPlayer(), e.getBlock().getLocation(), e.getBlock().getType());
}
/**
* Prevents dragon eggs from flying out of an island's protected space
*
* @param e - event
*/
@EventHandler(priority = EventPriority.LOWEST)
public void onDragonEggTeleport(BlockFromToEvent e) {
public void onDragonEggTeleport(BlockFromToEvent e)
{
Block block = e.getBlock();
if (!block.getType().equals(Material.DRAGON_EGG) || !getIWM().inWorld(block.getLocation())) {
if (!block.getType().equals(Material.DRAGON_EGG) || !this.getIWM().inWorld(block.getLocation()))
{
return;
}
// If egg starts in a protected island...
// Cancel if toIsland is not fromIsland or if there is no protected island there
// This protects against eggs dropping into adjacent islands, e.g. island distance and protection range are equal
Optional<Island> fromIsland = getIslands().getProtectedIslandAt(block.getLocation());
Optional<Island> toIsland = getIslands().getProtectedIslandAt(e.getToBlock().getLocation());
Optional<Island> fromIsland = this.getIslands().getProtectedIslandAt(block.getLocation());
Optional<Island> toIsland = this.getIslands().getProtectedIslandAt(e.getToBlock().getLocation());
fromIsland.ifPresent(from -> e.setCancelled(toIsland.map(to -> to != from).orElse(true)));
}
}
/**
* This method returns if player is holding given material in main or offhand.
* @param player Player that must be checked.
* @param material item that mus t be checjed.
* @return {@code true} if player is holding item in main hand or offhand.
*/
private static boolean holds(Player player, Material material)
{
return player.getInventory().getItemInMainHand().getType().equals(material) ||
player.getInventory().getItemInOffHand().getType().equals(material);
}
}

View File

@ -58,19 +58,23 @@ public class BreakBlocksListener extends FlagListener {
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerInteract(final PlayerInteractEvent e) {
public void onPlayerInteract(final PlayerInteractEvent e)
{
// Only handle hitting things
if (!e.getAction().equals(Action.LEFT_CLICK_BLOCK)) {
if (!e.getAction().equals(Action.LEFT_CLICK_BLOCK) || e.getClickedBlock() == null)
{
return;
}
Player p = e.getPlayer();
Location l = e.getClickedBlock().getLocation();
switch (e.getClickedBlock().getType()) {
case CAKE -> checkIsland(e, p, l, Flags.BREAK_BLOCKS);
case SPAWNER -> checkIsland(e, p, l, Flags.BREAK_SPAWNERS);
case DRAGON_EGG -> checkIsland(e, p, l, Flags.DRAGON_EGG);
case HOPPER -> checkIsland(e, p, l, Flags.BREAK_HOPPERS);
default -> {}
switch (e.getClickedBlock().getType())
{
case CAKE -> this.checkIsland(e, p, l, Flags.BREAK_BLOCKS);
case SPAWNER -> this.checkIsland(e, p, l, Flags.BREAK_SPAWNERS);
case DRAGON_EGG -> this.checkIsland(e, p, l, Flags.DRAGON_EGG);
case HOPPER -> this.checkIsland(e, p, l, Flags.BREAK_HOPPERS);
}
}
@ -79,16 +83,26 @@ public class BreakBlocksListener extends FlagListener {
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled=true)
public void onVehicleDamageEvent(VehicleDamageEvent e) {
public void onVehicleDamageEvent(VehicleDamageEvent e)
{
Location l = e.getVehicle().getLocation();
if (getIWM().inWorld(l) && e.getAttacker() instanceof Player p) {
String vehicleType = e.getVehicle().getType().toString();
if (e.getVehicle().getType().equals(EntityType.BOAT)) {
checkIsland(e, p, l, Flags.BOAT);
} else if (vehicleType.contains("MINECART")) {
checkIsland(e, p, l, Flags.MINECART);
} else {
checkIsland(e, p, l, Flags.BREAK_BLOCKS);
if (getIWM().inWorld(l) && e.getAttacker() instanceof Player p)
{
String vehicleType = e.getVehicle().getType().name();
// 1.19 introduced Chest Boat.
if (vehicleType.contains("BOAT"))
{
this.checkIsland(e, p, l, Flags.BOAT);
}
else if (vehicleType.contains("MINECART"))
{
this.checkIsland(e, p, l, Flags.MINECART);
}
else
{
this.checkIsland(e, p, l, Flags.BREAK_BLOCKS);
}
}
}

View File

@ -56,16 +56,27 @@ public class BreedingListener extends FlagListener {
bi.put(EntityType.TURTLE, Collections.singletonList(Material.SEAGRASS));
bi.put(EntityType.PANDA, Collections.singletonList(Material.BAMBOO));
bi.put(EntityType.FOX, Collections.singletonList(Material.SWEET_BERRIES));
if (Enums.getIfPresent(EntityType.class, "BEES").isPresent()) { // 1.15.2
bi.put(EntityType.BEE, Arrays.asList(Material.SUNFLOWER, Material.ORANGE_TULIP, Material.PINK_TULIP,
Material.RED_TULIP, Material.WHITE_TULIP, Material.ALLIUM,
Material.AZURE_BLUET, Material.BLUE_ORCHID, Material.CORNFLOWER,
Material.DANDELION, Material.OXEYE_DAISY, Material.PEONY, Material.POPPY));
}
if (Enums.getIfPresent(EntityType.class, "HOGLIN").isPresent()) {
bi.put(EntityType.HOGLIN, Collections.singletonList(Material.CRIMSON_FUNGUS)); // 1.16.1
bi.put(EntityType.STRIDER, Collections.singletonList(Material.WARPED_FUNGUS)); // 1.16.1
// 1.15+
bi.put(EntityType.BEE, Arrays.asList(Material.SUNFLOWER, Material.ORANGE_TULIP, Material.PINK_TULIP,
Material.RED_TULIP, Material.WHITE_TULIP, Material.ALLIUM,
Material.AZURE_BLUET, Material.BLUE_ORCHID, Material.CORNFLOWER,
Material.DANDELION, Material.OXEYE_DAISY, Material.PEONY, Material.POPPY));
// 1.16+
bi.put(EntityType.HOGLIN, Collections.singletonList(Material.CRIMSON_FUNGUS));
bi.put(EntityType.STRIDER, Collections.singletonList(Material.WARPED_FUNGUS));
// 1.18+
bi.put(EntityType.AXOLOTL, Collections.singletonList(Material.TROPICAL_FISH_BUCKET));
bi.put(EntityType.GOAT, Collections.singletonList(Material.WHEAT));
// 1.19+
// TODO: remove one 1.18 is dropped.
if (Enums.getIfPresent(EntityType.class, "FROG").isPresent()) {
bi.put(EntityType.FROG, Collections.singletonList(Material.SLIME_BALL));
bi.put(EntityType.ALLAY, Collections.singletonList(Material.AMETHYST_SHARD));
}
// Helper
// if (Enums.getIfPresent(EntityType.class, "<name>").isPresent()) {
// bi.put(EntityType.<type>, Collections.singletonList(Material.<material>));
// }
BREEDING_ITEMS = Collections.unmodifiableMap(bi);
}

View File

@ -3,9 +3,10 @@ package world.bentobox.bentobox.listeners.flags.protection;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Axolotl;
import org.bukkit.entity.Fish;
import org.bukkit.entity.MushroomCow;
import org.bukkit.entity.Player;
import org.bukkit.entity.TropicalFish;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerBucketEmptyEvent;
@ -31,7 +32,7 @@ public class BucketListener extends FlagListener {
public void onBucketEmpty(final PlayerBucketEmptyEvent e) {
// This is where the water or lava actually will be dumped
Block dumpBlock = e.getBlockClicked().getRelative(e.getBlockFace());
checkIsland(e, e.getPlayer(), dumpBlock.getLocation(), Flags.BUCKET);
this.checkIsland(e, e.getPlayer(), dumpBlock.getLocation(), Flags.BUCKET);
}
/**
@ -42,19 +43,35 @@ public class BucketListener extends FlagListener {
public void onBucketFill(final PlayerBucketFillEvent e) {
Player p = e.getPlayer();
Location l = e.getBlockClicked().getLocation();
if (e.getItemStack() == null)
{
// Null-pointer check.
return;
}
// Check filling of various liquids
switch (e.getItemStack().getType()) {
case LAVA_BUCKET -> checkIsland(e, p, l, Flags.COLLECT_LAVA);
case WATER_BUCKET -> checkIsland(e, p, l, Flags.COLLECT_WATER);
case MILK_BUCKET -> checkIsland(e, p, l, Flags.MILKING);
default -> checkIsland(e, p, l, Flags.BUCKET);
switch (e.getItemStack().getType())
{
case LAVA_BUCKET -> this.checkIsland(e, p, l, Flags.COLLECT_LAVA);
case WATER_BUCKET -> this.checkIsland(e, p, l, Flags.COLLECT_WATER);
case POWDER_SNOW_BUCKET -> this.checkIsland(e, p, l, Flags.COLLECT_POWDERED_SNOW);
case MILK_BUCKET -> this.checkIsland(e, p, l, Flags.MILKING);
default -> this.checkIsland(e, p, l, Flags.BUCKET);
}
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onTropicalFishScooping(final PlayerInteractEntityEvent e) {
if (e.getRightClicked() instanceof TropicalFish && e.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.WATER_BUCKET)) {
checkIsland(e, e.getPlayer(), e.getRightClicked().getLocation(), Flags.FISH_SCOOPING);
if (e.getRightClicked() instanceof Fish &&
e.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.WATER_BUCKET))
{
this.checkIsland(e, e.getPlayer(), e.getRightClicked().getLocation(), Flags.FISH_SCOOPING);
}
else if (e.getRightClicked() instanceof Axolotl &&
e.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.WATER_BUCKET))
{
this.checkIsland(e, e.getPlayer(), e.getRightClicked().getLocation(), Flags.AXOLOTL_SCOOPING);
}
}

View File

@ -1,10 +1,10 @@
package world.bentobox.bentobox.listeners.flags.protection;
import org.bukkit.entity.EntityType;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.entity.SheepDyeWoolEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import world.bentobox.bentobox.api.flags.FlagListener;
@ -22,24 +22,35 @@ public class DyeListener extends FlagListener {
* @param e - event
*/
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerInteract(final PlayerInteractEvent e) {
if (e.getClickedBlock() == null || e.getItem() == null) {
public void onPlayerInteract(final PlayerInteractEvent e)
{
if (e.getClickedBlock() == null || e.getItem() == null)
{
return;
}
if (e.getAction().equals(Action.RIGHT_CLICK_BLOCK) && e.getClickedBlock().getType().name().contains("SIGN")
&& e.getItem().getType().name().contains("DYE")) {
checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.DYE);
if (e.getAction().equals(Action.RIGHT_CLICK_BLOCK) &&
e.getClickedBlock().getType().name().contains("SIGN") &&
(e.getItem().getType().name().contains("DYE") || e.getItem().getType().equals(Material.GLOW_INK_SAC)))
{
this.checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.DYE);
}
}
/**
* Prevents from interacting with sheep.
* @param e - event
*/
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerInteract(final PlayerInteractEntityEvent e) {
// We cannot use SheepDyeWoolEvent since it doesn't provide who dyed the sheep
if (e.getRightClicked().getType().equals(EntityType.SHEEP)
&& (e.getPlayer().getInventory().getItemInMainHand().getType().name().contains("DYE")
|| e.getPlayer().getInventory().getItemInOffHand().getType().name().contains("DYE"))) {
checkIsland(e, e.getPlayer(), e.getRightClicked().getLocation(), Flags.DYE);
public void onPlayerInteract(final SheepDyeWoolEvent e)
{
if (e.getPlayer() == null)
{
// Sheep is not dyed by the player.
return;
}
this.checkIsland(e, e.getPlayer(), e.getPlayer().getLocation(), Flags.DYE);
}
}

View File

@ -2,13 +2,7 @@ package world.bentobox.bentobox.listeners.flags.protection;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Animals;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Boat;
import org.bukkit.entity.Player;
import org.bukkit.entity.Vehicle;
import org.bukkit.entity.Villager;
import org.bukkit.entity.WanderingTrader;
import org.bukkit.entity.*;
import org.bukkit.entity.minecart.RideableMinecart;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@ -17,6 +11,8 @@ import org.bukkit.event.player.PlayerInteractEntityEvent;
import world.bentobox.bentobox.api.flags.FlagListener;
import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.versions.ServerCompatibility;
/**
* Handles interaction with entities like armor stands
@ -34,34 +30,68 @@ public class EntityInteractListener extends FlagListener {
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerInteractEntity(PlayerInteractEntityEvent e) {
public void onPlayerInteractEntity(PlayerInteractEntityEvent e)
{
Player p = e.getPlayer();
Location l = e.getRightClicked().getLocation();
if (e.getRightClicked() instanceof Vehicle) {
// Animal riding
if (e.getRightClicked() instanceof Animals) {
checkIsland(e, p, l, Flags.RIDING);
if (e.getRightClicked() instanceof Vehicle)
{
if (e.getRightClicked() instanceof Animals)
{
// Animal riding
this.checkIsland(e, p, l, Flags.RIDING);
}
// Minecart riding
else if (e.getRightClicked() instanceof RideableMinecart) {
checkIsland(e, p, l, Flags.MINECART);
else if (e.getRightClicked() instanceof RideableMinecart)
{
// Minecart riding
this.checkIsland(e, p, l, Flags.MINECART);
}
// Boat riding
else if (e.getRightClicked() instanceof Boat) {
checkIsland(e, p, l, Flags.BOAT);
else if (!ServerCompatibility.getInstance().isVersion(
ServerCompatibility.ServerVersion.V1_18,
ServerCompatibility.ServerVersion.V1_18_1,
ServerCompatibility.ServerVersion.V1_18_2) &&
e.getPlayer().isSneaking() && e.getRightClicked() instanceof ChestBoat)
{
// Access to chest boat since 1.19
this.checkIsland(e, p, l, Flags.CHEST);
}
else if (e.getRightClicked() instanceof Boat)
{
// Boat riding
this.checkIsland(e, p, l, Flags.BOAT);
}
}
// Villager trading
else if (e.getRightClicked() instanceof Villager || e.getRightClicked() instanceof WanderingTrader) {
else if (e.getRightClicked() instanceof Villager || e.getRightClicked() instanceof WanderingTrader)
{
// Villager trading
// Check naming and check trading
checkIsland(e, p, l, Flags.TRADING);
if (e.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.NAME_TAG)) {
checkIsland(e, p, l, Flags.NAME_TAG);
this.checkIsland(e, p, l, Flags.TRADING);
if (e.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.NAME_TAG))
{
this.checkIsland(e, p, l, Flags.NAME_TAG);
}
}
// Name tags
else if (e.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.NAME_TAG)) {
checkIsland(e, p, l, Flags.NAME_TAG);
else if (!ServerCompatibility.getInstance().isVersion(
ServerCompatibility.ServerVersion.V1_18,
ServerCompatibility.ServerVersion.V1_18_1,
ServerCompatibility.ServerVersion.V1_18_2) &&
e.getRightClicked() instanceof Allay)
{
// Allay item giving/taking
this.checkIsland(e, p, l, Flags.ALLAY);
// Check naming
if (e.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.NAME_TAG))
{
this.checkIsland(e, p, l, Flags.NAME_TAG);
}
}
else if (e.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.NAME_TAG))
{
// Name tags
this.checkIsland(e, p, l, Flags.NAME_TAG);
}
}
}

View File

@ -14,7 +14,6 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Parrot;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.Villager;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
@ -31,7 +30,6 @@ import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.api.flags.FlagListener;
import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.util.Util;
import world.bentobox.bentobox.versions.ServerCompatibility;
/**
@ -50,17 +48,24 @@ public class HurtingListener extends FlagListener {
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onEntityDamage(final EntityDamageByEntityEvent e) {
public void onEntityDamage(final EntityDamageByEntityEvent e)
{
// Mobs being hurt
if (Util.isPassiveEntity(e.getEntity())) {
respond(e, e.getDamager(), Flags.HURT_ANIMALS);
} else if (e.getEntity() instanceof Villager || e.getEntityType().name().equals("WANDERING_TRADER")) { // TODO: Simplify when 1.13.2 support is dropped
respond(e, e.getDamager(), Flags.HURT_VILLAGERS);
} else if (Util.isHostileEntity(e.getEntity())) {
respond(e, e.getDamager(), Flags.HURT_MONSTERS);
if (Util.isPassiveEntity(e.getEntity()))
{
this.respond(e, e.getDamager(), Flags.HURT_ANIMALS);
}
else if (e.getEntity() instanceof AbstractVillager)
{
this.respond(e, e.getDamager(), Flags.HURT_VILLAGERS);
}
else if (Util.isHostileEntity(e.getEntity()))
{
this.respond(e, e.getDamager(), Flags.HURT_MONSTERS);
}
}
/**
* Finds the true attacker, even if the attack was via a projectile
* @param e - event
@ -159,12 +164,6 @@ public class HurtingListener extends FlagListener {
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled=true)
public void onLingeringPotionSplash(final LingeringPotionSplashEvent e) {
// TODO Switch this to 1.13 when we move to 1.14 officially
if (!ServerCompatibility.getInstance().isVersion(ServerCompatibility.ServerVersion.V1_14, ServerCompatibility.ServerVersion.V1_14_1)) {
// We're disabling this check for non-1.14 servers.
return;
}
// Try to get the shooter
Projectile projectile = e.getEntity();
if (projectile.getShooter() instanceof Player) {

View File

@ -13,6 +13,7 @@ import org.bukkit.block.Furnace;
import org.bukkit.block.Hopper;
import org.bukkit.block.ShulkerBox;
import org.bukkit.entity.Animals;
import org.bukkit.entity.ChestBoat;
import org.bukkit.entity.NPC;
import org.bukkit.entity.Player;
import org.bukkit.entity.minecart.HopperMinecart;
@ -20,83 +21,146 @@ import org.bukkit.entity.minecart.StorageMinecart;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.inventory.InventoryHolder;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.flags.FlagListener;
import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.versions.ServerCompatibility;
/**
* Handles inventory protection
* @author tastybento
*/
public class InventoryListener extends FlagListener {
public class InventoryListener extends FlagListener
{
/**
* Prevents players opening inventories
* @param event - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled=true)
public void onInventoryOpen(InventoryOpenEvent event)
{
InventoryHolder inventoryHolder = event.getInventory().getHolder();
if (inventoryHolder == null || !(event.getPlayer() instanceof Player player))
{
return;
}
if (inventoryHolder instanceof Animals)
{
// Prevent opening animal inventories.
this.checkIsland(event, player, event.getInventory().getLocation(), Flags.MOUNT_INVENTORY);
}
else if (!ServerCompatibility.getInstance().isVersion(ServerCompatibility.ServerVersion.V1_18,
ServerCompatibility.ServerVersion.V1_18_1,
ServerCompatibility.ServerVersion.V1_18_2) &&
inventoryHolder instanceof ChestBoat)
{
// Prevent opening chest inventories
this.checkIsland(event, player, event.getInventory().getLocation(), Flags.CHEST);
}
}
/**
* Prevents players picking items from inventories
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled=true)
public void onInventoryClick(InventoryClickEvent e) {
Player player = (Player)e.getWhoClicked();
public void onInventoryClick(InventoryClickEvent e)
{
Player player = (Player) e.getWhoClicked();
InventoryHolder inventoryHolder = e.getInventory().getHolder();
if (inventoryHolder == null || !(e.getWhoClicked() instanceof Player)) {
if (inventoryHolder == null || !(e.getWhoClicked() instanceof Player))
{
return;
}
if (inventoryHolder instanceof Animals) {
checkIsland(e, player, e.getInventory().getLocation(), Flags.MOUNT_INVENTORY);
if (inventoryHolder instanceof Animals)
{
this.checkIsland(e, player, e.getInventory().getLocation(), Flags.MOUNT_INVENTORY);
}
else if (inventoryHolder instanceof Dispenser) {
checkIsland(e, player, e.getInventory().getLocation(), Flags.DISPENSER);
else if (inventoryHolder instanceof Dispenser)
{
this.checkIsland(e, player, e.getInventory().getLocation(), Flags.DISPENSER);
}
else if (inventoryHolder instanceof Dropper) {
checkIsland(e, player, e.getInventory().getLocation(), Flags.DROPPER);
else if (inventoryHolder instanceof Dropper)
{
this.checkIsland(e, player, e.getInventory().getLocation(), Flags.DROPPER);
}
else if (inventoryHolder instanceof Hopper
|| inventoryHolder instanceof HopperMinecart) {
checkIsland(e, player, e.getInventory().getLocation(), Flags.HOPPER);
else if (inventoryHolder instanceof Hopper || inventoryHolder instanceof HopperMinecart)
{
this.checkIsland(e, player, e.getInventory().getLocation(), Flags.HOPPER);
}
else if (inventoryHolder instanceof Furnace) {
checkIsland(e, player, e.getInventory().getLocation(), Flags.FURNACE);
else if (inventoryHolder instanceof Furnace)
{
this.checkIsland(e, player, e.getInventory().getLocation(), Flags.FURNACE);
}
else if (inventoryHolder instanceof BrewingStand) {
checkIsland(e, player, e.getInventory().getLocation(), Flags.BREWING);
else if (inventoryHolder instanceof BrewingStand)
{
this.checkIsland(e, player, e.getInventory().getLocation(), Flags.BREWING);
}
else if (inventoryHolder instanceof Beacon) {
checkIsland(e, player, e.getInventory().getLocation(), Flags.BEACON);
else if (inventoryHolder instanceof Beacon)
{
this.checkIsland(e, player, e.getInventory().getLocation(), Flags.BEACON);
}
else if (inventoryHolder instanceof NPC) {
checkIsland(e, player, e.getInventory().getLocation(), Flags.TRADING);
else if (inventoryHolder instanceof NPC)
{
this.checkIsland(e, player, e.getInventory().getLocation(), Flags.TRADING);
}
else if (inventoryHolder instanceof Barrel) {
checkIsland(e, player, e.getInventory().getLocation(), Flags.BARREL);
else if (inventoryHolder instanceof Barrel)
{
this.checkIsland(e, player, e.getInventory().getLocation(), Flags.BARREL);
}
else if (inventoryHolder instanceof ShulkerBox) {
checkIsland(e, player, e.getInventory().getLocation(), Flags.SHULKER_BOX);
else if (inventoryHolder instanceof ShulkerBox)
{
this.checkIsland(e, player, e.getInventory().getLocation(), Flags.SHULKER_BOX);
}
else if (inventoryHolder instanceof Chest c) {
checkInvHolder(c.getLocation(), e, player);
else if (inventoryHolder instanceof Chest c)
{
this.checkInvHolder(c.getLocation(), e, player);
}
else if (inventoryHolder instanceof DoubleChest dc) {
checkInvHolder(dc.getLocation(), e, player);
else if (inventoryHolder instanceof DoubleChest dc)
{
this.checkInvHolder(dc.getLocation(), e, player);
}
else if (inventoryHolder instanceof StorageMinecart) {
checkIsland(e, player, e.getInventory().getLocation(), Flags.CHEST);
else if (inventoryHolder instanceof StorageMinecart)
{
this.checkIsland(e, player, e.getInventory().getLocation(), Flags.CHEST);
}
else if (!(inventoryHolder instanceof Player)) {
else if (!ServerCompatibility.getInstance().isVersion(ServerCompatibility.ServerVersion.V1_18, ServerCompatibility.ServerVersion.V1_18_1, ServerCompatibility.ServerVersion.V1_18_2) &&
inventoryHolder instanceof ChestBoat)
{
// TODO: 1.19 added chest boat. Remove compatibility check when 1.18 is dropped.
this.checkIsland(e, player, e.getInventory().getLocation(), Flags.CHEST);
}
else if (!(inventoryHolder instanceof Player))
{
// All other containers
checkIsland(e, player, e.getInventory().getLocation(), Flags.CONTAINER);
this.checkIsland(e, player, e.getInventory().getLocation(), Flags.CONTAINER);
}
}
private void checkInvHolder(Location l, InventoryClickEvent e, Player player) {
if (l.getBlock().getType().equals(Material.TRAPPED_CHEST)) {
checkIsland(e, player, l, Flags.TRAPPED_CHEST);
} else {
checkIsland(e, player, l, Flags.CHEST);
/**
* This method runs check based on clicked chest type.
* @param l location of chest.
* @param e click event.
* @param player player who clicked.
*/
private void checkInvHolder(Location l, InventoryClickEvent e, Player player)
{
if (l.getBlock().getType().equals(Material.TRAPPED_CHEST))
{
this.checkIsland(e, player, l, Flags.TRAPPED_CHEST);
}
else
{
this.checkIsland(e, player, l, Flags.CHEST);
}
}
}

View File

@ -104,22 +104,31 @@ public class LockAndBanListener extends FlagListener {
* @param loc - location to check
* @return CheckResult LOCKED, BANNED or OPEN. If an island is locked, that will take priority over banned
*/
private CheckResult check(@NonNull Player player, Location loc) {
private CheckResult check(@NonNull Player player, Location loc)
{
// Ops or NPC's are allowed everywhere
if (player.isOp() || player.hasMetadata("NPC")) {
if (player.isOp() || player.hasMetadata("NPC"))
{
return CheckResult.OPEN;
}
// See if the island is locked to non-members or player is banned
return getIslands().getProtectedIslandAt(loc)
.map(is -> {
if (is.isBanned(player.getUniqueId())) {
return player.hasPermission(getIWM().getPermissionPrefix(loc.getWorld()) + "mod.bypassban") ? CheckResult.OPEN : CheckResult.BANNED;
}
if (!is.isAllowed(User.getInstance(player), Flags.LOCK)) {
return player.hasPermission(getIWM().getPermissionPrefix(loc.getWorld()) + "mod.bypasslock") ? CheckResult.OPEN : CheckResult.LOCKED;
}
return CheckResult.OPEN;
}).orElse(CheckResult.OPEN);
return this.getIslands().getProtectedIslandAt(loc).
map(is ->
{
if (is.isBanned(player.getUniqueId()))
{
return player.hasPermission(getIWM().getPermissionPrefix(loc.getWorld()) + "mod.bypassban") ?
CheckResult.OPEN : CheckResult.BANNED;
}
if (!is.isAllowed(User.getInstance(player), Flags.LOCK))
{
return player.hasPermission(getIWM().getPermissionPrefix(loc.getWorld()) + "mod.bypasslock") ?
CheckResult.OPEN : CheckResult.LOCKED;
}
return CheckResult.OPEN;
}).
orElse(CheckResult.OPEN);
}
/**
@ -128,19 +137,17 @@ public class LockAndBanListener extends FlagListener {
* @param loc - location to check
* @return true if banned
*/
private CheckResult checkAndNotify(@NonNull Player player, Location loc) {
CheckResult r = check(player,loc);
switch (r) {
case BANNED:
User.getInstance(player).notify("commands.island.ban.you-are-banned");
break;
case LOCKED:
User.getInstance(player).notify("protection.locked");
break;
default:
break;
private CheckResult checkAndNotify(@NonNull Player player, Location loc)
{
CheckResult result = this.check(player, loc);
switch (result)
{
case BANNED -> User.getInstance(player).notify("commands.island.ban.you-are-banned");
case LOCKED -> User.getInstance(player).notify("protection.locked");
}
return r;
return result;
}
/**

View File

@ -13,67 +13,66 @@ import org.bukkit.event.player.PlayerInteractEvent;
import world.bentobox.bentobox.api.flags.FlagListener;
import world.bentobox.bentobox.lists.Flags;
/**
* @author tastybento
*
*/
public class PhysicalInteractionListener extends FlagListener {
public class PhysicalInteractionListener extends FlagListener
{
/**
* Handle physical interaction with blocks
* Crop trample, pressure plates, triggering redstone, tripwires
* @param e - event
*/
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerInteract(PlayerInteractEvent e) {
if (!e.getAction().equals(Action.PHYSICAL)) {
public void onPlayerInteract(PlayerInteractEvent e)
{
if (!e.getAction().equals(Action.PHYSICAL) || e.getClickedBlock() == null)
{
return;
}
if (isPressurePlate(e.getClickedBlock().getType())) {
if (Tag.PRESSURE_PLATES.isTagged(e.getClickedBlock().getType()))
{
// Pressure plates
checkIsland(e, e.getPlayer(), e.getPlayer().getLocation(), Flags.PRESSURE_PLATE);
this.checkIsland(e, e.getPlayer(), e.getPlayer().getLocation(), Flags.PRESSURE_PLATE);
return;
}
switch (e.getClickedBlock().getType()) {
case FARMLAND:
// Crop trample
checkIsland(e, e.getPlayer(), e.getPlayer().getLocation(), Flags.CROP_TRAMPLE);
break;
case TURTLE_EGG:
checkIsland(e, e.getPlayer(), e.getPlayer().getLocation(), Flags.TURTLE_EGGS);
break;
default:
break;
switch (e.getClickedBlock().getType())
{
case FARMLAND -> this.checkIsland(e, e.getPlayer(), e.getPlayer().getLocation(), Flags.CROP_TRAMPLE);
case TURTLE_EGG -> this.checkIsland(e, e.getPlayer(), e.getPlayer().getLocation(), Flags.TURTLE_EGGS);
}
}
/**
* Protects buttons and plates from being activated by projectiles
* @param e - event
*/
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onProjectileHit(EntityInteractEvent e) {
if (!(e.getEntity() instanceof Projectile p)) {
public void onProjectileHit(EntityInteractEvent e)
{
if (!(e.getEntity() instanceof Projectile p))
{
return;
}
if (p.getShooter() instanceof Player) {
if (Tag.WOODEN_BUTTONS.isTagged(e.getBlock().getType())) {
checkIsland(e, (Player)p.getShooter(), e.getBlock().getLocation(), Flags.BUTTON);
if (p.getShooter() instanceof Player)
{
if (Tag.WOODEN_BUTTONS.isTagged(e.getBlock().getType()))
{
this.checkIsland(e, (Player) p.getShooter(), e.getBlock().getLocation(), Flags.BUTTON);
return;
}
if (isPressurePlate(e.getBlock().getType())) {
if (Tag.PRESSURE_PLATES.isTagged(e.getBlock().getType()))
{
// Pressure plates
checkIsland(e, (Player)p.getShooter(), e.getBlock().getLocation(), Flags.PRESSURE_PLATE);
this.checkIsland(e, (Player) p.getShooter(), e.getBlock().getLocation(), Flags.PRESSURE_PLATE);
}
}
}
private boolean isPressurePlate(Material material) {
return switch (material) {
case STONE_PRESSURE_PLATE, POLISHED_BLACKSTONE_PRESSURE_PLATE, ACACIA_PRESSURE_PLATE, BIRCH_PRESSURE_PLATE, CRIMSON_PRESSURE_PLATE, DARK_OAK_PRESSURE_PLATE, HEAVY_WEIGHTED_PRESSURE_PLATE, JUNGLE_PRESSURE_PLATE, LIGHT_WEIGHTED_PRESSURE_PLATE, OAK_PRESSURE_PLATE, SPRUCE_PRESSURE_PLATE, WARPED_PRESSURE_PLATE -> true;
default -> false;
};
}
}

View File

@ -18,95 +18,126 @@ import world.bentobox.bentobox.lists.Flags;
/**
* @author tastybento
*/
public class PlaceBlocksListener extends FlagListener {
public class PlaceBlocksListener extends FlagListener
{
/**
* Check blocks being placed in general
*
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onBlockPlace(final BlockPlaceEvent e) {
if (e.getBlock().getType().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)) {
public void onBlockPlace(final BlockPlaceEvent e)
{
if (e.getBlock().getType().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))
{
// Books can only be placed on lecterns and as such are protected by the LECTERN flag.
return;
}
checkIsland(e, e.getPlayer(), e.getBlock().getLocation(), Flags.PLACE_BLOCKS);
this.checkIsland(e, e.getPlayer(), e.getBlock().getLocation(), Flags.PLACE_BLOCKS);
}
/**
* Check for paintings and other hanging placements
*
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onHangingPlace(final HangingPlaceEvent e) {
checkIsland(e, e.getPlayer(), e.getBlock().getLocation(), Flags.PLACE_BLOCKS);
public void onHangingPlace(final HangingPlaceEvent e)
{
this.checkIsland(e, e.getPlayer(), e.getBlock().getLocation(), Flags.PLACE_BLOCKS);
}
/**
* Handles placing items into ItemFrames
*
* @param e - event
*/
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerHitItemFrame(PlayerInteractEntityEvent e) {
if (e.getRightClicked().getType().equals(EntityType.ITEM_FRAME) || e.getRightClicked().getType().equals(EntityType.GLOW_ITEM_FRAME)) {
if (!checkIsland(e, e.getPlayer(), e.getRightClicked().getLocation(), Flags.PLACE_BLOCKS)) return;
checkIsland(e, e.getPlayer(), e.getRightClicked().getLocation(), Flags.ITEM_FRAME);
public void onPlayerHitItemFrame(PlayerInteractEntityEvent e)
{
if (e.getRightClicked().getType().equals(EntityType.ITEM_FRAME) ||
e.getRightClicked().getType().equals(EntityType.GLOW_ITEM_FRAME))
{
if (!this.checkIsland(e, e.getPlayer(), e.getRightClicked().getLocation(), Flags.PLACE_BLOCKS))
{
return;
}
this.checkIsland(e, e.getPlayer(), e.getRightClicked().getLocation(), Flags.ITEM_FRAME);
}
}
/**
* Handle placing of fireworks, item frames, mine carts, end crystals, chests and boats on land
* The doors and chests are related to an exploit.
* Handle placing of fireworks, item frames, mine carts, end crystals, chests and boats on land The doors and chests
* are related to an exploit.
*
* @param e - event
*/
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerInteract(final PlayerInteractEvent e) {
if (!e.getAction().equals(Action.RIGHT_CLICK_BLOCK) || e.getClickedBlock() == null) {
public void onPlayerInteract(final PlayerInteractEvent e)
{
if (!e.getAction().equals(Action.RIGHT_CLICK_BLOCK) || e.getClickedBlock() == null)
{
return;
}
switch (e.getClickedBlock().getType()) {
case FIREWORK_ROCKET:
checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.PLACE_BLOCKS);
return;
case RAIL:
case POWERED_RAIL:
case DETECTOR_RAIL:
case ACTIVATOR_RAIL:
if ((e.getMaterial() == Material.MINECART || e.getMaterial() == Material.CHEST_MINECART || e.getMaterial() == Material.HOPPER_MINECART
|| e.getMaterial() == Material.TNT_MINECART || e.getMaterial() == Material.FURNACE_MINECART)) {
checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.MINECART);
switch (e.getClickedBlock().getType())
{
case FIREWORK_ROCKET ->
{
this.checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.PLACE_BLOCKS);
}
return;
default:
// Check in-hand items
if (e.getMaterial().equals(Material.FIREWORK_ROCKET)
|| e.getMaterial().equals(Material.ARMOR_STAND)
|| e.getMaterial().equals(Material.END_CRYSTAL)
|| e.getMaterial().equals(Material.ITEM_FRAME)
//|| Tag.DOORS.isTagged(e.getMaterial())
|| e.getMaterial().equals(Material.CHEST)
|| e.getMaterial().equals(Material.TRAPPED_CHEST)) {
checkIsland(e, e.getPlayer(), e.getPlayer().getLocation(), Flags.PLACE_BLOCKS);
case RAIL, POWERED_RAIL, DETECTOR_RAIL, ACTIVATOR_RAIL ->
{
if (e.getMaterial() == Material.MINECART ||
e.getMaterial() == Material.CHEST_MINECART ||
e.getMaterial() == Material.HOPPER_MINECART ||
e.getMaterial() == Material.TNT_MINECART ||
e.getMaterial() == Material.FURNACE_MINECART)
{
this.checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.MINECART);
}
}
else if (e.getMaterial().name().contains("BOAT")) {
checkIsland(e, e.getPlayer(), e.getPlayer().getLocation(), Flags.BOAT);
default ->
{
// Check in-hand items
if (e.getMaterial() == Material.FIREWORK_ROCKET ||
e.getMaterial() == Material.ARMOR_STAND ||
e.getMaterial() == Material.END_CRYSTAL ||
e.getMaterial() == Material.ITEM_FRAME ||
e.getMaterial() == Material.GLOW_ITEM_FRAME ||
e.getMaterial() == Material.CHEST ||
e.getMaterial() == Material.TRAPPED_CHEST)
{
this.checkIsland(e, e.getPlayer(), e.getPlayer().getLocation(), Flags.PLACE_BLOCKS);
}
else if (e.getMaterial().name().contains("BOAT"))
{
this.checkIsland(e, e.getPlayer(), e.getPlayer().getLocation(), Flags.BOAT);
}
}
}
}
/**
* Handles Frost Walking on visitor's islands. This creates ice blocks, which is like placing blocks
*
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled=true)
public void onBlockForm(EntityBlockFormEvent e) {
if (e.getNewState().getType().equals(Material.FROSTED_ICE) && e.getEntity() instanceof Player) {
checkIsland(e, (Player)e.getEntity(), e.getBlock().getLocation(), Flags.FROST_WALKER);
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onBlockForm(EntityBlockFormEvent e)
{
if (e.getNewState().getType().equals(Material.FROSTED_ICE) && e.getEntity() instanceof Player)
{
this.checkIsland(e, (Player) e.getEntity(), e.getBlock().getLocation(), Flags.FROST_WALKER);
}
}
}

View File

@ -0,0 +1,53 @@
//
// Created by BONNe
// Copyright - 2022
//
package world.bentobox.bentobox.listeners.flags.protection;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockReceiveGameEvent;
import world.bentobox.bentobox.api.flags.FlagListener;
import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.versions.ServerCompatibility;
/**
* This method prevents sculk sensor from activation based on protection settings.
*/
public class SculkSensorListener extends FlagListener
{
/**
* This listener detects if a visitor activates sculk sensor, and block it, if required.
* @param event Sculk activation event.
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onSculkSensor(BlockReceiveGameEvent event)
{
if (!this.getIWM().inWorld(event.getBlock().getWorld()))
{
return;
}
if (ServerCompatibility.getInstance().isVersion(ServerCompatibility.ServerVersion.V1_18,
ServerCompatibility.ServerVersion.V1_18_1,
ServerCompatibility.ServerVersion.V1_18_2))
{
// TODO: 1.18 compatibility exit
return;
}
if (event.getBlock().getType() == Material.SCULK_SENSOR &&
event.getEntity() != null &&
event.getEntity() instanceof Player player)
{
this.checkIsland(event, player, event.getBlock().getLocation(), Flags.SCULK_SENSOR, true);
}
}
}

View File

@ -0,0 +1,53 @@
//
// Created by BONNe
// Copyright - 2022
//
package world.bentobox.bentobox.listeners.flags.protection;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockReceiveGameEvent;
import world.bentobox.bentobox.api.flags.FlagListener;
import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.versions.ServerCompatibility;
/**
* This method prevents sculk shrieker from activation based on protection settings.
*/
public class SculkShriekerListener extends FlagListener
{
/**
* This listener detects if a visitor activates sculk sensor, and block it, if required.
* @param event Sculk activation event.
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onSculkShrieker(BlockReceiveGameEvent event)
{
if (!this.getIWM().inWorld(event.getBlock().getWorld()))
{
return;
}
if (ServerCompatibility.getInstance().isVersion(ServerCompatibility.ServerVersion.V1_18,
ServerCompatibility.ServerVersion.V1_18_1,
ServerCompatibility.ServerVersion.V1_18_2))
{
// TODO: 1.18 compatibility exit
return;
}
if (event.getBlock().getType() == Material.SCULK_SHRIEKER &&
event.getEntity() != null &&
event.getEntity() instanceof Player player)
{
this.checkIsland(event, player, event.getBlock().getLocation(), Flags.SCULK_SHRIEKER, true);
}
}
}

View File

@ -19,68 +19,82 @@ import world.bentobox.bentobox.util.Util;
* Handles natural mob spawning.
* @author tastybento
*/
public class MobSpawnListener extends FlagListener {
public class MobSpawnListener extends FlagListener
{
/**
* Prevents mobs spawning naturally
*
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onMobSpawnEvent(CreatureSpawnEvent e)
{
this.onMobSpawn(e);
}
/**
* Prevents mobs spawning naturally
*
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onMobSpawnEvent(CreatureSpawnEvent e) {
onMobSpawn(e);
}
/**
* Prevents mobs spawning naturally
*
* @param e - event
* @return true if cancelled
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
void onMobSpawn(CreatureSpawnEvent e) {
void onMobSpawn(CreatureSpawnEvent e)
{
// If not in the right world, or spawning is not natural return
if (!getIWM().inWorld(e.getEntity().getLocation())) {
if (!this.getIWM().inWorld(e.getEntity().getLocation()))
{
return;
}
switch (e.getSpawnReason()) {
// Natural
case DEFAULT:
case DROWNED:
case JOCKEY:
case LIGHTNING:
case MOUNT:
case NATURAL:
case NETHER_PORTAL:
case OCELOT_BABY:
case PATROL:
case RAID:
case REINFORCEMENTS:
case SILVERFISH_BLOCK:
//case SLIME_SPLIT: messes with slimes from spawners, slime must have previously existed to create another
case TRAP:
case VILLAGE_DEFENSE:
case VILLAGE_INVASION:
boolean cancelNatural = shouldCancel(e.getEntity(), e.getLocation(), Flags.ANIMAL_NATURAL_SPAWN, Flags.MONSTER_NATURAL_SPAWN);
e.setCancelled(cancelNatural);
return;
switch (e.getSpawnReason())
{
// Natural
case DEFAULT, DROWNED, JOCKEY, LIGHTNING, MOUNT, NATURAL, NETHER_PORTAL, OCELOT_BABY, PATROL,
RAID, REINFORCEMENTS, SILVERFISH_BLOCK, TRAP, VILLAGE_DEFENSE, VILLAGE_INVASION ->
{
boolean cancelNatural = this.shouldCancel(e.getEntity(),
e.getLocation(),
Flags.ANIMAL_NATURAL_SPAWN,
Flags.MONSTER_NATURAL_SPAWN);
e.setCancelled(cancelNatural);
}
// Spawners
case SPAWNER:
boolean cancelSpawners = shouldCancel(e.getEntity(), e.getLocation(), Flags.ANIMAL_SPAWNERS_SPAWN, Flags.MONSTER_SPAWNERS_SPAWN);
e.setCancelled(cancelSpawners);
return;
default:
return;
case SPAWNER ->
{
boolean cancelSpawners = this.shouldCancel(e.getEntity(),
e.getLocation(),
Flags.ANIMAL_SPAWNERS_SPAWN,
Flags.MONSTER_SPAWNERS_SPAWN);
e.setCancelled(cancelSpawners);
}
}
}
private boolean shouldCancel(Entity entity, Location loc, Flag animalSpawnFlag, Flag monsterSpawnFlag) {
/**
* This method checks if entity should be cancelled from spawning in given location base on flag values.
* @param entity Entity that is checked.
* @param loc location where entity is spawned.
* @param animalSpawnFlag Animal Spawn Flag.
* @param monsterSpawnFlag Monster Spawn Flag.
* @return {@code true} if flag prevents entity to spawn, {@code false} otherwise.
*/
private boolean shouldCancel(Entity entity, Location loc, Flag animalSpawnFlag, Flag monsterSpawnFlag)
{
Optional<Island> island = getIslands().getIslandAt(loc);
if (Util.isHostileEntity(entity) && !(entity instanceof PufferFish)) {
return island.map(i -> !i.isAllowed(monsterSpawnFlag)).orElseGet(() -> !monsterSpawnFlag.isSetForWorld(entity.getWorld()));
} else if (Util.isPassiveEntity(entity) || entity instanceof PufferFish) {
return island.map(i -> !i.isAllowed(animalSpawnFlag)).orElseGet(() -> !animalSpawnFlag.isSetForWorld(entity.getWorld()));
}
return false;
}
}
if (Util.isHostileEntity(entity) && !(entity instanceof PufferFish))
{
return island.map(i -> !i.isAllowed(monsterSpawnFlag)).
orElseGet(() -> !monsterSpawnFlag.isSetForWorld(entity.getWorld()));
}
else if (Util.isPassiveEntity(entity) || entity instanceof PufferFish)
{
return island.map(i -> !i.isAllowed(animalSpawnFlag)).
orElseGet(() -> !animalSpawnFlag.isSetForWorld(entity.getWorld()));
}
else
{
return false;
}
}
}

View File

@ -1,6 +1,7 @@
package world.bentobox.bentobox.listeners.flags.worldsettings;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityExplodeEvent;
@ -18,12 +19,13 @@ public class ChestDamageListener extends FlagListener {
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onExplosion(final EntityExplodeEvent e) {
if (getIWM().inWorld(e.getLocation()) && !Flags.CHEST_DAMAGE.isSetForWorld(e.getLocation().getWorld())) {
e.blockList().removeIf(b -> b.getType().equals(Material.CHEST)
|| b.getType().equals(Material.TRAPPED_CHEST)
|| b.getType().name().contains("SHULKER_BOX")
);
public void onExplosion(final EntityExplodeEvent e)
{
if (getIWM().inWorld(e.getLocation()) && !Flags.CHEST_DAMAGE.isSetForWorld(e.getLocation().getWorld()))
{
e.blockList().removeIf(b -> b.getType().equals(Material.CHEST) ||
b.getType().equals(Material.TRAPPED_CHEST) ||
Tag.SHULKER_BOXES.isTagged(b.getType()));
}
}
}

View File

@ -12,6 +12,8 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.entity.EntityTargetEvent;
import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
import org.bukkit.event.inventory.ClickType;
import world.bentobox.bentobox.BentoBox;
@ -157,5 +159,28 @@ public class InvincibleVisitorsListener extends FlagListener implements ClickHan
}
/**
* This listener cancels entity targeting a player if he is a visitor, and visitors are immune to entity damage.
* @param e EntityTargetLivingEntityEvent
*/
@EventHandler(priority = EventPriority.HIGHEST)
public void onVisitorTargeting(EntityTargetLivingEntityEvent e)
{
World world = e.getEntity().getWorld();
if (!(e.getTarget() instanceof Player p) ||
!this.getIWM().inWorld(world) ||
e.getTarget().hasMetadata("NPC") ||
this.getIslands().userIsOnIsland(world, User.getInstance(e.getEntity())) ||
this.PVPAllowed(p.getLocation()) ||
e.getReason() == EntityTargetEvent.TargetReason.TARGET_DIED ||
!this.getIWM().getIvSettings(world).contains(DamageCause.ENTITY_ATTACK.name()))
{
return;
}
// Cancel targeting event.
e.setCancelled(true);
}
}

View File

@ -1,5 +1,6 @@
package world.bentobox.bentobox.lists;
import com.google.common.base.Enums;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@ -13,30 +14,7 @@ import world.bentobox.bentobox.api.flags.clicklisteners.CycleClick;
import world.bentobox.bentobox.listeners.flags.clicklisteners.CommandRankClickListener;
import world.bentobox.bentobox.listeners.flags.clicklisteners.GeoLimitClickListener;
import world.bentobox.bentobox.listeners.flags.clicklisteners.MobLimitClickListener;
import world.bentobox.bentobox.listeners.flags.protection.BlockInteractionListener;
import world.bentobox.bentobox.listeners.flags.protection.BreakBlocksListener;
import world.bentobox.bentobox.listeners.flags.protection.BreedingListener;
import world.bentobox.bentobox.listeners.flags.protection.BucketListener;
import world.bentobox.bentobox.listeners.flags.protection.DyeListener;
import world.bentobox.bentobox.listeners.flags.protection.EggListener;
import world.bentobox.bentobox.listeners.flags.protection.ElytraListener;
import world.bentobox.bentobox.listeners.flags.protection.EntityInteractListener;
import world.bentobox.bentobox.listeners.flags.protection.ExperiencePickupListener;
import world.bentobox.bentobox.listeners.flags.protection.FireListener;
import world.bentobox.bentobox.listeners.flags.protection.HurtingListener;
import world.bentobox.bentobox.listeners.flags.protection.InventoryListener;
import world.bentobox.bentobox.listeners.flags.protection.ItemDropPickUpListener;
import world.bentobox.bentobox.listeners.flags.protection.LeashListener;
import world.bentobox.bentobox.listeners.flags.protection.LecternListener;
import world.bentobox.bentobox.listeners.flags.protection.LockAndBanListener;
import world.bentobox.bentobox.listeners.flags.protection.PaperExperiencePickupListener;
import world.bentobox.bentobox.listeners.flags.protection.PhysicalInteractionListener;
import world.bentobox.bentobox.listeners.flags.protection.PlaceBlocksListener;
import world.bentobox.bentobox.listeners.flags.protection.PortalListener;
import world.bentobox.bentobox.listeners.flags.protection.ShearingListener;
import world.bentobox.bentobox.listeners.flags.protection.TNTListener;
import world.bentobox.bentobox.listeners.flags.protection.TeleportationListener;
import world.bentobox.bentobox.listeners.flags.protection.ThrowingListener;
import world.bentobox.bentobox.listeners.flags.protection.*;
import world.bentobox.bentobox.listeners.flags.settings.DecayListener;
import world.bentobox.bentobox.listeners.flags.settings.MobSpawnListener;
import world.bentobox.bentobox.listeners.flags.settings.PVPListener;
@ -174,7 +152,10 @@ public final class Flags {
public static final Flag BOAT = new Flag.Builder("BOAT", Material.OAK_BOAT).mode(Flag.Mode.BASIC).build();
public static final Flag TRADING = new Flag.Builder("TRADING", Material.EMERALD).defaultSetting(true).mode(Flag.Mode.BASIC).build();
public static final Flag NAME_TAG = new Flag.Builder("NAME_TAG", Material.NAME_TAG).mode(Flag.Mode.ADVANCED).build();
/**
* @since 1.21
*/
public static final Flag ALLAY = new Flag.Builder("ALLAY", Material.AMETHYST_SHARD).mode(Flag.Mode.ADVANCED).build();
// Breeding
public static final Flag BREEDING = new Flag.Builder("BREEDING", Material.CARROT).listener(new BreedingListener()).mode(Flag.Mode.ADVANCED).build();
@ -182,8 +163,16 @@ public final class Flags {
public static final Flag BUCKET = new Flag.Builder("BUCKET", Material.BUCKET).listener(new BucketListener()).mode(Flag.Mode.BASIC).build();
public static final Flag COLLECT_LAVA = new Flag.Builder("COLLECT_LAVA", Material.LAVA_BUCKET).build();
public static final Flag COLLECT_WATER = new Flag.Builder("COLLECT_WATER", Material.WATER_BUCKET).mode(Flag.Mode.ADVANCED).build();
/**
* @since 1.21
*/
public static final Flag COLLECT_POWDERED_SNOW = new Flag.Builder("COLLECT_POWDERED_SNOW", Material.POWDER_SNOW_BUCKET).mode(Flag.Mode.ADVANCED).build();
public static final Flag MILKING = new Flag.Builder("MILKING", Material.MILK_BUCKET).mode(Flag.Mode.ADVANCED).build();
public static final Flag FISH_SCOOPING = new Flag.Builder("FISH_SCOOPING", Material.TROPICAL_FISH_BUCKET).build();
/**
* @since 1.21
*/
public static final Flag AXOLOTL_SCOOPING = new Flag.Builder("AXOLOTL_SCOOPING", Material.AXOLOTL_BUCKET).build();
// Chorus Fruit and Enderpearls
public static final Flag CHORUS_FRUIT = new Flag.Builder("CHORUS_FRUIT", Material.CHORUS_FRUIT).listener(new TeleportationListener()).build();
@ -314,6 +303,32 @@ public final class Flags {
.clickHandler(new CycleClick("CHANGE_SETTINGS", RanksManager.MEMBER_RANK, RanksManager.OWNER_RANK))
.mode(Flag.Mode.TOP_ROW).build();
/**
* This flag allows choosing which island member group can activate sculk sensors.
* TODO: Enums#getIfPresent is used to support 1.18
* @since 1.21.0
*/
public static final Flag SCULK_SENSOR = new Flag.Builder("SCULK_SENSOR", Enums.getIfPresent(Material.class, "SCULK_SENSOR").or(Material.BARRIER)).
listener(new SculkSensorListener()).
type(Type.PROTECTION).
defaultSetting(true).
defaultRank(RanksManager.MEMBER_RANK).
clickHandler(new CycleClick("SCULK_SENSOR", RanksManager.VISITOR_RANK, RanksManager.MEMBER_RANK)).
build();
/**
* This flag allows choosing which island member group can activate sculk shrieker.
* TODO: Enums#getIfPresent is used to support 1.18
* @since 1.21.0
*/
public static final Flag SCULK_SHRIEKER = new Flag.Builder("SCULK_SHRIEKER", Enums.getIfPresent(Material.class, "SCULK_SHRIEKER").or(Material.BARRIER)).
listener(new SculkShriekerListener()).
type(Type.PROTECTION).
defaultSetting(true).
defaultRank(RanksManager.MEMBER_RANK).
clickHandler(new CycleClick("SCULK_SHRIEKER", RanksManager.VISITOR_RANK, RanksManager.MEMBER_RANK)).
build();
/*
* Settings flags (not protection flags)
*/

View File

@ -1,10 +1,10 @@
package world.bentobox.bentobox.nms.v1_18_R2;
package world.bentobox.bentobox.nms.v1_19_R1;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData;
import net.minecraft.core.BlockPosition;
import net.minecraft.world.level.World;

View File

@ -25,19 +25,7 @@ import org.bukkit.World.Environment;
import org.bukkit.attribute.Attribute;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Animals;
import org.bukkit.entity.Bat;
import org.bukkit.entity.EnderDragon;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Flying;
import org.bukkit.entity.IronGolem;
import org.bukkit.entity.Monster;
import org.bukkit.entity.Player;
import org.bukkit.entity.PufferFish;
import org.bukkit.entity.Shulker;
import org.bukkit.entity.Slime;
import org.bukkit.entity.Snowman;
import org.bukkit.entity.WaterMob;
import org.bukkit.entity.*;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
@ -49,6 +37,7 @@ import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.nms.PasteHandler;
import world.bentobox.bentobox.nms.WorldRegenerator;
import world.bentobox.bentobox.versions.ServerCompatibility;
/**
@ -356,8 +345,19 @@ public class Util {
// Bat extends Mob
// Most of passive mobs extends Animals
return entity instanceof Animals || entity instanceof IronGolem || entity instanceof Snowman ||
if (ServerCompatibility.getInstance().isVersion(ServerCompatibility.ServerVersion.V1_18,
ServerCompatibility.ServerVersion.V1_18_1,
ServerCompatibility.ServerVersion.V1_18_2))
{
return entity instanceof Animals || entity instanceof IronGolem || entity instanceof Snowman ||
entity instanceof WaterMob && !(entity instanceof PufferFish) || entity instanceof Bat;
}
else
{
return entity instanceof Animals || entity instanceof IronGolem || entity instanceof Snowman ||
entity instanceof WaterMob && !(entity instanceof PufferFish) || entity instanceof Bat ||
entity instanceof Allay;
}
}
/*

View File

@ -176,28 +176,36 @@ public class ServerCompatibility {
/**
* @since 1.16.0
*/
V1_16_5(Compatibility.NOT_SUPPORTED),
V1_16_5(Compatibility.INCOMPATIBLE),
/**
* @since 1.17.0
*/
V1_17(Compatibility.NOT_SUPPORTED),
V1_17(Compatibility.INCOMPATIBLE),
/**
* @since 1.17.1
*/
V1_17_1(Compatibility.SUPPORTED),
V1_17_1(Compatibility.INCOMPATIBLE),
/**
* @since 1.19.0
*/
V1_18(Compatibility.COMPATIBLE),
V1_18(Compatibility.SUPPORTED),
/**
* @since 1.19.0
*/
V1_18_1(Compatibility.COMPATIBLE),
V1_18_1(Compatibility.SUPPORTED),
/**
* @since 1.20.1
*/
V1_18_2(Compatibility.COMPATIBLE),
V1_18_2(Compatibility.SUPPORTED),
/**
* @since 1.21.0
*/
V1_19(Compatibility.COMPATIBLE),
/**
* @since 1.21.0
*/
V1_19_1(Compatibility.COMPATIBLE),
;
private final Compatibility compatibility;

View File

@ -731,6 +731,10 @@ ranks:
protection:
command-is-banned: "Command is banned for visitors"
flags:
ALLAY:
name: "Allay interaction"
description: "Allow giving and taking items to/from Allay"
hint: "Allay interaction disabled"
ANIMAL_NATURAL_SPAWN:
description: "Toggle natural animal spawning"
name: "Animal natural spawn"
@ -745,6 +749,10 @@ protection:
description: "Toggle interaction"
name: "Armor stands"
hint: "Armor stand use disabled"
AXOLOTL_SCOOPING:
name: "Axolotl Scooping"
description: "Allow scooping of axolotl using a bucket"
hint: "Axolotl scooping disabled"
BEACON:
description: "Toggle interaction"
name: "Beacons"
@ -889,6 +897,12 @@ protection:
&a (override Buckets)
name: "Collect water"
hint: "Water buckets disabled"
COLLECT_POWDERED_SNOW:
description: |-
&a Toggle collecting powdered snow
&a (override Buckets)
name: "Collect powdered snow"
hint: "Powdered snow buckets disabled"
COMMAND_RANKS:
name: "&e Command Ranks"
description: "&a Configure command ranks"
@ -1271,6 +1285,18 @@ protection:
&a using spawn eggs.
name: "Spawn eggs on spawners"
hint: "changing a spawner's entity type using spawn eggs is not allowed"
SCULK_SENSOR:
description: |-
&a Allows to change if sculk sensor
&a can be activated by visitor.
name: "Sculk Sensor"
hint: "sculk sensor activation is disabled"
SCULK_SHRIEKER:
description: |-
&a Allows to change if sculk shrieker
&a can be activated by visitor.
name: "Sculk Shrieker"
hint: "sculk shrieker activation is disabled"
TNT_DAMAGE:
description: |-
&a Allow TNT and TNT minecarts

View File

@ -1,7 +1,7 @@
name: BentoBox
main: world.bentobox.bentobox.BentoBox
version: ${project.version}${build.number}
api-version: "1.17"
api-version: "1.18"
authors: [tastybento, Poslovitch]
contributors: ["The BentoBoxWorld Community"]

View File

@ -110,13 +110,13 @@ public class GeoMobLimitTabTest {
assertEquals("AXOLOTL", list.get(0));
// Click on AXOLOTL
tab.onClick(panel, user, ClickType.LEFT, 9);
tab.onClick(panel, user, ClickType.LEFT, 10);
list.forEach(System.out::println);
assertEquals(2, list.size());
assertEquals("COW", list.get(1));
assertEquals("BAT", list.get(0));
// Click on AXOLOTL again to have it added
tab.onClick(panel, user, ClickType.LEFT, 9);
tab.onClick(panel, user, ClickType.LEFT, 10);
assertEquals(3, list.size());
assertEquals("BAT", list.get(0));
assertEquals("COW", list.get(1));

View File

@ -69,7 +69,7 @@ public class BlockInteractionListenerTest extends AbstractCommonSetup {
clickedBlocks.put(Material.WHITE_BED, Flags.BED);
when(Tag.BEDS.isTagged(Material.WHITE_BED)).thenReturn(true);
clickedBlocks.put(Material.BREWING_STAND, Flags.BREWING);
clickedBlocks.put(Material.CAULDRON, Flags.BREWING);
clickedBlocks.put(Material.WATER_CAULDRON, Flags.COLLECT_WATER);
clickedBlocks.put(Material.BARREL, Flags.BARREL);
clickedBlocks.put(Material.CHEST, Flags.CHEST);
clickedBlocks.put(Material.CHEST_MINECART, Flags.CHEST);
@ -87,6 +87,7 @@ public class BlockInteractionListenerTest extends AbstractCommonSetup {
clickedBlocks.put(Material.IRON_TRAPDOOR, Flags.TRAPDOOR);
when(Tag.TRAPDOORS.isTagged(Material.IRON_TRAPDOOR)).thenReturn(true);
clickedBlocks.put(Material.SPRUCE_FENCE_GATE, Flags.GATE);
when(Tag.FENCE_GATES.isTagged(Material.SPRUCE_FENCE_GATE)).thenReturn(true);
clickedBlocks.put(Material.BLAST_FURNACE, Flags.FURNACE);
clickedBlocks.put(Material.CAMPFIRE, Flags.FURNACE);
clickedBlocks.put(Material.FURNACE_MINECART, Flags.FURNACE);
@ -135,6 +136,8 @@ public class BlockInteractionListenerTest extends AbstractCommonSetup {
// Nothing in hand right now
when(item.getType()).thenReturn(Material.AIR);
when(player.getInventory()).thenReturn(inv);
when(inv.getItemInMainHand()).thenReturn(item);
when(inv.getItemInOffHand()).thenReturn(new ItemStack(Material.BUCKET));
// FlagsManager
setFlags();

View File

@ -45,6 +45,8 @@ import world.bentobox.bentobox.managers.FlagsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.util.Util;
import world.bentobox.bentobox.versions.ServerCompatibility;
@RunWith(PowerMockRunner.class)
@PrepareForTest( {BentoBox.class, Bukkit.class, Flags.class, Util.class })
@ -78,6 +80,10 @@ public class MobSpawnListenerTest {
when(server.getWorld("world")).thenReturn(world);
when(server.getVersion()).thenReturn("BSB_Mocking");
ServerCompatibility serverCompatibility = mock(ServerCompatibility.class);
Whitebox.setInternalState(ServerCompatibility.class, "instance", serverCompatibility);
when(serverCompatibility.getServerVersion()).thenReturn(ServerCompatibility.ServerVersion.V1_19);
PluginManager pim = mock(PluginManager.class);
ItemFactory itemFactory = mock(ItemFactory.class);

View File

@ -19,11 +19,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.entity.Cow;
import org.bukkit.entity.Entity;
@ -50,6 +46,7 @@ import world.bentobox.bentobox.Settings;
import world.bentobox.bentobox.api.configuration.WorldSettings;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.listeners.flags.AbstractCommonSetup;
import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.managers.FlagsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
@ -64,18 +61,25 @@ import world.bentobox.bentobox.util.Util;
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest( {Bukkit.class, BentoBox.class, Flags.class, Util.class} )
public class ChestDamageListenerTest {
public class ChestDamageListenerTest extends AbstractCommonSetup
{
private Location location;
private BentoBox plugin;
private World world;
@Override
@Before
public void setUp() {
public void setUp() throws Exception {
super.setUp();
// Set up plugin
plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Tags
when(Tag.SHULKER_BOXES.isTagged(any(Material.class))).thenReturn(false);
Server server = mock(Server.class);
world = mock(World.class);
when(server.getLogger()).thenReturn(Logger.getAnonymousLogger());
@ -161,8 +165,6 @@ public class ChestDamageListenerTest {
// Util
PowerMockito.mockStatic(Util.class);
when(Util.getWorld(Mockito.any())).thenReturn(mock(World.class));
}
@After

View File

@ -46,7 +46,7 @@ public class FlagsManagerTest {
/**
* Update this value if the number of registered listeners changes
*/
private static final int NUMBER_OF_LISTENERS = 50;
private static final int NUMBER_OF_LISTENERS = 52;
@Mock
private BentoBox plugin;
@Mock