From 5a5c60cd6a4af7a24d99f5fac8f70919632681ca Mon Sep 17 00:00:00 2001 From: LoJoSho Date: Fri, 23 Feb 2024 14:06:27 -0600 Subject: [PATCH] feat: initial item builder work --- .../hibiscuscommons/items/ItemBuilder.java | 345 ++++++++++++++++++ .../hibiscuscommons/items/LoreAppendMode.java | 8 + 2 files changed, 353 insertions(+) create mode 100644 common/src/main/java/me/lojosho/hibiscuscommons/items/ItemBuilder.java create mode 100644 common/src/main/java/me/lojosho/hibiscuscommons/items/LoreAppendMode.java diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/items/ItemBuilder.java b/common/src/main/java/me/lojosho/hibiscuscommons/items/ItemBuilder.java new file mode 100644 index 0000000..0176476 --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/items/ItemBuilder.java @@ -0,0 +1,345 @@ +package me.lojosho.hibiscuscommons.items; + +import lombok.Getter; +import me.lojosho.hibiscuscommons.hooks.Hooks; +import me.lojosho.hibiscuscommons.util.InventoryUtils; +import me.lojosho.hibiscuscommons.util.StringUtils; +import org.apache.commons.lang3.EnumUtils; +import org.bukkit.*; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.material.Colorable; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.profile.PlayerProfile; +import org.bukkit.profile.PlayerTextures; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.net.URL; +import java.util.*; + +public class ItemBuilder { + + @Getter + private String material; + @Getter + private String display; + @Getter + private String texture; + @Getter + private String skullOwner; + private ArrayList lore = new ArrayList<>(); + private ArrayList itemFlags = new ArrayList<>(); + private HashMap enchantments = new HashMap<>(); + private HashMap nbtData = new HashMap<>(); + @Getter + private int amount = 1; + @Getter + private int model = -1; + @Getter + private LoreAppendMode loreAppendMode; + @Getter + private boolean unbreakable = false; + @Getter + private boolean glowing = false; + @Getter + private Color color; + + public ItemBuilder(String material) { + ItemStack generatedItem = Hooks.getItem(material); + if (generatedItem == null) throw new IllegalArgumentException("Item String " + material + " is not valid"); + new ItemBuilder(generatedItem); + } + + public ItemBuilder(Material material) { + ItemStack generatedItem = Hooks.getItem(material.toString()); + if (generatedItem == null) throw new IllegalArgumentException("Item String " + material + " is not valid"); + new ItemBuilder(generatedItem); + } + + public ItemBuilder(@NotNull ItemStack itemStack) { + this.material = itemStack.getType().toString(); + this.amount = itemStack.getAmount(); + ItemMeta meta = itemStack.getItemMeta(); + if (meta == null) return; + if (meta.hasDisplayName()) this.display = meta.getDisplayName(); + if (meta.hasCustomModelData()) this.model = meta.getCustomModelData(); + if (meta.isUnbreakable()) this.unbreakable = true; + if (meta instanceof SkullMeta skullMeta) { + if (skullMeta.hasOwner()) this.skullOwner = skullMeta.getOwningPlayer().getName(); + if (skullMeta.getPersistentDataContainer().has(InventoryUtils.getSkullTexture(), PersistentDataType.STRING)) { + this.texture = skullMeta.getPersistentDataContainer().get(InventoryUtils.getSkullTexture(), PersistentDataType.STRING); + } + } + if (meta.hasLore()) this.lore = new ArrayList<>(meta.getLore()); + if (meta instanceof Colorable colorable) { + this.color = colorable.getColor().getColor(); + } + if (meta.hasEnchants()) { + for (Map.Entry entry : meta.getEnchants().entrySet()) { + this.enchantments.put(entry.getKey().getKey().getKey(), entry.getValue()); + } + } + if (!meta.getItemFlags().isEmpty()) { + for (ItemFlag flag : meta.getItemFlags()) { + this.itemFlags.add(flag.toString()); + } + } + } + + /** + * Sets the material of the item + * @param material + * @return + */ + public ItemBuilder setMaterial(@NotNull String material) { + this.material = material; + return this; + } + + public ItemBuilder setDisplayName(@NotNull String display) { + this.display = display; + return this; + } + + public ItemBuilder setModelData(int modelData) { + this.model = modelData; + return this; + } + + public ItemBuilder setAmount(int amount) { + this.amount = amount; + return this; + } + + public ItemBuilder setUnbreakable(boolean unbreakable) { + this.unbreakable = unbreakable; + return this; + } + + public ItemBuilder setTexture(@NotNull String texture) { + this.texture = texture; + return this; + } + + public ItemBuilder setSkullOwner(@NotNull String username) { + this.skullOwner = username; + return this; + } + + public ItemBuilder setLore(@Nullable ArrayList lore) { + this.lore = lore; + return this; + } + + /** + * Adds an itemflag to the item + * @param flags + * @return + */ + public ItemBuilder addItemFlag(ItemFlag... flags) { + for (ItemFlag flag : flags) this.itemFlags.add(flag.toString()); + return this; + } + + /** + * Adds an itemflag to the item + * @param flags + * @return + */ + public ItemBuilder addItemFlag(String... flags) { + this.itemFlags.addAll((Arrays.asList(flags))); + return this; + } + + /** + * Sets the lore append mode on how to add extra lore to an existing item + * So if you get an item from Oraxen, where do you want the additional lore to be added + * @param mode + * @return + */ + public ItemBuilder setLoreAppendMode(LoreAppendMode mode) { + this.loreAppendMode = mode; + return this; + } + + /** + * Sets the color of the item + * @param color + * @return + */ + public ItemBuilder setColor(Color color) { + this.color = color; + return this; + } + + /** + * Sets the color of the item + * @param color + * @return + */ + public ItemBuilder setColor(DyeColor color) { + this.color = color.getColor(); + return this; + } + + /** + * Adds an enchantment to the item. If the enchantment is not valid, it will be ignored. Default value is 1 + * @param enchants + * @return + */ + public ItemBuilder addEnchantment(String... enchants) { + for (String enchant : enchants) enchantments.put(enchant, 1); + return this; + } + + /** + * Adds an enchantment to the item. If the enchantment is not valid, it will be ignored + * @param enchant + * @param level + * @return + */ + public ItemBuilder addEnchantment(String enchant, int level) { + enchantments.put(enchant, level); + return this; + } + + /** + * Adds an enchantment to the item. If the enchantment is not valid, it will be ignored. + * @param enchant + * @param level + * @return + */ + public ItemBuilder addEnchantment(Enchantment enchant, int level) { + enchantments.put(enchant.getKey().getKey(), level); + return this; + } + + /** + * Sets the glowing of the item (Adds the luck and hide enchant item flag to the item when you build the itemstack) + * @param glowing + * @return + */ + public ItemBuilder setGlowing(boolean glowing) { + this.glowing = glowing; + return this; + } + + /** + * Returns the lore of the item. Use #setLore to set the lore! + * @return + */ + public List getLore() { + return List.copyOf(lore); + } + + /** + * Returns all the item flags of the item. Use #addItemFlag to add item flags! + * @return + */ + public List getItemFlags() { + return List.copyOf(itemFlags); + } + + public ItemStack build() { + ItemStack itemStack = Hooks.getItem(material); + if (itemStack == null) return null; + itemStack.setAmount(amount); + if (!itemStack.hasItemMeta()) return itemStack; + ItemMeta meta = itemStack.getItemMeta(); + if (meta == null) return itemStack; + if (display != null) meta.setDisplayName(StringUtils.parseStringToString(display)); + if (model >= 0) meta.setCustomModelData(model); + if (!lore.isEmpty()) { + meta.setUnbreakable(unbreakable); + List itemLore = Objects.requireNonNullElse(meta.getLore(), new ArrayList<>()); + List lore = new ArrayList<>(); + LoreAppendMode mode = loreAppendMode; + + if (!meta.hasLore() && loreAppendMode != null) mode = LoreAppendMode.IGNORE; + switch (mode) { + case IGNORE: // DM lore is not added at all + lore.addAll(itemLore); + break; + case TOP: // DM lore is added at the top + lore.addAll(this.lore); + lore.addAll(itemLore); + break; + case BOTTOM: // DM lore is bottom at the bottom + lore.addAll(itemLore); + lore.addAll(this.lore); + break; + case OVERRIDE: // Lore from DM overrides the lore from the item + lore.addAll(this.lore); + break; + } + + lore.forEach(StringUtils::parseStringToString); + meta.setLore(lore); + } + + if (meta instanceof SkullMeta skullMeta) { + if (skullOwner != null) { + if (skullOwner.contains("%")) { + // This means it has PAPI placeholders in it + skullMeta.getPersistentDataContainer().set(InventoryUtils.getSkullOwner(), PersistentDataType.STRING, skullOwner); + } + OfflinePlayer player = Bukkit.getOfflinePlayer(skullOwner); + skullMeta.setOwningPlayer(player); + } + if (texture != null) { + if (texture.contains("%")) { + // This means it has PAPI placeholders in it + skullMeta.getPersistentDataContainer().set(InventoryUtils.getSkullTexture(), PersistentDataType.STRING, texture); + } + // Decodes the texture string and sets the texture url to the skull + PlayerProfile profile = Bukkit.createPlayerProfile(UUID.randomUUID()); + PlayerTextures textures = profile.getTextures(); + + String decoded = new String(Base64.getDecoder().decode(texture)); + URL url = null; + try { + url = new URL(decoded.substring("{\"textures\":{\"SKIN\":{\"url\":\"".length(), decoded.length() - "\"}}}".length())); + } catch (Exception exception) { + exception.printStackTrace(); + } + if (url != null) { + textures.setSkin(url); + profile.setTextures(textures); + skullMeta.setOwnerProfile(profile); + } + } + } + if (itemFlags != null && !itemFlags.isEmpty()) { + for (String flag : itemFlags) { + if (!EnumUtils.isValidEnum(ItemFlag.class, flag)) continue; + ItemFlag iFlag = ItemFlag.valueOf(flag); + meta.addItemFlags(iFlag); + } + } + + if (glowing) { + meta.addEnchant(Enchantment.LUCK, 1, true); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + } + + if (enchantments != null && !enchantments.isEmpty()) { + for (String enchantment : enchantments.keySet()) { + if (Enchantment.getByKey(NamespacedKey.minecraft(enchantment)) == null) continue; + meta.addEnchant(Enchantment.getByKey(NamespacedKey.minecraft(enchantment)), enchantments.get(enchantment), true); + } + } + + if (meta instanceof Colorable colorable) { + if (color != null) colorable.setColor(DyeColor.getByColor(color)); + } + + itemStack.setItemMeta(meta); + + return itemStack; + } + +} diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/items/LoreAppendMode.java b/common/src/main/java/me/lojosho/hibiscuscommons/items/LoreAppendMode.java new file mode 100644 index 0000000..34cf1c6 --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/items/LoreAppendMode.java @@ -0,0 +1,8 @@ +package me.lojosho.hibiscuscommons.items; + +public enum LoreAppendMode { + OVERRIDE, + BOTTOM, + TOP, + IGNORE +}