Merge pull request #2580 from BentoBoxWorld/Abstract_out_paper_lib

Abstract out paper lib
This commit is contained in:
tastybento 2024-12-29 13:49:53 -08:00 committed by GitHub
commit da8ad2f63c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 103 additions and 123 deletions

14
pom.xml
View File

@ -233,6 +233,13 @@
<version>4.2.2</version>
<scope>test</scope>
</dependency>
<!-- Paper API -->
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>${paper.version}</version>
<scope>provided</scope>
</dependency>
<!-- Spigot API -->
<dependency>
<groupId>org.spigotmc</groupId>
@ -357,13 +364,6 @@
<artifactId>org.eclipse.jdt.annotation</artifactId>
<version>2.2.600</version>
</dependency>
<!-- PaperLib -->
<dependency>
<groupId>io.papermc</groupId>
<artifactId>paperlib</artifactId>
<version>1.0.6</version>
<scope>compile</scope>
</dependency>
<!-- LangUtils -->
<dependency>
<groupId>com.github.apachezy</groupId>

View File

@ -12,8 +12,6 @@ import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import de.oliver.fancynpcs.api.Npc;
import lol.pyr.znpcsplus.api.npc.NpcEntry;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;
/**

View File

@ -30,7 +30,6 @@ import de.oliver.fancynpcs.api.actions.ActionTrigger;
import de.oliver.fancynpcs.api.actions.NpcAction;
import de.oliver.fancynpcs.api.utils.NpcEquipmentSlot;
import de.oliver.fancynpcs.api.utils.SkinFetcher;
import lol.pyr.znpcsplus.api.npc.NpcEntry;
import net.kyori.adventure.text.format.NamedTextColor;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.hooks.NPCHook;

View File

@ -13,11 +13,11 @@ import org.bukkit.event.vehicle.VehicleMoveEvent;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import io.papermc.lib.PaperLib;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.flags.FlagListener;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.util.Util;
/**
* Listener for the lock flag
@ -164,7 +164,7 @@ public class LockAndBanListener extends FlagListener {
// We'll try to teleport him to the spawn...
Location l = player.getWorld().getSpawnLocation();
if (l != null) {
PaperLib.teleportAsync(player, l);
Util.teleportAsync(player, l);
}
// Switch him back to the default gamemode. He may die, sorry :(

View File

@ -40,7 +40,6 @@ import com.github.puregero.multilib.MultiLib;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
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;
@ -1080,7 +1079,7 @@ public class IslandsManager {
.ifFail(() -> goingHome.remove(user.getUniqueId())).buildFuture().thenAccept(result::complete);
return;
}
PaperLib.teleportAsync(Objects.requireNonNull(player), home).thenAccept(b -> {
Util.teleportAsync(Objects.requireNonNull(player), home).thenAccept(b -> {
// Only run the commands if the player is successfully teleported
if (Boolean.TRUE.equals(b)) {
teleported(world, user, name, newIsland, island);
@ -1192,7 +1191,6 @@ public class IslandsManager {
*
* @param player player
*/
@SuppressWarnings("deprecation")
private void readyPlayer(@NonNull Player player) {
// Stop any gliding
player.setGliding(false);
@ -1469,7 +1467,7 @@ public class IslandsManager {
} else {
// Move player to spawn
getSpawn(w).map(i -> i.getSpawnPoint(w.getEnvironment())).filter(Objects::nonNull)
.ifPresentOrElse(sp -> PaperLib.teleportAsync(p, sp),
.ifPresentOrElse(sp -> Util.teleportAsync(p, sp),
() -> plugin.logWarning("Spawn exists but its location is null!"));
}

View File

@ -15,9 +15,9 @@ import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.island.IslandCreateEvent;
import world.bentobox.bentobox.api.events.island.IslandEvent;
import world.bentobox.bentobox.api.events.island.IslandEvent.Reason;
import world.bentobox.bentobox.api.events.island.IslandResetEvent;
import world.bentobox.bentobox.api.logs.LogEntry;
import world.bentobox.bentobox.api.logs.LogEntry.LogType;
import world.bentobox.bentobox.api.events.island.IslandResetEvent;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.BlueprintsManager;

View File

@ -38,7 +38,6 @@ import org.bukkit.util.BoundingBox;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import io.papermc.lib.PaperLib;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.hooks.Hook;
@ -48,6 +47,7 @@ import world.bentobox.bentobox.hooks.ItemsAdderHook;
import world.bentobox.bentobox.hooks.SlimefunHook;
import world.bentobox.bentobox.hooks.ZNPCsPlusHook;
import world.bentobox.bentobox.util.MyBiomeGrid;
import world.bentobox.bentobox.util.Util;
/**
* Regenerates by using a seed world. The seed world is created using the same generator as the game
@ -148,7 +148,7 @@ public abstract class CopyWorldRegenerator implements WorldRegenerator {
CompletableFuture<Chunk> seedWorldFuture = getSeedWorldChunk(world, chunkX, chunkZ);
// Set up a future to get the chunk requests using Paper's Lib. If Paper is used, this should be done async
CompletableFuture<Chunk> chunkFuture = PaperLib.getChunkAtAsync(world, chunkX, chunkZ);
CompletableFuture<Chunk> chunkFuture = Util.getChunkAtAsync(world, chunkX, chunkZ);
// If there is no island, do not clean chunk
CompletableFuture<Void> cleanFuture = di != null ? cleanChunk(chunkFuture, di) : CompletableFuture.completedFuture(null);
@ -172,7 +172,7 @@ public abstract class CopyWorldRegenerator implements WorldRegenerator {
private CompletableFuture<Chunk> getSeedWorldChunk(World world, int chunkX, int chunkZ) {
World seed = Bukkit.getWorld(world.getName() + "/bentobox");
if (seed == null) return CompletableFuture.completedFuture(null);
return PaperLib.getChunkAtAsync(seed, chunkX, chunkZ);
return Util.getChunkAtAsync(seed, chunkX, chunkZ);
}
/**
@ -247,6 +247,7 @@ public abstract class CopyWorldRegenerator implements WorldRegenerator {
Arrays.stream(fromChunk.getTileEntities()).forEach(bs -> processTileEntity(bs.getBlock(), bs.getLocation().toVector().toLocation(toChunk.getWorld()).getBlock()));
}
@SuppressWarnings("deprecation")
private void processEntity(Entity entity, Location location) {
Entity bpe = location.getWorld().spawnEntity(location, entity.getType());
bpe.setCustomName(entity.getCustomName());
@ -374,7 +375,7 @@ public abstract class CopyWorldRegenerator implements WorldRegenerator {
@SuppressWarnings("deprecation")
private CompletableFuture<Void> regenerateChunk(GameModeAddon gm, IslandDeletion di, @Nonnull World world,
int chunkX, int chunkZ) {
CompletableFuture<Chunk> chunkFuture = PaperLib.getChunkAtAsync(world, chunkX, chunkZ);
CompletableFuture<Chunk> chunkFuture = Util.getChunkAtAsync(world, chunkX, chunkZ);
CompletableFuture<Void> invFuture = chunkFuture.thenAccept(chunk ->
Arrays.stream(chunk.getTileEntities()).filter(InventoryHolder.class::isInstance)
.filter(te -> di.inBounds(te.getLocation().getBlockX(), te.getLocation().getBlockZ()))

View File

@ -1,6 +1,7 @@
package world.bentobox.bentobox.util;
import java.io.IOException;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@ -26,7 +27,6 @@ import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.attribute.Attribute;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Allay;
import org.bukkit.entity.Animals;
@ -51,8 +51,6 @@ import org.eclipse.jdt.annotation.Nullable;
import com.google.common.base.Enums;
import com.google.common.base.Optional;
import io.papermc.lib.PaperLib;
import io.papermc.lib.features.blockstatesnapshot.BlockStateSnapshotResult;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.nms.PasteHandler;
@ -382,7 +380,7 @@ public class Util {
*/
@NonNull
public static CompletableFuture<Boolean> teleportAsync(@Nonnull Entity entity, @Nonnull Location location) {
return PaperLib.teleportAsync(entity, location);
return teleportAsync(entity, location, TeleportCause.UNKNOWN);
}
/**
@ -392,12 +390,26 @@ public class Util {
* @param cause The cause for the teleportation
* @return Future that completes with the result of the teleport
*/
@SuppressWarnings("unchecked")
@NonNull
public static CompletableFuture<Boolean> teleportAsync(@Nonnull Entity entity, @Nonnull Location location,
TeleportCause cause) {
return PaperLib.teleportAsync(entity, location, cause);
try {
// Use reflection to check if the method exists
Method method = Entity.class.getMethod("teleportAsync", Location.class, TeleportCause.class);
if (method != null) {
// Invoke the method using reflection on the entity instance
return (CompletableFuture<Boolean>) method.invoke(entity, location, cause);
}
} catch (NoSuchMethodException e) {
// Method does not exist, fallback to Spigot behavior
} catch (Exception e) {
plugin.logStacktrace(e); // Report other exceptions
}
// Fallback for Spigot servers
entity.teleport(location, cause);
return CompletableFuture.completedFuture(true);
}
/**
* Gets the chunk at the target location, loading it asynchronously if needed.
* @param loc Location to get chunk for
@ -440,9 +452,24 @@ public class Util {
* @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.
*/
@SuppressWarnings("unchecked")
@NonNull
public static CompletableFuture<Chunk> getChunkAtAsync(@Nonnull World world, int x, int z, boolean gen) {
return PaperLib.getChunkAtAsync(world, x, z, gen);
try {
// Use reflection to check if the method exists
Method method = World.class.getMethod("getChunkAtAsync", int.class, int.class, boolean.class);
if (method != null) {
// Invoke the method using reflection
return (CompletableFuture<Chunk>) method.invoke(world, x, z, gen);
}
} catch (NoSuchMethodException e) {
// Method does not exist, fallback to Spigot behavior
} catch (Exception e) {
e.printStackTrace(); // Handle other exceptions (optional)
}
// Fallback for Spigot servers
return CompletableFuture.completedFuture(world.getChunkAt(x, z, gen));
}
/**
@ -462,56 +489,7 @@ public class Util {
* @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.
* <p>
* 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();
return world.isChunkGenerated(x, z);
}
/**
@ -562,42 +540,26 @@ public class Util {
return !(!isRequiredSnapshot && isVersionSnapshot);
}
/**
* Check if the server has access to the Spigot API
* @return True for Spigot <em>and</em> 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 !isJUnitTest() && PaperLib.isPaper();
}
/**
* I don't like doing this, but otherwise we need to set a flag in every test
*/
private static boolean isJUnitTest() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for (StackTraceElement element : stackTrace) {
if (element.getClassName().startsWith("org.junit.")) {
return true;
}
try {
Class.forName("com.destroystokyo.paper.PaperConfig");
return true; // Paper-specific class exists
} catch (ClassNotFoundException e) {
return false; // Not a Paper server
}
return false;
}
/**
* This method translates color codes in given string and strips whitespace after them.
* This code parses both: hex and old color codes.
* @param textToColor Text which color codes must be parsed.
* @return String text with parsed colors and stripped whitespaces after them.
*/
@SuppressWarnings("deprecation")
@NonNull
public static String translateColorCodes(@NonNull String textToColor) {
// Use matcher to find hex patterns in given text.
@ -760,8 +722,14 @@ public class Util {
* @param player - player
*/
public static void resetHealth(Player player) {
double maxHealth = player.getAttribute(Attribute.MAX_HEALTH).getBaseValue();
player.setHealth(maxHealth);
try {
// Paper
double maxHealth = player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getBaseValue();
player.setHealth(maxHealth);
} catch (Exception e) {
// Spigot
player.setHealth(20D);
}
}
/**
@ -862,6 +830,7 @@ public class Util {
* @param input Input that need to be sanitized.
* @return A sanitized input without illegal characters in names.
*/
@SuppressWarnings("deprecation")
public static String sanitizeInput(String input)
{
return ChatColor.stripColor(

View File

@ -72,6 +72,7 @@ public class IslandTeamInviteCommandTest extends RanksManagerBeforeClassTest {
private IslandTeamInviteCommand itl;
private UUID notUUID;
@SuppressWarnings("deprecation")
@Before
public void setUp() throws Exception {
super.setUp();
@ -168,7 +169,7 @@ public class IslandTeamInviteCommandTest extends RanksManagerBeforeClassTest {
when(itemFactory.getItemMeta(any())).thenReturn(bannerMeta);
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
Inventory inventory = mock(Inventory.class);
when(Bukkit.createInventory(eq(null), anyInt(), any())).thenReturn(inventory);
when(Bukkit.createInventory(eq(null), anyInt(), anyString())).thenReturn(inventory);
// Command under test
itl = new IslandTeamInviteCommand(ic);

View File

@ -3,6 +3,7 @@ package world.bentobox.bentobox.database.json.adapters;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@ -94,7 +95,7 @@ public class ItemStackTypeAdapterTest {
// Mock up the deserialization
PowerMockito.mockStatic(ItemStack.class);
when(ItemStack.deserialize(any())).thenReturn(new ItemStack(Material.STONE, 4));
when(ItemStack.deserialize(anyMap())).thenReturn(new ItemStack(Material.STONE, 4));
}
@After

View File

@ -338,7 +338,7 @@ public class BreakBlocksListenerTest extends AbstractCommonSetup {
when(island.isAllowed(any(), any())).thenReturn(false);
Vehicle vehicle = mock(Vehicle.class);
when(vehicle.getLocation()).thenReturn(location);
when(vehicle.getType()).thenReturn(EntityType.OAK_BOAT);
when(vehicle.getType()).thenReturn(EntityType.BOAT);
VehicleDamageEvent e = new VehicleDamageEvent(vehicle, mockPlayer, 10);
bbl.onVehicleDamageEvent(e);
assertTrue(e.isCancelled());

View File

@ -181,7 +181,7 @@ public class InvincibleVisitorsListenerTest {
when(top.getSize()).thenReturn(9);
when(panel.getInventory()).thenReturn(top);
when(Bukkit.createInventory(any(), anyInt(), any())).thenReturn(top);
when(Bukkit.createInventory(any(), anyInt(), anyString())).thenReturn(top);
}
@After

View File

@ -74,9 +74,6 @@ import com.github.puregero.multilib.MultiLib;
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.AbstractCommonSetup;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.Settings;
@ -148,8 +145,6 @@ public class IslandsManagerTest extends AbstractCommonSetup {
private Material sign;
private Material wallSign;
private Environment env;
// Class under test
IslandsManager im;
@ -170,7 +165,7 @@ public class IslandsManagerTest extends AbstractCommonSetup {
}
@Override
@SuppressWarnings("unchecked")
@SuppressWarnings({ "unchecked", "deprecation" })
@Before
public void setUp() throws Exception {
super.setUp();
@ -350,10 +345,6 @@ public class IslandsManagerTest extends AbstractCommonSetup {
sign = Material.BIRCH_SIGN;
wallSign = Material.ACACIA_WALL_SIGN;
// PaperLib
env = new CraftBukkitEnvironment();
PaperLib.setCustomEnvironment(env);
// Util strip spaces
when(Util.stripSpaceAfterColorCodes(anyString())).thenCallRealMethod();
@ -423,7 +414,6 @@ public class IslandsManagerTest extends AbstractCommonSetup {
assertFalse(im.isSafeLocation(location));
}
@SuppressWarnings("deprecation")
@Test
@Ignore("Material#isSolid() cannot be tested")
public void testCheckIfSafeTrapdoor() {

View File

@ -181,7 +181,7 @@ public class PlayersManagerTest {
when(p.getUniqueId()).thenReturn(uuid);
AttributeInstance at = mock(AttributeInstance.class);
when(at.getValue()).thenReturn(20D);
when(p.getAttribute(Attribute.MAX_HEALTH)).thenReturn(at);
when(p.getAttribute(Attribute.GENERIC_MAX_HEALTH)).thenReturn(at);
when(p.getName()).thenReturn("tastybento");
User.getInstance(p);

View File

@ -1,5 +1,6 @@
package world.bentobox.bentobox.mocks;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
@ -21,10 +22,26 @@ import org.bukkit.Server;
import org.bukkit.Tag;
import org.bukkit.UnsafeValues;
import org.eclipse.jdt.annotation.NonNull;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import io.papermc.paper.ServerBuildInfo;
@RunWith(PowerMockRunner.class)
@PrepareForTest(ServerBuildInfo.class)
public final class ServerMocks {
@Mock
private static ServerBuildInfo sbi;
public static @NonNull Server newServer() {
PowerMockito.mockStatic(ServerBuildInfo.class, Mockito.RETURNS_MOCKS);
when(sbi.asString(any())).thenReturn("Mock server version");
when(ServerBuildInfo.buildInfo()).thenReturn(sbi);
Server mock = mock(Server.class);
Logger noOp = mock(Logger.class);
@ -66,7 +83,7 @@ public final class ServerMocks {
doReturn(key).when(keyed).getKey();
return keyed;
});
}).when(registry).get(notNull());
}).when(registry).get((NamespacedKey) notNull());
return registry;
})).when(mock).getRegistry(notNull());

View File

@ -80,7 +80,7 @@ public class BlueprintManagementPanelTest {
ItemFactory itemFac = mock(ItemFactory.class);
when(Bukkit.getItemFactory()).thenReturn(itemFac);
// Panel inventory
when(Bukkit.createInventory(any(), Mockito.anyInt(), any())).thenReturn(inv);
when(Bukkit.createInventory(any(), Mockito.anyInt(), anyString())).thenReturn(inv);
// Player
Player player = mock(Player.class);

View File

@ -37,6 +37,7 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import io.papermc.paper.ServerBuildInfo;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.Settings;
import world.bentobox.bentobox.api.addons.GameModeAddon;
@ -48,13 +49,14 @@ import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.PlayersManager;
import world.bentobox.bentobox.mocks.ServerMocks;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Bukkit.class, BentoBox.class })
@PrepareForTest({ Bukkit.class, BentoBox.class, ServerBuildInfo.class })
public class IslandCreationPanelTest {
@Mock
@ -89,6 +91,8 @@ public class IslandCreationPanelTest {
*/
@Before
public void setUp() throws Exception {
ServerMocks.newServer();
PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
// Set up plugin
@ -160,7 +164,8 @@ public class IslandCreationPanelTest {
when(plugin.getIWM()).thenReturn(iwm);
// Panel inventory
when(Bukkit.createInventory(any(), Mockito.anyInt(), any())).thenReturn(inv);
when(Bukkit.createInventory(any(), Mockito.anyInt(), anyString())).thenReturn(inv);
// Item Factory (needed for ItemStack)
ItemFactory itemF = mock(ItemFactory.class);
@ -202,6 +207,7 @@ public class IslandCreationPanelTest {
public void tearDown() {
User.clearUsers();
Mockito.framework().clearInlineMocks();
ServerMocks.unsetBukkitServer();
}
/**

View File

@ -131,7 +131,7 @@ public class LanguagePanelTest {
// Panel
PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
when(Bukkit.createInventory(any(), Mockito.anyInt(), any())).thenReturn(inv);
when(Bukkit.createInventory(any(), Mockito.anyInt(), anyString())).thenReturn(inv);
// Item Factory (needed for ItemStack)
ItemFactory itemF = mock(ItemFactory.class);