diff --git a/InvUI/src/main/java/de/studiocode/invui/item/ItemBuilder.java b/InvUI/src/main/java/de/studiocode/invui/item/builder/BaseItemBuilder.java similarity index 54% rename from InvUI/src/main/java/de/studiocode/invui/item/ItemBuilder.java rename to InvUI/src/main/java/de/studiocode/invui/item/builder/BaseItemBuilder.java index 869cea9..5a5ce26 100644 --- a/InvUI/src/main/java/de/studiocode/invui/item/ItemBuilder.java +++ b/InvUI/src/main/java/de/studiocode/invui/item/builder/BaseItemBuilder.java @@ -1,21 +1,12 @@ -package de.studiocode.invui.item; +package de.studiocode.invui.item.builder; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; -import com.mojang.authlib.properties.PropertyMap; -import de.studiocode.inventoryaccess.util.ReflectionRegistry; -import de.studiocode.inventoryaccess.util.ReflectionUtils; import de.studiocode.inventoryaccess.version.InventoryAccess; +import de.studiocode.invui.item.ItemProvider; import de.studiocode.invui.util.ComponentUtils; -import de.studiocode.invui.util.MojangApiUtils; import de.studiocode.invui.util.Pair; import de.studiocode.invui.window.impl.BaseWindow; import net.md_5.bungee.api.chat.BaseComponent; -import org.bukkit.Bukkit; import org.bukkit.Material; -import org.bukkit.OfflinePlayer; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemFlag; @@ -24,14 +15,11 @@ import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; -import java.io.Serializable; import java.util.*; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; -public class ItemBuilder implements ItemProvider { +abstract class BaseItemBuilder implements ItemProvider { protected ItemStack base; protected Material material; @@ -42,52 +30,39 @@ public class ItemBuilder implements ItemProvider { protected List lore; protected List itemFlags; protected HashMap> enchantments; - protected GameProfile gameProfile; protected List> modifiers; /** - * Constructs a new {@link ItemBuilder} based on the given {@link Material}. + * Constructs a new {@link BaseItemBuilder} based on the given {@link Material}. * * @param material The {@link Material} */ - public ItemBuilder(@NotNull Material material) { + public BaseItemBuilder(@NotNull Material material) { this.material = material; } /** - * Constructs a new {@link ItemBuilder} based on the given {@link Material} and amount. + * Constructs a new {@link BaseItemBuilder} based on the given {@link Material} and amount. * * @param material The {@link Material} * @param amount The amount */ - public ItemBuilder(@NotNull Material material, int amount) { + public BaseItemBuilder(@NotNull Material material, int amount) { this.material = material; this.amount = amount; } /** - * Constructs a new {@link ItemBuilder} based on the give {@link ItemStack}. + * Constructs a new {@link BaseItemBuilder} based on the give {@link ItemStack}. * This will keep the {@link ItemStack} and uses it's {@link ItemMeta} * * @param base The {@link ItemStack to use as a base} */ - public ItemBuilder(@NotNull ItemStack base) { + public BaseItemBuilder(@NotNull ItemStack base) { this.base = base.clone(); this.amount = base.getAmount(); } - /** - * Constructs a new {@link ItemBuilder} of skull with the specified {@link HeadTexture}. - * - * @param headTexture The {@link HeadTexture} - */ - public ItemBuilder(@NotNull HeadTexture headTexture) { - material = Material.PLAYER_HEAD; - gameProfile = new GameProfile(UUID.randomUUID(), null); - PropertyMap propertyMap = gameProfile.getProperties(); - propertyMap.put("textures", new Property("textures", headTexture.getTextureValue())); - } - /** * Builds the {@link ItemStack} * @@ -137,10 +112,6 @@ public class ItemBuilder implements ItemProvider { itemMeta.addItemFlags(itemFlags.toArray(new ItemFlag[0])); } - // game profile - if (gameProfile != null) - ReflectionUtils.setFieldValue(ReflectionRegistry.CB_CRAFT_META_SKULL_PROFILE_FIELD, itemMeta, gameProfile); - // apply to the item stack itemStack.setItemMeta(itemMeta); } @@ -157,7 +128,7 @@ public class ItemBuilder implements ItemProvider { /** * Builds the {@link ItemStack} for a specific player. * This is the method called by {@link BaseWindow} which gives you - * the option to (for example) create a subclass of {@link ItemBuilder} that automatically + * the option to (for example) create a subclass of {@link BaseItemBuilder} that automatically * translates the item's name into the player's language. * * @param playerUUID The {@link UUID} of the {@link Player} @@ -169,81 +140,81 @@ public class ItemBuilder implements ItemProvider { return get(); } - public ItemBuilder setLegacyLore(@NotNull List lore) { + public T setLegacyLore(@NotNull List lore) { this.lore = lore.stream() .map(ComponentUtils::withoutPreFormatting) .collect(Collectors.toList()); - return this; + return getThis(); } - public ItemBuilder addLoreLines(@NotNull String... lines) { + public T addLoreLines(@NotNull String... lines) { if (lore == null) lore = new ArrayList<>(); for (String line : lines) lore.add(ComponentUtils.withoutPreFormatting(line)); - return this; + return getThis(); } - public ItemBuilder addLoreLines(@NotNull BaseComponent[]... lines) { + public T addLoreLines(@NotNull BaseComponent[]... lines) { if (lore == null) lore = new ArrayList<>(); lore.addAll(Arrays.stream(lines).map(ComponentUtils::withoutPreFormatting).collect(Collectors.toList())); - return this; + return getThis(); } - public ItemBuilder removeLoreLine(int index) { + public T removeLoreLine(int index) { if (lore != null) lore.remove(index); - return this; + return getThis(); } - public ItemBuilder clearLore() { + public T clearLore() { if (lore != null) lore.clear(); - return this; + return getThis(); } - public ItemBuilder addItemFlags(@NotNull ItemFlag... itemFlags) { + public T addItemFlags(@NotNull ItemFlag... itemFlags) { if (this.itemFlags == null) this.itemFlags = new ArrayList<>(); this.itemFlags.addAll(Arrays.asList(itemFlags)); - return this; + return getThis(); } - public ItemBuilder removeItemFlags(@NotNull ItemFlag... itemFlags) { + public T removeItemFlags(@NotNull ItemFlag... itemFlags) { if (this.itemFlags != null) this.itemFlags.removeAll(Arrays.asList(itemFlags)); - return this; + return getThis(); } - public ItemBuilder clearItemFlags() { + public T clearItemFlags() { if (itemFlags != null) itemFlags.clear(); - return this; + return getThis(); } - public ItemBuilder addEnchantment(Enchantment enchantment, int level, boolean ignoreLevelRestriction) { + public T addEnchantment(Enchantment enchantment, int level, boolean ignoreLevelRestriction) { if (enchantments == null) enchantments = new HashMap<>(); enchantments.put(enchantment, new Pair<>(level, ignoreLevelRestriction)); - return this; + return getThis(); } - public ItemBuilder removeEnchantment(Enchantment enchantment) { + public T removeEnchantment(Enchantment enchantment) { if (enchantments == null) enchantments = new HashMap<>(); enchantments.remove(enchantment); - return this; + return getThis(); } - public ItemBuilder clearEnchantments() { + public T clearEnchantments() { if (enchantments != null) enchantments.clear(); - return this; + return getThis(); } - public ItemBuilder addModifier(Function modifier) { + public T addModifier(Function modifier) { if (modifiers == null) modifiers = new ArrayList<>(); modifiers.add(modifier); - return this; + return getThis(); } - public ItemBuilder clearModifiers() { + public T clearModifiers() { if (modifiers != null) modifiers.clear(); - return this; + return getThis(); } public ItemStack getBase() { @@ -254,162 +225,100 @@ public class ItemBuilder implements ItemProvider { return material; } - public ItemBuilder setMaterial(@NotNull Material material) { + public T setMaterial(@NotNull Material material) { this.material = material; - return this; + return getThis(); } public int getAmount() { return amount; } - public ItemBuilder setAmount(int amount) { + public T setAmount(int amount) { this.amount = amount; - return this; + return getThis(); } public int getDamage() { return damage; } - public ItemBuilder setDamage(int damage) { + public T setDamage(int damage) { this.damage = damage; - return this; + return getThis(); } public int getCustomModelData() { return customModelData; } - public ItemBuilder setCustomModelData(int customModelData) { + public T setCustomModelData(int customModelData) { this.customModelData = customModelData; - return this; + return getThis(); } public BaseComponent[] getDisplayName() { return displayName; } - public ItemBuilder setDisplayName(String displayName) { + public T setDisplayName(String displayName) { this.displayName = ComponentUtils.withoutPreFormatting(displayName); - return this; + return getThis(); } - public ItemBuilder setDisplayName(BaseComponent... displayName) { + public T setDisplayName(BaseComponent... displayName) { this.displayName = ComponentUtils.withoutPreFormatting(displayName); - return this; + return getThis(); } public List getLore() { return lore; } - public ItemBuilder setLore(List lore) { + public T setLore(List lore) { this.lore = lore; - return this; + return getThis(); } public List getItemFlags() { return itemFlags; } - public ItemBuilder setItemFlags(@NotNull List itemFlags) { + public T setItemFlags(@NotNull List itemFlags) { this.itemFlags = itemFlags; - return this; + return getThis(); } public HashMap> getEnchantments() { return enchantments; } - public ItemBuilder setEnchantments(@NotNull HashMap> enchantments) { + public T setEnchantments(@NotNull HashMap> enchantments) { this.enchantments = enchantments; - return this; - } - - public GameProfile getGameProfile() { - return gameProfile; + return getThis(); } public List> getModifiers() { return modifiers; } + @SuppressWarnings("unchecked") @Override - public ItemBuilder clone() { + public T clone() { try { - ItemBuilder clone = ((ItemBuilder) super.clone()); + BaseItemBuilder clone = ((BaseItemBuilder) super.clone()); if (base != null) clone.base = base.clone(); if (lore != null) clone.lore = new ArrayList<>(lore); if (itemFlags != null) clone.itemFlags = new ArrayList<>(itemFlags); if (enchantments != null) clone.enchantments = new HashMap<>(enchantments); if (modifiers != null) clone.modifiers = new ArrayList<>(modifiers); - return clone; + return (T) clone; } catch (CloneNotSupportedException e) { throw new AssertionError(e); } } - /** - * Contains the texture value for a player head. - * - * @see ItemBuilder - */ - public static class HeadTexture implements Serializable { - - private static final Cache textureCache = CacheBuilder.newBuilder() - .expireAfterWrite(1, TimeUnit.DAYS) - .build(); - - private static final Cache uuidCache = CacheBuilder.newBuilder() - .expireAfterWrite(1, TimeUnit.DAYS) - .build(); - - private final String textureValue; - - public HeadTexture(@NotNull String textureValue) { - this.textureValue = textureValue; - } - - public static HeadTexture of(@NotNull OfflinePlayer offlinePlayer) { - return of(offlinePlayer.getUniqueId()); - } - - @SuppressWarnings("deprecation") - public static HeadTexture of(@NotNull String playerName) { - if (Bukkit.getServer().getOnlineMode()) { - // if the server is in online mode, the Minecraft UUID cache (usercache.json) can be used - return of(Bukkit.getOfflinePlayer(playerName).getUniqueId()); - } else { - // the server isn't in online mode - the UUID has to be retrieved from the Mojang API - try { - return of(uuidCache.get(playerName, () -> MojangApiUtils.getCurrentUUID(playerName))); - } catch (ExecutionException e) { - e.printStackTrace(); - return null; - } - } - } - - public static HeadTexture of(@NotNull UUID uuid) { - try { - return new HeadTexture(textureCache.get(uuid, () -> MojangApiUtils.getSkinData(uuid, false)[0])); - } catch (ExecutionException e) { - e.printStackTrace(); - return null; - } - } - - public static void invalidateCache() { - uuidCache.invalidateAll(); - textureCache.invalidateAll(); - } - - public String getTextureValue() { - return textureValue; - } - - } + protected abstract T getThis(); } diff --git a/InvUI/src/main/java/de/studiocode/invui/item/builder/ItemBuilder.java b/InvUI/src/main/java/de/studiocode/invui/item/builder/ItemBuilder.java new file mode 100644 index 0000000..b02eda1 --- /dev/null +++ b/InvUI/src/main/java/de/studiocode/invui/item/builder/ItemBuilder.java @@ -0,0 +1,44 @@ +package de.studiocode.invui.item.builder; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; + +public final class ItemBuilder extends BaseItemBuilder { + + /** + * Constructs a new {@link BaseItemBuilder} based on the given {@link Material}. + * + * @param material The {@link Material} + */ + public ItemBuilder(@NotNull Material material) { + super(material); + } + + /** + * Constructs a new {@link BaseItemBuilder} based on the given {@link Material} and amount. + * + * @param material The {@link Material} + * @param amount The amount + */ + public ItemBuilder(@NotNull Material material, int amount) { + super(material, amount); + } + + /** + * Constructs a new {@link BaseItemBuilder} based on the give {@link ItemStack}. + * This will keep the {@link ItemStack} and uses it's {@link ItemMeta} + * + * @param base The {@link ItemStack to use as a base} + */ + public ItemBuilder(@NotNull ItemStack base) { + super(base); + } + + @Override + protected ItemBuilder getThis() { + return this; + } + +} diff --git a/InvUI/src/main/java/de/studiocode/invui/item/builder/PotionBuilder.java b/InvUI/src/main/java/de/studiocode/invui/item/builder/PotionBuilder.java new file mode 100644 index 0000000..385d969 --- /dev/null +++ b/InvUI/src/main/java/de/studiocode/invui/item/builder/PotionBuilder.java @@ -0,0 +1,91 @@ +package de.studiocode.invui.item.builder; + +import org.bukkit.Color; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionData; +import org.bukkit.potion.PotionEffect; + +import java.util.ArrayList; +import java.util.List; + +public class PotionBuilder extends BaseItemBuilder { + + private List effects = new ArrayList<>(); + private Color color; + private PotionData basePotionData; + + public PotionBuilder(PotionType type) { + super(type.getMaterial()); + } + + public PotionBuilder(ItemStack base) { + super(base); + } + + public PotionBuilder setColor(Color color) { + this.color = color; + return this; + } + + public PotionBuilder setColor(java.awt.Color color) { + this.color = Color.fromRGB(color.getRed(), color.getGreen(), color.getBlue()); + return this; + } + + public PotionBuilder setBasePotionData(PotionData basePotionData) { + this.basePotionData = basePotionData; + return this; + } + + public PotionBuilder addEffect(PotionEffect effect) { + effects.add(effect); + return this; + } + + @Override + public ItemStack get() { + ItemStack item = super.get(); + PotionMeta meta = (PotionMeta) item.getItemMeta(); + + meta.clearCustomEffects(); + if (color != null) meta.setColor(color); + if (basePotionData != null) meta.setBasePotionData(basePotionData); + effects.forEach(effect -> meta.addCustomEffect(effect, true)); + + item.setItemMeta(meta); + return item; + } + + @Override + public PotionBuilder clone() { + PotionBuilder builder = super.clone(); + builder.effects = new ArrayList<>(effects); + return builder; + } + + @Override + protected PotionBuilder getThis() { + return null; + } + + public enum PotionType { + + NORMAL(Material.POTION), + SPLASH(Material.SPLASH_POTION), + LINGERING(Material.LINGERING_POTION); + + private final Material material; + + PotionType(Material material) { + this.material = material; + } + + public Material getMaterial() { + return material; + } + + } + +} diff --git a/InvUI/src/main/java/de/studiocode/invui/item/builder/SkullBuilder.java b/InvUI/src/main/java/de/studiocode/invui/item/builder/SkullBuilder.java new file mode 100644 index 0000000..4adcdcd --- /dev/null +++ b/InvUI/src/main/java/de/studiocode/invui/item/builder/SkullBuilder.java @@ -0,0 +1,194 @@ +package de.studiocode.invui.item.builder; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import de.studiocode.inventoryaccess.util.ReflectionRegistry; +import de.studiocode.inventoryaccess.util.ReflectionUtils; +import de.studiocode.invui.util.MojangApiUtils; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; + +import java.io.Serializable; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +public final class SkullBuilder extends BaseItemBuilder { + + private GameProfile gameProfile; + + /** + * Create a {@link SkullBuilder} of a {@link Player Player's} {@link UUID}. + * + * @param uuid The {@link UUID} of the skull owner. + */ + public SkullBuilder(UUID uuid) { + this(HeadTexture.of(uuid)); + } + + /** + * Create a {@link SkullBuilder} with the {@link Player Player's} username. + * + * @param username The username of the skull owner. + */ + public SkullBuilder(String username) { + this(HeadTexture.of(username)); + } + + /** + * Create a {@link SkullBuilder} with a {@link HeadTexture}. + * + * @param headTexture The {@link HeadTexture} to be applied to the skull. + */ + public SkullBuilder(HeadTexture headTexture) { + super(Material.PLAYER_HEAD); + setGameProfile(headTexture); + } + + private void setGameProfile(HeadTexture texture) { + gameProfile = new GameProfile(UUID.randomUUID(), null); + PropertyMap propertyMap = gameProfile.getProperties(); + propertyMap.put("textures", new Property("textures", texture.getTextureValue())); + } + + @Override + public ItemStack get() { + ItemStack item = super.get(); + ItemMeta meta = item.getItemMeta(); + + if (gameProfile != null) + ReflectionUtils.setFieldValue(ReflectionRegistry.CB_CRAFT_META_SKULL_PROFILE_FIELD, meta, gameProfile); + + item.setItemMeta(meta); + + return item; + } + + @Override + public SkullBuilder setMaterial(@NotNull Material material) { + return this; + } + + @Override + protected SkullBuilder getThis() { + return null; + } + + /** + * Contains the texture value for a player head. + * + * @see SkullBuilder + */ + public static class HeadTexture implements Serializable { + + private static final Cache textureCache = CacheBuilder.newBuilder() + .expireAfterWrite(1, TimeUnit.DAYS) + .build(); + + private static final Cache uuidCache = CacheBuilder.newBuilder() + .expireAfterWrite(1, TimeUnit.DAYS) + .build(); + + private final String textureValue; + + /** + * Creates a new {@link HeadTexture} from the raw texture value. + * + * @param textureValue The texture value of this {@link HeadTexture} + * @see HeadTexture#of(OfflinePlayer) + * @see HeadTexture#of(UUID) + * @see HeadTexture#of(String) + */ + public HeadTexture(@NotNull String textureValue) { + this.textureValue = textureValue; + } + + /** + * Retrieves the {@link HeadTexture} from this {@link OfflinePlayer} + * Please note that this data might not be pulled from the Mojang API as it might already be cached. + * Use {@link HeadTexture#invalidateCache()} to invalidate the cache. + * + * @param offlinePlayer The skull owner. + * @return The {@link HeadTexture} of that player. + * @see HeadTexture#of(UUID) + */ + public static HeadTexture of(@NotNull OfflinePlayer offlinePlayer) { + return of(offlinePlayer.getUniqueId()); + } + + /** + * Retrieves the {@link HeadTexture} from the username of the skull owner. + * This will first retrieve the {@link UUID} of the player from either Bukkit's usercache.json file + * (if the server is in only mode) or from the Mojang API (if the server is in offline mode). + *

+ * Please note that this data might not be pulled from the Mojang API as it might already be cached. + * Use {@link HeadTexture#invalidateCache()} to invalidate the cache. + * + * @param playerName The username of the player. + * @return The {@link HeadTexture} of that player. + * @see HeadTexture#of(UUID) + */ + @SuppressWarnings("deprecation") + public static HeadTexture of(@NotNull String playerName) { + if (Bukkit.getServer().getOnlineMode()) { + // if the server is in online mode, the Minecraft UUID cache (usercache.json) can be used + return of(Bukkit.getOfflinePlayer(playerName).getUniqueId()); + } else { + // the server isn't in online mode - the UUID has to be retrieved from the Mojang API + try { + return of(uuidCache.get(playerName, () -> MojangApiUtils.getCurrentUUID(playerName))); + } catch (ExecutionException e) { + e.printStackTrace(); + return null; + } + } + } + + /** + * Retrieves the {@link HeadTexture} from the {@link UUID} of the skull owner. + * Please note that this data might not be pulled from the Mojang API as it might already be cached. + * Use {@link HeadTexture#invalidateCache()} to invalidate the cache. + * + * @param uuid The {@link UUID} of the skull owner. + * @return The {@link HeadTexture} of that player. + */ + public static HeadTexture of(@NotNull UUID uuid) { + try { + return new HeadTexture(textureCache.get(uuid, () -> MojangApiUtils.getSkinData(uuid, false)[0])); + } catch (ExecutionException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Invalidates the uuid and texture value cache. + * This means that when {@link HeadTexture#of(OfflinePlayer)}, {@link HeadTexture#of(UUID)} + * and {@link HeadTexture#of(String)} are called, these values will be pulled from the + * Mojang API again. + */ + public static void invalidateCache() { + uuidCache.invalidateAll(); + textureCache.invalidateAll(); + } + + /** + * Gets the stored texture value. + * + * @return The stored texture value. + */ + public String getTextureValue() { + return textureValue; + } + + } + +} diff --git a/InvUI/src/main/java/de/studiocode/invui/item/impl/AsyncItem.java b/InvUI/src/main/java/de/studiocode/invui/item/impl/AsyncItem.java index ea14170..5e57e27 100644 --- a/InvUI/src/main/java/de/studiocode/invui/item/impl/AsyncItem.java +++ b/InvUI/src/main/java/de/studiocode/invui/item/impl/AsyncItem.java @@ -2,13 +2,14 @@ package de.studiocode.invui.item.impl; import de.studiocode.invui.InvUI; import de.studiocode.invui.item.Item; -import de.studiocode.invui.item.ItemBuilder; import de.studiocode.invui.item.ItemProvider; +import de.studiocode.invui.item.ItemWrapper; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -23,7 +24,7 @@ public class AsyncItem extends BaseItem { private volatile ItemProvider itemProvider; public AsyncItem(@Nullable ItemProvider itemProvider, @NotNull Supplier providerSupplier) { - this.itemProvider = itemProvider == null ? new ItemBuilder(Material.AIR) : itemProvider; + this.itemProvider = itemProvider == null ? new ItemWrapper(new ItemStack(Material.AIR)) : itemProvider; Bukkit.getScheduler().runTaskAsynchronously(InvUI.getInstance().getPlugin(), () -> { this.itemProvider = providerSupplier.get(); diff --git a/InvUI/src/main/java/de/studiocode/invui/resourcepack/Icon.java b/InvUI/src/main/java/de/studiocode/invui/resourcepack/Icon.java index 5099693..891a09f 100644 --- a/InvUI/src/main/java/de/studiocode/invui/resourcepack/Icon.java +++ b/InvUI/src/main/java/de/studiocode/invui/resourcepack/Icon.java @@ -1,7 +1,7 @@ package de.studiocode.invui.resourcepack; import de.studiocode.invui.item.Item; -import de.studiocode.invui.item.ItemBuilder; +import de.studiocode.invui.item.builder.ItemBuilder; import de.studiocode.invui.item.impl.SimpleItem; import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.Material;