diff --git a/pom.xml b/pom.xml
index 568358b99..97f596d4e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -41,7 +41,7 @@
jenkins
- http://ci.codemc.org/job/BentoBoxWorld/job/BentoBox
+ https://ci.codemc.org/job/BentoBoxWorld/job/BentoBox
@@ -87,8 +87,9 @@
-
-
+
+
ci
@@ -101,10 +102,14 @@
-
-
-
-
+
+
+
+
master
@@ -115,7 +120,7 @@
${build.version}
-
+
@@ -130,7 +135,7 @@
org.sonarsource.scanner.maven
sonar-maven-plugin
-
+
3.6.0.1398
@@ -161,78 +166,81 @@
placeholderapi-repo
- http://repo.extendedclip.com/content/repositories/placeholderapi/
+ https://repo.extendedclip.com/content/repositories/placeholderapi/
dynmap-repo
- http://repo.mikeprimm.com/
+ https://repo.mikeprimm.com/
worldedit-repo
- http://maven.sk89q.com/repo/
+ https://maven.sk89q.com/repo/
+
+
+ papermc
+ https://papermc.io/repo/repository/maven-public/
-
-
-
- org.spigotmc
- spigot-api
- ${spigot.version}
- provided
-
-
-
- org.bstats
- bstats-bukkit
- ${bstats.version}
-
-
-
- org.mockito
- mockito-core
- 3.1.0
- test
-
-
- org.powermock
- powermock-module-junit4
- ${powermock.version}
- test
-
-
- org.powermock
- powermock-api-mockito2
- ${powermock.version}
- test
-
-
-
- org.mongodb
- mongodb-driver
- ${mongodb.version}
-
-
-
-
- com.github.MilkBowl
- VaultAPI
- ${vault.version}
- provided
-
-
-
- me.clip
- placeholderapi
- ${placeholderapi.version}
- provided
-
+
+
-
- com.github.Prouser123-forks
+ org.spigotmc
+ spigot-api
+ ${spigot.version}
+ provided
+
+
+
+ org.bstats
+ bstats-bukkit
+ ${bstats.version}
+
+
+
+ org.mockito
+ mockito-core
+ 3.1.0
+ test
+
+
+ org.powermock
+ powermock-module-junit4
+ ${powermock.version}
+ test
+
+
+ org.powermock
+ powermock-api-mockito2
+ ${powermock.version}
+ test
+
+
+
+ org.mongodb
+ mongodb-driver
+ ${mongodb.version}
+
+
+
+
+ com.github.MilkBowl
+ VaultAPI
+ ${vault.version}
+ provided
+
+
+
+ me.clip
+ placeholderapi
+ ${placeholderapi.version}
+ provided
+
+
+
+ com.github.BentoBoxWorld
MVdWPlaceholderAPI
${mvdwplaceholderapi.version}
@@ -255,26 +263,35 @@
GitHubWebAPI4Java
${githubapi.version}
-
-
+
+
org.eclipse.jdt
org.eclipse.jdt.annotation
2.2.200
+
+
+ io.papermc
+ paperlib
+ 1.0.2
+ compile
+
-
+
-
+
${project.name}-${revision}${build.number}
-
+
clean package
@@ -350,6 +367,10 @@
io.github.TheBusyBiscuit.GitHubWebAPI4Java
world.bentobox.bentobox.api.github
+
+ io.papermc.lib
+ world.bentobox.bentobox.paperlib
+
@@ -384,8 +405,8 @@
true
-
+
**/*Names*
diff --git a/src/main/java/world/bentobox/bentobox/listeners/flags/protection/EntityInteractListener.java b/src/main/java/world/bentobox/bentobox/listeners/flags/protection/EntityInteractListener.java
index fd82408bc..c88b30038 100644
--- a/src/main/java/world/bentobox/bentobox/listeners/flags/protection/EntityInteractListener.java
+++ b/src/main/java/world/bentobox/bentobox/listeners/flags/protection/EntityInteractListener.java
@@ -1,11 +1,11 @@
package world.bentobox.bentobox.listeners.flags.protection;
import org.bukkit.Material;
+import org.bukkit.entity.AbstractVillager;
import org.bukkit.entity.Animals;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Boat;
import org.bukkit.entity.Vehicle;
-import org.bukkit.entity.Villager;
import org.bukkit.entity.minecart.RideableMinecart;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@@ -47,7 +47,7 @@ public class EntityInteractListener extends FlagListener {
}
}
// Villager trading
- else if (e.getRightClicked() instanceof Villager) {
+ else if (e.getRightClicked() instanceof AbstractVillager) {
// Check naming and check trading
checkIsland(e, e.getPlayer(), e.getRightClicked().getLocation(), Flags.TRADING);
if (e.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.NAME_TAG)) {
diff --git a/src/main/java/world/bentobox/bentobox/listeners/flags/protection/HurtingListener.java b/src/main/java/world/bentobox/bentobox/listeners/flags/protection/HurtingListener.java
index 61ac70d16..17bdd4917 100644
--- a/src/main/java/world/bentobox/bentobox/listeners/flags/protection/HurtingListener.java
+++ b/src/main/java/world/bentobox/bentobox/listeners/flags/protection/HurtingListener.java
@@ -1,19 +1,24 @@
package world.bentobox.bentobox.listeners.flags.protection;
import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
import org.bukkit.Material;
+import org.bukkit.entity.AbstractVillager;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Firework;
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;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
+import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.LingeringPotionSplashEvent;
import org.bukkit.event.entity.PotionSplashEvent;
import org.bukkit.event.player.PlayerFishEvent;
@@ -35,7 +40,8 @@ import world.bentobox.bentobox.versions.ServerCompatibility;
*/
public class HurtingListener extends FlagListener {
- private HashMap thrownPotions = new HashMap<>();
+ private Map thrownPotions = new HashMap<>();
+ private Map firedFireworks = new WeakHashMap<>();
/**
* Handles mob and monster protection
@@ -47,7 +53,7 @@ public class HurtingListener extends FlagListener {
// Mobs being hurt
if (Util.isPassiveEntity(e.getEntity())) {
respond(e, e.getDamager(), Flags.HURT_ANIMALS);
- } else if (e.getEntity() instanceof Villager) {
+ } else if (e.getEntity() instanceof AbstractVillager) {
respond(e, e.getDamager(), Flags.HURT_VILLAGERS);
} else if (Util.isHostileEntity(e.getEntity())) {
respond(e, e.getDamager(), Flags.HURT_MONSTERS);
@@ -85,7 +91,7 @@ public class HurtingListener extends FlagListener {
if ((Util.isPassiveEntity(e.getCaught()) && checkIsland(e, e.getPlayer(), e.getCaught().getLocation(), Flags.HURT_ANIMALS))
|| (Util.isHostileEntity(e.getCaught()) && checkIsland(e, e.getPlayer(), e.getCaught().getLocation(), Flags.HURT_MONSTERS))
- || (e.getCaught() instanceof Villager && checkIsland(e, e.getPlayer(), e.getCaught().getLocation(), Flags.HURT_VILLAGERS))) {
+ || (e.getCaught() instanceof AbstractVillager && checkIsland(e, e.getPlayer(), e.getCaught().getLocation(), Flags.HURT_VILLAGERS))) {
e.getHook().remove();
}
@@ -139,7 +145,7 @@ public class HurtingListener extends FlagListener {
}
// Villagers being hurt
- if (entity instanceof Villager && !checkIsland(e, attacker, entity.getLocation(), Flags.HURT_VILLAGERS)) {
+ if (entity instanceof AbstractVillager && !checkIsland(e, attacker, entity.getLocation(), Flags.HURT_VILLAGERS)) {
for (PotionEffect effect : e.getPotion().getEffects()) {
entity.removePotionEffect(effect.getType());
}
@@ -173,23 +179,43 @@ public class HurtingListener extends FlagListener {
public void onLingeringPotionDamage(final EntityDamageByEntityEvent e) {
if (e.getCause().equals(DamageCause.ENTITY_ATTACK) && thrownPotions.containsKey(e.getDamager().getEntityId())) {
Player attacker = thrownPotions.get(e.getDamager().getEntityId());
- // Self damage
- if (attacker == null || attacker.equals(e.getEntity())) {
- return;
- }
- Entity entity = e.getEntity();
- // Monsters being hurt
- if (Util.isHostileEntity(entity)) {
- checkIsland(e, attacker, entity.getLocation(), Flags.HURT_MONSTERS);
- }
- // Mobs being hurt
- if (Util.isPassiveEntity(entity)) {
- checkIsland(e, attacker, entity.getLocation(), Flags.HURT_ANIMALS);
- }
- // Villagers being hurt
- if (entity instanceof Villager) {
- checkIsland(e, attacker, entity.getLocation(), Flags.HURT_VILLAGERS);
- }
+ processDamage(e, attacker);
+ }
+ }
+
+ private void processDamage(EntityDamageByEntityEvent e, Player attacker) {
+ // Self damage
+ if (attacker == null || attacker.equals(e.getEntity())) {
+ return;
+ }
+ Entity entity = e.getEntity();
+ // Monsters being hurt
+ if (Util.isHostileEntity(entity)) {
+ checkIsland(e, attacker, entity.getLocation(), Flags.HURT_MONSTERS);
+ }
+ // Mobs being hurt
+ if (Util.isPassiveEntity(entity)) {
+ checkIsland(e, attacker, entity.getLocation(), Flags.HURT_ANIMALS);
+ }
+ // Villagers being hurt
+ if (entity instanceof AbstractVillager) {
+ checkIsland(e, attacker, entity.getLocation(), Flags.HURT_VILLAGERS);
+ }
+
+ }
+
+ @EventHandler(priority = EventPriority.LOW, ignoreCancelled=true)
+ public void onFireworkDamage(final EntityDamageByEntityEvent e) {
+ if (e.getDamager() instanceof Firework && firedFireworks.containsKey(e.getDamager())) {
+ processDamage(e, (Player)firedFireworks.get(e.getDamager()));
+ }
+ }
+
+ @EventHandler(priority = EventPriority.LOW, ignoreCancelled=true)
+ public void onPlayerShootEvent(final EntityShootBowEvent e) {
+ // Only care about players shooting fireworks
+ if (e.getEntityType().equals(EntityType.PLAYER) && (e.getProjectile() instanceof Firework)) {
+ firedFireworks.put(e.getProjectile(), e.getEntity());
}
}
}
diff --git a/src/main/java/world/bentobox/bentobox/listeners/flags/protection/LockAndBanListener.java b/src/main/java/world/bentobox/bentobox/listeners/flags/protection/LockAndBanListener.java
index 7d26b8412..ef107d9f7 100644
--- a/src/main/java/world/bentobox/bentobox/listeners/flags/protection/LockAndBanListener.java
+++ b/src/main/java/world/bentobox/bentobox/listeners/flags/protection/LockAndBanListener.java
@@ -12,6 +12,7 @@ import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.vehicle.VehicleMoveEvent;
import org.bukkit.util.Vector;
+import io.papermc.lib.PaperLib;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.flags.FlagListener;
import world.bentobox.bentobox.api.user.User;
@@ -155,7 +156,7 @@ public class LockAndBanListener extends FlagListener {
} else {
// There's nothing much we can do.
// We'll try to teleport him to the spawn...
- player.teleport(player.getWorld().getSpawnLocation());
+ PaperLib.teleportAsync(player, player.getWorld().getSpawnLocation());
// Switch him back to the default gamemode. He may die, sorry :(
player.setGameMode(getIWM().getDefaultGameMode(player.getWorld()));
diff --git a/src/main/java/world/bentobox/bentobox/listeners/flags/settings/PVPListener.java b/src/main/java/world/bentobox/bentobox/listeners/flags/settings/PVPListener.java
index a62fb0c5e..8ce05bb1a 100644
--- a/src/main/java/world/bentobox/bentobox/listeners/flags/settings/PVPListener.java
+++ b/src/main/java/world/bentobox/bentobox/listeners/flags/settings/PVPListener.java
@@ -1,11 +1,14 @@
package world.bentobox.bentobox.listeners.flags.settings;
import java.util.HashMap;
+import java.util.Map;
import java.util.UUID;
+import java.util.WeakHashMap;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Entity;
+import org.bukkit.entity.Firework;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
@@ -16,6 +19,7 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.AreaEffectCloudApplyEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
+import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.LingeringPotionSplashEvent;
import org.bukkit.event.entity.PotionSplashEvent;
import org.bukkit.event.player.PlayerFishEvent;
@@ -32,7 +36,8 @@ import world.bentobox.bentobox.lists.Flags;
*/
public class PVPListener extends FlagListener {
- private HashMap thrownPotions = new HashMap<>();
+ private Map thrownPotions = new HashMap<>();
+ private Map firedFireworks = new WeakHashMap<>();
/**
* This method protects players from PVP if it is not allowed and from
@@ -79,23 +84,31 @@ public class PVPListener extends FlagListener {
} else if (damager instanceof Projectile) {
// Find out who fired the arrow
Projectile p = (Projectile) damager;
- Entity entity =(Entity)p.getShooter();
- if (entity instanceof Player) {
- // Allow self damage
- if (hurtEntity.equals(entity)) {
- return;
- }
- User user = User.getInstance((Player)p.getShooter());
- if (!checkIsland((Event)e, (Player)entity, damager.getLocation(), flag)) {
- damager.setFireTicks(0);
- hurtEntity.setFireTicks(0);
- user.notify(Flags.PVP_OVERWORLD.getHintReference());
- e.setCancelled(true);
- }
+ Entity shooter =(Entity)p.getShooter();
+ if (shooter instanceof Player) {
+ processDamage(e, damager, (Player)shooter, hurtEntity, flag);
}
+ } else if (damager instanceof Firework && firedFireworks.containsKey(damager)) {
+ Player shooter = firedFireworks.get(damager);
+ processDamage(e, damager, shooter, hurtEntity, flag);
}
}
+ private void processDamage(Cancellable e, Entity damager, Player shooter, Entity hurtEntity, Flag flag) {
+ // Allow self damage
+ if (hurtEntity.equals(shooter)) {
+ return;
+ }
+ User user = User.getInstance(shooter);
+ if (!checkIsland((Event)e, shooter, damager.getLocation(), flag)) {
+ damager.setFireTicks(0);
+ hurtEntity.setFireTicks(0);
+ user.notify(Flags.PVP_OVERWORLD.getHintReference());
+ e.setCancelled(true);
+ }
+
+ }
+
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onFishing(PlayerFishEvent e) {
if (e.getCaught() instanceof Player && getPlugin().getIWM().inWorld(e.getCaught().getLocation())) {
@@ -191,4 +204,11 @@ public class PVPListener extends FlagListener {
}
}
+ @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled=true)
+ public void onPlayerShootFireworkEvent(final EntityShootBowEvent e) {
+ // Only care about players shooting fireworks
+ if (e.getEntity() instanceof Player && (e.getProjectile() instanceof Firework)) {
+ firedFireworks.put(e.getProjectile(), (Player)e.getEntity());
+ }
+ }
}
diff --git a/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java b/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java
index f3a870990..dd0198d14 100644
--- a/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java
+++ b/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java
@@ -20,6 +20,7 @@ import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.TreeSpecies;
import org.bukkit.World;
+import org.bukkit.attribute.Attribute;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
@@ -36,6 +37,7 @@ import org.eclipse.jdt.annotation.Nullable;
import com.google.common.collect.ImmutableMap;
+import io.papermc.lib.PaperLib;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.island.IslandEvent;
@@ -664,27 +666,26 @@ public class IslandsManager {
.build();
return;
}
- if (!home.getChunk().isLoaded()) {
- home.getChunk().load();
- }
- player.teleport(home);
// Add home
if (plugin.getPlayers().getHomeLocations(world, player.getUniqueId()).isEmpty()) {
plugin.getPlayers().setHomeLocation(player.getUniqueId(), home);
}
- if (number == 1) {
- user.sendMessage("commands.island.go.teleport");
- } else {
+ user.sendMessage("commands.island.go.teleport");
+ PaperLib.teleportAsync(player, home).thenAccept(b -> teleported(world, user, number, newIsland));
+ }
+
+ private void teleported(World world, User user, int number, boolean newIsland) {
+ if (number > 1) {
user.sendMessage("commands.island.go.teleported", TextVariables.NUMBER, String.valueOf(number));
}
// If this is a new island, then run commands and do resets
if (newIsland) {
// Execute commands
plugin.getIWM().getOnJoinCommands(world).forEach(command -> {
- command = command.replace("[player]", player.getName());
+ command = command.replace("[player]", user.getName());
if (command.startsWith("[SUDO]")) {
// Execute the command by the player
- player.performCommand(command.substring(6));
+ user.performCommand(command.substring(6));
} else {
// Otherwise execute as the server console
plugin.getServer().dispatchCommand(Bukkit.getConsoleSender(), command);
@@ -704,7 +705,7 @@ public class IslandsManager {
// Reset the health
if (plugin.getIWM().isOnJoinResetHealth(world)) {
- user.getPlayer().setHealth(20.0D);
+ user.getPlayer().setHealth(user.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getDefaultValue());
}
// Reset the hunger
@@ -789,7 +790,7 @@ public class IslandsManager {
this.spawn.put(spawn.getWorld(), spawn);
spawn.setSpawn(true);
}
-
+
/**
* Clears the spawn island for this world
* @param world - world
@@ -986,7 +987,7 @@ public class IslandsManager {
// Move player to spawn
if (spawn.containsKey(w)) {
// go to island spawn
- p.teleport(spawn.get(w).getSpawnPoint(w.getEnvironment()));
+ PaperLib.teleportAsync(p, spawn.get(w).getSpawnPoint(w.getEnvironment()));
}
}
});
diff --git a/src/main/java/world/bentobox/bentobox/util/DeleteIslandChunks.java b/src/main/java/world/bentobox/bentobox/util/DeleteIslandChunks.java
index 9ea677d39..457619c51 100644
--- a/src/main/java/world/bentobox/bentobox/util/DeleteIslandChunks.java
+++ b/src/main/java/world/bentobox/bentobox/util/DeleteIslandChunks.java
@@ -5,6 +5,8 @@ import java.util.Random;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
+import org.bukkit.Material;
+import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.generator.ChunkGenerator;
@@ -12,6 +14,7 @@ import org.bukkit.generator.ChunkGenerator.ChunkData;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.scheduler.BukkitTask;
+import io.papermc.lib.PaperLib;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.events.island.IslandEvent;
@@ -25,13 +28,11 @@ import world.bentobox.bentobox.database.objects.IslandDeletion;
*/
public class DeleteIslandChunks {
- /**
- * This is how many chunks per world will be done in one tick.
- */
private int chunkX;
private int chunkZ;
private BukkitTask task;
private IslandDeletion di;
+ private boolean inDelete;
public DeleteIslandChunks(BentoBox plugin, IslandDeletion di) {
// Fire event
@@ -42,16 +43,19 @@ public class DeleteIslandChunks {
this.di = di;
// Run through all chunks of the islands and regenerate them.
task = Bukkit.getScheduler().runTaskTimer(plugin, () -> {
+ if (inDelete) return;
+ inDelete = true;
for (int i = 0; i < plugin.getSettings().getDeleteSpeed(); i++) {
plugin.getIWM().getAddon(di.getWorld()).ifPresent(gm -> {
- Chunk chunk = di.getWorld().getChunkAt(chunkX, chunkZ);
- regenerateChunk(gm, chunk);
-
+ // Overworld
+ processChunk(gm, di.getWorld(), chunkX, chunkZ);
+ // Nether
if (plugin.getIWM().isNetherGenerate(di.getWorld()) && plugin.getIWM().isNetherIslands(di.getWorld())) {
- regenerateChunk(gm, plugin.getIWM().getNetherWorld(di.getWorld()).getChunkAt(chunkX, chunkZ));
+ processChunk(gm, plugin.getIWM().getNetherWorld(di.getWorld()), chunkX, chunkZ);
}
+ // End
if (plugin.getIWM().isEndGenerate(di.getWorld()) && plugin.getIWM().isEndIslands(di.getWorld())) {
- regenerateChunk(gm, plugin.getIWM().getEndWorld(di.getWorld()).getChunkAt(chunkX, chunkZ));
+ processChunk(gm, plugin.getIWM().getEndWorld(di.getWorld()), chunkX, chunkZ);
}
chunkZ++;
if (chunkZ > di.getMaxZChunk()) {
@@ -66,9 +70,16 @@ public class DeleteIslandChunks {
}
});
}
+ inDelete = false;
}, 0L, 1L);
}
+ private void processChunk(GameModeAddon gm, World world, int x, int z) {
+ if (PaperLib.isChunkGenerated(world, x, z)) {
+ PaperLib.getChunkAtAsync(world, x, z).thenAccept(chunk -> regenerateChunk(gm, chunk));
+ }
+ }
+
private void regenerateChunk(GameModeAddon gm, Chunk chunk) {
boolean isLoaded = chunk.isLoaded();
// Clear all inventories
@@ -88,6 +99,9 @@ public class DeleteIslandChunks {
if (di.inBounds(baseX + x, baseZ + z)) {
chunk.getBlock(x, 0, z).setBiome(grid.getBiome(x, z));
for (int y = 0; y < chunk.getWorld().getMaxHeight(); y++) {
+ // Note: setting block to air before setting it to something else stops a bug in the server
+ // where it reports a "
+ chunk.getBlock(x, y, z).setType(Material.AIR, false);
chunk.getBlock(x, y, z).setBlockData(cd.getBlockData(x, y, z), false);
}
}
diff --git a/src/main/java/world/bentobox/bentobox/util/Util.java b/src/main/java/world/bentobox/bentobox/util/Util.java
index eb469580f..797c23746 100644
--- a/src/main/java/world/bentobox/bentobox/util/Util.java
+++ b/src/main/java/world/bentobox/bentobox/util/Util.java
@@ -6,14 +6,19 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
+import java.util.concurrent.CompletableFuture;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+
import org.bukkit.Bukkit;
+import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.World.Environment;
+import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Animals;
import org.bukkit.entity.Bat;
@@ -28,10 +33,13 @@ import org.bukkit.entity.Shulker;
import org.bukkit.entity.Slime;
import org.bukkit.entity.Snowman;
import org.bukkit.entity.WaterMob;
+import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import io.papermc.lib.PaperLib;
+import io.papermc.lib.features.blockstatesnapshot.BlockStateSnapshotResult;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.user.User;
@@ -351,4 +359,164 @@ public class Util {
return entity instanceof Animals || entity instanceof IronGolem || entity instanceof Snowman ||
entity instanceof WaterMob && !(entity instanceof PufferFish) || entity instanceof Bat;
}
+
+ /*
+ * PaperLib methods for addons to call
+ */
+
+ /**
+ * Teleports an Entity to the target location, loading the chunk asynchronously first if needed.
+ * @param entity The Entity to teleport
+ * @param location The Location to Teleport to
+ * @return Future that completes with the result of the teleport
+ */
+ @Nonnull
+ public static CompletableFuture teleportAsync(@Nonnull Entity entity, @Nonnull Location location) {
+ return PaperLib.teleportAsync(entity, location);
+ }
+
+ /**
+ * Teleports an Entity to the target location, loading the chunk asynchronously first if needed.
+ * @param entity The Entity to teleport
+ * @param location The Location to Teleport to
+ * @param cause The cause for the teleportation
+ * @return Future that completes with the result of the teleport
+ */
+ @Nonnull
+ public static CompletableFuture teleportAsync(@Nonnull Entity entity, @Nonnull Location location, TeleportCause cause) {
+ return PaperLib.teleportAsync(entity, location, cause);
+ }
+
+ /**
+ * Gets the chunk at the target location, loading it asynchronously if needed.
+ * @param loc Location to get chunk for
+ * @return Future that completes with the chunk
+ */
+ @Nonnull
+ public static CompletableFuture getChunkAtAsync(@Nonnull Location loc) {
+ return getChunkAtAsync(loc.getWorld(), loc.getBlockX() >> 4, loc.getBlockZ() >> 4, true);
+ }
+
+ /**
+ * Gets the chunk at the target location, loading it asynchronously if needed.
+ * @param loc Location to get chunk for
+ * @param gen Should the chunk generate or not. Only respected on some MC versions, 1.13 for CB, 1.12 for Paper
+ * @return Future that completes with the chunk, or null if the chunk did not exists and generation was not requested.
+ */
+ @Nonnull
+ public static CompletableFuture getChunkAtAsync(@Nonnull Location loc, boolean gen) {
+ return getChunkAtAsync(loc.getWorld(), loc.getBlockX() >> 4, loc.getBlockZ() >> 4, gen);
+ }
+
+ /**
+ * Gets the chunk at the target location, loading it asynchronously if needed.
+ * @param world World to load chunk for
+ * @param x X coordinate of the chunk to load
+ * @param z Z coordinate of the chunk to load
+ * @return Future that completes with the chunk
+ */
+ @Nonnull
+ public static CompletableFuture getChunkAtAsync(@Nonnull World world, int x, int z) {
+ return getChunkAtAsync(world, x, z, true);
+ }
+
+ /**
+ * Gets the chunk at the target location, loading it asynchronously if needed.
+ * @param world World to load chunk for
+ * @param x X coordinate of the chunk to load
+ * @param z Z coordinate of the chunk to load
+ * @param gen Should the chunk generate or not. Only respected on some MC versions, 1.13 for CB, 1.12 for Paper
+ * @return Future that completes with the chunk, or null if the chunk did not exists and generation was not requested.
+ */
+ @Nonnull
+ public static CompletableFuture getChunkAtAsync(@Nonnull World world, int x, int z, boolean gen) {
+ return PaperLib.getChunkAtAsync(world, x, z, gen);
+ }
+
+ /**
+ * Checks if the chunk has been generated or not. Only works on Paper 1.12+ or any 1.13.1+ version
+ * @param loc Location to check if the chunk is generated
+ * @return If the chunk is generated or not
+ */
+ public static boolean isChunkGenerated(@Nonnull Location loc) {
+ return isChunkGenerated(loc.getWorld(), loc.getBlockX() >> 4, loc.getBlockZ() >> 4);
+ }
+
+ /**
+ * Checks if the chunk has been generated or not. Only works on Paper 1.12+ or any 1.13.1+ version
+ * @param world World to check for
+ * @param x X coordinate of the chunk to check
+ * @param z Z coordinate of the chunk to checl
+ * @return If the chunk is generated or not
+ */
+ public static boolean isChunkGenerated(@Nonnull World world, int x, int z) {
+ return PaperLib.isChunkGenerated(world, x, z);
+ }
+
+ /**
+ * Get's a BlockState, optionally not using a snapshot
+ * @param block The block to get a State of
+ * @param useSnapshot Whether or not to use a snapshot when supported
+ * @return The BlockState
+ */
+ @Nonnull
+ public static BlockStateSnapshotResult getBlockState(@Nonnull Block block, boolean useSnapshot) {
+ return PaperLib.getBlockState(block, useSnapshot);
+ }
+
+ /**
+ * Detects if the current MC version is at least the following version.
+ *
+ * Assumes 0 patch version.
+ *
+ * @param minor Min Minor Version
+ * @return Meets the version requested
+ */
+ public static boolean isVersion(int minor) {
+ return PaperLib.isVersion(minor);
+ }
+
+ /**
+ * Detects if the current MC version is at least the following version.
+ * @param minor Min Minor Version
+ * @param patch Min Patch Version
+ * @return Meets the version requested
+ */
+ public static boolean isVersion(int minor, int patch) {
+ return PaperLib.isVersion(minor, patch);
+ }
+
+ /**
+ * Gets the current Minecraft Minor version. IE: 1.13.1 returns 13
+ * @return The Minor Version
+ */
+ public static int getMinecraftVersion() {
+ return PaperLib.getMinecraftVersion();
+ }
+
+ /**
+ * Gets the current Minecraft Patch version. IE: 1.13.1 returns 1
+ * @return The Patch Version
+ */
+ public static int getMinecraftPatchVersion() {
+ return PaperLib.getMinecraftPatchVersion();
+ }
+
+ /**
+ * Check if the server has access to the Spigot API
+ * @return True for Spigot and Paper environments
+ */
+ public static boolean isSpigot() {
+ return PaperLib.isSpigot();
+ }
+
+ /**
+ * Check if the server has access to the Paper API
+ * @return True for Paper environments
+ */
+ public static boolean isPaper() {
+ return PaperLib.isPaper();
+ }
+
+
}
diff --git a/src/main/java/world/bentobox/bentobox/util/teleport/SafeSpotTeleport.java b/src/main/java/world/bentobox/bentobox/util/teleport/SafeSpotTeleport.java
index b5b31001c..895280bd0 100644
--- a/src/main/java/world/bentobox/bentobox/util/teleport/SafeSpotTeleport.java
+++ b/src/main/java/world/bentobox/bentobox/util/teleport/SafeSpotTeleport.java
@@ -17,6 +17,7 @@ import org.bukkit.scheduler.BukkitTask;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.Nullable;
+import io.papermc.lib.PaperLib;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
@@ -226,16 +227,13 @@ public class SafeSpotTeleport {
*/
private void teleportEntity(final Location loc) {
task.cancel();
+ if (!portal && entity instanceof Player && homeNumber > 0) {
+ // Set home if so marked
+ plugin.getPlayers().setHomeLocation(User.getInstance(entity), loc, homeNumber);
+ }
+ Vector velocity = entity.getVelocity();
// Return to main thread and teleport the player
- Bukkit.getScheduler().runTask(plugin, () -> {
- if (!portal && entity instanceof Player && homeNumber > 0) {
- // Set home if so marked
- plugin.getPlayers().setHomeLocation(User.getInstance(entity), loc, homeNumber);
- }
- Vector velocity = entity.getVelocity();
- entity.teleport(loc);
- entity.setVelocity(velocity);
- });
+ Bukkit.getScheduler().runTask(plugin, () -> PaperLib.teleportAsync(entity, loc).thenAccept(b -> entity.setVelocity(velocity)));
}
/**
diff --git a/src/test/java/world/bentobox/bentobox/listeners/flags/protection/EntityInteractListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/flags/protection/EntityInteractListenerTest.java
index 8fcc3337e..8bcdee8a1 100644
--- a/src/test/java/world/bentobox/bentobox/listeners/flags/protection/EntityInteractListenerTest.java
+++ b/src/test/java/world/bentobox/bentobox/listeners/flags/protection/EntityInteractListenerTest.java
@@ -1,10 +1,15 @@
package world.bentobox.bentobox.listeners.flags.protection;
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.*;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.Optional;
@@ -21,6 +26,7 @@ import org.bukkit.entity.Horse;
import org.bukkit.entity.Player;
import org.bukkit.entity.Sheep;
import org.bukkit.entity.Villager;
+import org.bukkit.entity.WanderingTrader;
import org.bukkit.entity.minecart.RideableMinecart;
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
@@ -329,6 +335,63 @@ public class EntityInteractListenerTest {
verify(notifier).notify(any(), eq("protection.protected"));
assertTrue(e.isCancelled());
}
+
+ /**
+ * Test method for {@link world.bentobox.bentobox.listeners.flags.protection.EntityInteractListener#onPlayerInteractEntity(org.bukkit.event.player.PlayerInteractEntityEvent)}.
+ */
+ @Test
+ public void testOnPlayerInteractEntityWanderingTraderNoInteraction() {
+ clickedEntity = mock(WanderingTrader.class);
+ when(clickedEntity.getLocation()).thenReturn(location);
+ PlayerInteractEntityEvent e = new PlayerInteractEntityEvent(player, clickedEntity, hand);
+ eil.onPlayerInteractEntity(e);
+ verify(notifier, times(2)).notify(any(), eq("protection.protected"));
+ assertTrue(e.isCancelled());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.bentobox.listeners.flags.protection.EntityInteractListener#onPlayerInteractEntity(org.bukkit.event.player.PlayerInteractAtEntityEvent)}.
+ */
+ @Test
+ public void testOnPlayerInteractAtEntityWanderingTraderAllowed() {
+ when(island.isAllowed(any(), any())).thenReturn(true);
+ clickedEntity = mock(WanderingTrader.class);
+ when(clickedEntity.getLocation()).thenReturn(location);
+ PlayerInteractEntityEvent e = new PlayerInteractEntityEvent(player, clickedEntity, hand);
+ eil.onPlayerInteractEntity(e);
+ verify(notifier, never()).notify(any(), eq("protection.protected"));
+ assertFalse(e.isCancelled());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.bentobox.listeners.flags.protection.EntityInteractListener#onPlayerInteractEntity(org.bukkit.event.player.PlayerInteractAtEntityEvent)}.
+ */
+ @Test
+ public void testOnPlayerInteractEntityNamingWanderingTraderAllowedNoTrading() {
+ when(island.isAllowed(any(), eq(Flags.TRADING))).thenReturn(false);
+ when(island.isAllowed(any(), eq(Flags.NAME_TAG))).thenReturn(true);
+ clickedEntity = mock(WanderingTrader.class);
+ when(clickedEntity.getLocation()).thenReturn(location);
+ PlayerInteractEntityEvent e = new PlayerInteractEntityEvent(player, clickedEntity, hand);
+ eil.onPlayerInteractEntity(e);
+ verify(notifier).notify(any(), eq("protection.protected"));
+ assertTrue(e.isCancelled());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.bentobox.listeners.flags.protection.EntityInteractListener#onPlayerInteractEntity(org.bukkit.event.player.PlayerInteractAtEntityEvent)}.
+ */
+ @Test
+ public void testOnPlayerInteractEntityNamingWanderingTraderAllowedTradingNoNaming() {
+ when(island.isAllowed(any(), eq(Flags.TRADING))).thenReturn(true);
+ when(island.isAllowed(any(), eq(Flags.NAME_TAG))).thenReturn(false);
+ clickedEntity = mock(WanderingTrader.class);
+ when(clickedEntity.getLocation()).thenReturn(location);
+ PlayerInteractEntityEvent e = new PlayerInteractEntityEvent(player, clickedEntity, hand);
+ eil.onPlayerInteractEntity(e);
+ verify(notifier).notify(any(), eq("protection.protected"));
+ assertTrue(e.isCancelled());
+ }
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.protection.EntityInteractListener#onPlayerInteractEntity(org.bukkit.event.player.PlayerInteractEntityEvent)}.
diff --git a/src/test/java/world/bentobox/bentobox/listeners/flags/protection/HurtingListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/flags/protection/HurtingListenerTest.java
index 405ed0912..2d3dbc965 100644
--- a/src/test/java/world/bentobox/bentobox/listeners/flags/protection/HurtingListenerTest.java
+++ b/src/test/java/world/bentobox/bentobox/listeners/flags/protection/HurtingListenerTest.java
@@ -1,6 +1,3 @@
-/**
- *
- */
package world.bentobox.bentobox.listeners.flags.protection;
import static org.junit.Assert.assertFalse;
@@ -30,6 +27,7 @@ import org.bukkit.entity.Monster;
import org.bukkit.entity.Player;
import org.bukkit.entity.Slime;
import org.bukkit.entity.Villager;
+import org.bukkit.entity.WanderingTrader;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.player.PlayerFishEvent;
import org.bukkit.event.player.PlayerFishEvent.State;
@@ -333,6 +331,22 @@ public class HurtingListenerTest {
// Verify
verify(notifier).notify(eq(user), eq("protection.protected"));
}
+
+ /**
+ * Test method for {@link HurtingListener#onFishing(org.bukkit.event.player.PlayerFishEvent)}.
+ */
+ @Test
+ public void testOnFishingDisallowWanderingTraderCatching() {
+ WanderingTrader entity = mock(WanderingTrader.class);
+ when(entity.getLocation()).thenReturn(location);
+ State state = State.CAUGHT_ENTITY;
+ PlayerFishEvent e = new PlayerFishEvent(player, entity, hookEntity, state);
+ HurtingListener hl = new HurtingListener();
+ hl.onFishing(e);
+ // Verify
+ verify(notifier).notify(eq(user), eq("protection.protected"));
+ }
+
/**
* Test method for {@link HurtingListener#onFishing(org.bukkit.event.player.PlayerFishEvent)}.
@@ -350,6 +364,24 @@ public class HurtingListenerTest {
// Verify
verify(notifier, never()).notify(eq(user), eq("protection.protected"));
}
+
+ /**
+ * Test method for {@link HurtingListener#onFishing(org.bukkit.event.player.PlayerFishEvent)}.
+ */
+ @Test
+ public void testOnFishingAllowWanderingTraderCatching() {
+ WanderingTrader entity = mock(WanderingTrader.class);
+ when(entity.getLocation()).thenReturn(location);
+ State state = State.CAUGHT_ENTITY;
+ PlayerFishEvent e = new PlayerFishEvent(player, entity, hookEntity, state);
+ HurtingListener hl = new HurtingListener();
+ // Allow
+ when(island.isAllowed(any(), any())).thenReturn(true);
+ hl.onFishing(e);
+ // Verify
+ verify(notifier, never()).notify(eq(user), eq("protection.protected"));
+ }
+
/**
* Test method for {@link HurtingListener#onPlayerFeedParrots(org.bukkit.event.player.PlayerInteractEntityEvent)}.
*/
diff --git a/src/test/java/world/bentobox/bentobox/listeners/flags/protection/InventoryListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/flags/protection/InventoryListenerTest.java
index fe583ff18..2c1f17a86 100644
--- a/src/test/java/world/bentobox/bentobox/listeners/flags/protection/InventoryListenerTest.java
+++ b/src/test/java/world/bentobox/bentobox/listeners/flags/protection/InventoryListenerTest.java
@@ -29,6 +29,7 @@ import org.bukkit.block.ShulkerBox;
import org.bukkit.entity.Horse;
import org.bukkit.entity.Player;
import org.bukkit.entity.Villager;
+import org.bukkit.entity.WanderingTrader;
import org.bukkit.entity.minecart.StorageMinecart;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryAction;
@@ -76,7 +77,7 @@ public class InventoryListenerTest {
private final static List> HOLDERS = Arrays.asList(Horse.class, Chest.class,ShulkerBox.class, StorageMinecart.class,
Dispenser.class,
Dropper.class, Hopper.class, Furnace.class, BrewingStand.class,
- Villager.class);
+ Villager.class, WanderingTrader.class);
private Location location;
private BentoBox plugin;
diff --git a/src/test/java/world/bentobox/bentobox/listeners/flags/settings/PVPListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/flags/settings/PVPListenerTest.java
index 2257d0314..d671d2e53 100644
--- a/src/test/java/world/bentobox/bentobox/listeners/flags/settings/PVPListenerTest.java
+++ b/src/test/java/world/bentobox/bentobox/listeners/flags/settings/PVPListenerTest.java
@@ -3,13 +3,13 @@ package world.bentobox.bentobox.listeners.flags.settings;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.times;
import java.util.ArrayList;
import java.util.Collections;
@@ -22,10 +22,14 @@ import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Location;
+import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.AreaEffectCloud;
+import org.bukkit.entity.Arrow;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.Entity;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Firework;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.LingeringPotion;
import org.bukkit.entity.LivingEntity;
@@ -37,7 +41,9 @@ import org.bukkit.entity.Zombie;
import org.bukkit.event.entity.AreaEffectCloudApplyEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.entity.EntityDamageEvent.DamageModifier;
+import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.LingeringPotionSplashEvent;
import org.bukkit.event.entity.PotionSplashEvent;
import org.bukkit.event.player.PlayerFishEvent;
@@ -49,6 +55,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
@@ -87,15 +94,25 @@ import world.bentobox.bentobox.util.Util;
@PrepareForTest({BentoBox.class, Util.class, Bukkit.class })
public class PVPListenerTest {
+ @Mock
private IslandWorldManager iwm;
+ @Mock
private IslandsManager im;
+ @Mock
private Island island;
+ @Mock
private Player player;
+ @Mock
private Player player2;
+ @Mock
private Location loc;
+ @Mock
private Zombie zombie;
+ @Mock
private Creeper creeper;
+ @Mock
private World world;
+ @Mock
private Notifier notifier;
/**
@@ -109,7 +126,6 @@ public class PVPListenerTest {
// Make sure you set the plung for the User class otherwise it'll use an old object
User.setPlugin(plugin);
// Island World Manager
- iwm = mock(IslandWorldManager.class);
when(iwm.inWorld(any(World.class))).thenReturn(true);
when(iwm.inWorld(any(Location.class))).thenReturn(true);
when(iwm.getPermissionPrefix(Mockito.any())).thenReturn("bskyblock.");
@@ -120,23 +136,23 @@ public class PVPListenerTest {
Panel panel = mock(Panel.class);
when(panel.getInventory()).thenReturn(mock(Inventory.class));
- // Sometimes use Mockito.withSettings().verboseLogging()
- player = mock(Player.class);
- UUID uuid = UUID.randomUUID();
- when(player.getUniqueId()).thenReturn(uuid);
- world = mock(World.class);
+ // World
when(world.getEnvironment()).thenReturn(World.Environment.NORMAL);
- when(player.getWorld()).thenReturn(world);
- loc = mock(Location.class);
+ // Location
when(loc.getWorld()).thenReturn(world);
+ // Sometimes use Mockito.withSettings().verboseLogging()
+ // Player
+ UUID uuid = UUID.randomUUID();
+ when(player.getUniqueId()).thenReturn(uuid);
when(player.getLocation()).thenReturn(loc);
+ when(player.getWorld()).thenReturn(world);
User.getInstance(player);
// Sometimes use Mockito.withSettings().verboseLogging()
- player2 = mock(Player.class);
+ // Player 2
UUID uuid2 = UUID.randomUUID();
when(player2.getUniqueId()).thenReturn(uuid2);
@@ -144,9 +160,11 @@ public class PVPListenerTest {
when(player2.getLocation()).thenReturn(loc);
User.getInstance(player2);
+ // Util
PowerMockito.mockStatic(Util.class);
when(Util.getWorld(any())).thenReturn(mock(World.class));
+ // Flags Manager
FlagsManager fm = mock(FlagsManager.class);
Flag flag = mock(Flag.class);
when(flag.isSetForWorld(any())).thenReturn(false);
@@ -156,7 +174,7 @@ public class PVPListenerTest {
when(fm.getFlag(Mockito.anyString())).thenReturn(Optional.of(flag));
when(plugin.getFlagsManager()).thenReturn(fm);
- im = mock(IslandsManager.class);
+ // Island Manager
// Default is that player in on their island
when(im.userIsOnIsland(any(), any())).thenReturn(true);
island = mock(Island.class);
@@ -182,12 +200,12 @@ public class PVPListenerTest {
when(placeholdersManager.replacePlaceholders(any(), any())).thenAnswer(answer);
// Create some entities
- zombie = mock(Zombie.class);
when(zombie.getWorld()).thenReturn(world);
when(zombie.getUniqueId()).thenReturn(UUID.randomUUID());
- creeper = mock(Creeper.class);
+ when(zombie.getType()).thenReturn(EntityType.ZOMBIE);
when(creeper.getWorld()).thenReturn(world);
when(creeper.getUniqueId()).thenReturn(UUID.randomUUID());
+ when(creeper.getType()).thenReturn(EntityType.CREEPER);
// Scheduler
BukkitScheduler sch = mock(BukkitScheduler.class);
@@ -204,7 +222,6 @@ public class PVPListenerTest {
when(iwm.getAddon(any())).thenReturn(opGma);
// Notifier
- notifier = mock(Notifier.class);
when(plugin.getNotifier()).thenReturn(notifier);
// Addon
@@ -1000,4 +1017,102 @@ public class PVPListenerTest {
assertFalse(ae.getAffectedEntities().contains(player2));
verify(notifier).notify(any(), eq(Flags.INVINCIBLE_VISITORS.getHintReference()));
}
+
+ /**
+ * Test method for {@link PVPListener#onPlayerShootFireworkEvent(org.bukkit.event.entity.EntityShootBowEvent)}.
+ */
+ @Test
+ public void testOnPlayerShootFireworkEventNotPlayer() {
+ PVPListener listener = new PVPListener();
+ ItemStack bow = new ItemStack(Material.CROSSBOW);
+ Firework firework = mock(Firework.class);
+ when(firework.getEntityId()).thenReturn(123);
+ EntityShootBowEvent e = new EntityShootBowEvent(creeper, bow, firework, 0);
+ listener.onPlayerShootFireworkEvent(e);
+
+ // Now damage
+ EntityDamageByEntityEvent en = new EntityDamageByEntityEvent(firework, player, DamageCause.ENTITY_ATTACK, 0);
+ listener.onEntityDamage(en);
+ assertFalse(en.isCancelled());
+ }
+
+ /**
+ * Test method for {@link PVPListener#onPlayerShootFireworkEvent(org.bukkit.event.entity.EntityShootBowEvent)}.
+ */
+ @Test
+ public void testOnPlayerShootFireworkEventNotFirework() {
+ PVPListener listener = new PVPListener();
+ ItemStack bow = new ItemStack(Material.CROSSBOW);
+ Arrow arrow = mock(Arrow.class);
+ EntityShootBowEvent e = new EntityShootBowEvent(creeper, bow, arrow, 0);
+ listener.onPlayerShootFireworkEvent(e);
+ // Now damage
+ EntityDamageByEntityEvent en = new EntityDamageByEntityEvent(arrow, player, DamageCause.ENTITY_ATTACK, 0);
+ listener.onEntityDamage(en);
+ assertFalse(en.isCancelled());
+ }
+
+ /**
+ * Test method for {@link PVPListener#onPlayerShootFireworkEvent(org.bukkit.event.entity.EntityShootBowEvent)}.
+ */
+ @Test
+ public void testOnPlayerShootFireworkEventNoPVPSelfDamage() {
+ // Disallow PVP
+ when(island.isAllowed(any())).thenReturn(false);
+ PVPListener listener = new PVPListener();
+ ItemStack bow = new ItemStack(Material.CROSSBOW);
+ Firework firework = mock(Firework.class);
+ when(firework.getEntityId()).thenReturn(123);
+ when(firework.getLocation()).thenReturn(loc);
+ EntityShootBowEvent e = new EntityShootBowEvent(player, bow, firework, 0);
+ listener.onPlayerShootFireworkEvent(e);
+
+ // Now damage
+ EntityDamageByEntityEvent en = new EntityDamageByEntityEvent(firework, player, DamageCause.ENTITY_EXPLOSION, 0);
+ listener.onEntityDamage(en);
+ assertFalse(en.isCancelled());
+ }
+
+ /**
+ * Test method for {@link PVPListener#onPlayerShootFireworkEvent(org.bukkit.event.entity.EntityShootBowEvent)}.
+ */
+ @Test
+ public void testOnPlayerShootFireworkEventNoPVP() {
+ // Disallow PVP
+ when(island.isAllowed(any())).thenReturn(false);
+ PVPListener listener = new PVPListener();
+ ItemStack bow = new ItemStack(Material.CROSSBOW);
+ Firework firework = mock(Firework.class);
+ when(firework.getEntityId()).thenReturn(123);
+ when(firework.getLocation()).thenReturn(loc);
+ EntityShootBowEvent e = new EntityShootBowEvent(player, bow, firework, 0);
+ listener.onPlayerShootFireworkEvent(e);
+
+ // Now damage
+ EntityDamageByEntityEvent en = new EntityDamageByEntityEvent(firework, player2, DamageCause.ENTITY_EXPLOSION, 0);
+ listener.onEntityDamage(en);
+ assertTrue(en.isCancelled());
+ }
+
+ /**
+ * Test method for {@link PVPListener#onPlayerShootFireworkEvent(org.bukkit.event.entity.EntityShootBowEvent)}.
+ */
+ @Test
+ public void testOnPlayerShootFireworkEventPVPAllowed() {
+ // Allow PVP
+ when(island.isAllowed(any())).thenReturn(true);
+ PVPListener listener = new PVPListener();
+ ItemStack bow = new ItemStack(Material.CROSSBOW);
+ Firework firework = mock(Firework.class);
+ when(firework.getEntityId()).thenReturn(123);
+ when(firework.getLocation()).thenReturn(loc);
+ EntityShootBowEvent e = new EntityShootBowEvent(player, bow, firework, 0);
+ listener.onPlayerShootFireworkEvent(e);
+
+ // Now damage
+ EntityDamageByEntityEvent en = new EntityDamageByEntityEvent(firework, player2, DamageCause.ENTITY_EXPLOSION, 0);
+ listener.onEntityDamage(en);
+ assertFalse(en.isCancelled());
+ }
+
}
diff --git a/src/test/java/world/bentobox/bentobox/managers/IslandsManagerTest.java b/src/test/java/world/bentobox/bentobox/managers/IslandsManagerTest.java
index a4682a7ab..3761b2744 100644
--- a/src/test/java/world/bentobox/bentobox/managers/IslandsManagerTest.java
+++ b/src/test/java/world/bentobox/bentobox/managers/IslandsManagerTest.java
@@ -66,6 +66,9 @@ import org.powermock.reflect.Whitebox;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
+import io.papermc.lib.PaperLib;
+import io.papermc.lib.environments.CraftBukkitEnvironment;
+import io.papermc.lib.environments.Environment;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.Settings;
import world.bentobox.bentobox.api.configuration.WorldSettings;
@@ -131,6 +134,8 @@ public class IslandsManagerTest {
private Material sign;
private Material wallSign;
+ private Environment env;
+
/**
* @throws java.lang.Exception
@@ -188,6 +193,8 @@ public class IslandsManagerTest {
BukkitScheduler sch = mock(BukkitScheduler.class);
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.getScheduler()).thenReturn(sch);
+ // version
+ when(Bukkit.getVersion()).thenReturn("Paper version git-Paper-225 (MC: 1.14.4) (Implementing API version 1.14.4-R0.1-SNAPSHOT)");
// Standard location
manager = new IslandsManager(plugin);
@@ -295,6 +302,10 @@ public class IslandsManagerTest {
if (wallSign == null) {
wallSign = Material.getMaterial("OAK_WALL_SIGN");
}
+
+ // PaperLib
+ env = new CraftBukkitEnvironment();
+ PaperLib.setCustomEnvironment(env);
}
@After
@@ -716,7 +727,7 @@ public class IslandsManagerTest {
when(pm.getHomeLocation(any(), any(User.class), eq(0))).thenReturn(null);
when(pm.getHomeLocation(any(), any(User.class), eq(1))).thenReturn(location);
im.homeTeleport(world, player, 0);
- verify(player).teleport(location);
+ verify(player).teleport(eq(location), any());
}