Package com.bergerkiller.bukkit.common.utils

Source Code of com.bergerkiller.bukkit.common.utils.ItemUtil

package com.bergerkiller.bukkit.common.utils;

import org.bukkit.Material;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.inventory.Inventory;

import com.bergerkiller.bukkit.common.conversion.Conversion;
import com.bergerkiller.bukkit.common.internal.CommonNMS;
import com.bergerkiller.bukkit.common.inventory.InventoryBaseImpl;
import com.bergerkiller.bukkit.common.inventory.ItemParser;
import com.bergerkiller.bukkit.common.nbt.CommonTagCompound;
import com.bergerkiller.bukkit.common.nbt.CommonTagList;
import com.bergerkiller.bukkit.common.reflection.classes.ItemStackRef;

import net.minecraft.server.EntityItem;
import net.minecraft.server.Item;
import net.minecraft.server.ItemStack;

/**
* Contains item stack, item and inventory utilities
*/
public class ItemUtil {

  /**
   * Tests if the given ItemStacks can be fully transferred to another array of ItemStacks
   *
   * @param from ItemStack source array
   * @param to destination Inventory
   * @return True if full transfer was possible, False if not
   */
  public static boolean canTransferAll(org.bukkit.inventory.ItemStack[] from, Inventory to) {
    return canTransferAll(from, to.getContents());
  }

  /**
   * Tests if the given ItemStacks can be fully transferred to another array of ItemStacks
   *
   * @param from ItemStack source array
   * @param to ItemStack destination array
   * @return True if full transfer was possible, False if not
   */
  public static boolean canTransferAll(org.bukkit.inventory.ItemStack[] from, org.bukkit.inventory.ItemStack[] to) {
    Inventory invto = new InventoryBaseImpl(to, true);
    for (org.bukkit.inventory.ItemStack item : cloneItems(from)) {
      transfer(item, invto, Integer.MAX_VALUE);
      if (!LogicUtil.nullOrEmpty(item)) {
        return false;
      }
    }
    return true;
  }

  /**
   * Tests if the given ItemStack can be transferred to the Inventory
   *
   * @return The amount that could be transferred
   */
  public static int testTransfer(org.bukkit.inventory.ItemStack from, Inventory to) {
    if (LogicUtil.nullOrEmpty(from)) {
      return 0;
    }
    int startAmount = from.getAmount();
    int fromAmount = startAmount;
    for (org.bukkit.inventory.ItemStack item : to.getContents()) {
      if (LogicUtil.nullOrEmpty(item)) {
        // Full transfer is possible (empty slot)
        fromAmount -= getMaxSize(from);
      } else if (equalsIgnoreAmount(from, item)) {
        // Stack transfer is possible (same item slot)
        fromAmount -= getMaxSize(item) - item.getAmount();
      }
      if (fromAmount <= 0) {
        // All items could be transferred!
        return startAmount;
      }
    }
    return startAmount - fromAmount;
  }

  /**
   * Tests if the two items can be merged
   *
   * @return The amount that could be transferred
   */
  public static int testTransfer(org.bukkit.inventory.ItemStack from, org.bukkit.inventory.ItemStack to) {
    if (LogicUtil.nullOrEmpty(from)) {
      return 0;
    }
    if (LogicUtil.nullOrEmpty(to)) {
      return Math.min(from.getAmount(), getMaxSize(from));
    }
    if (equalsIgnoreAmount(from, to)) {
      return Math.min(from.getAmount(), getMaxSize(to) - to.getAmount());
    }
    return 0;
  }

  /**
   * Transfers all ItemStacks from one Inventory to another
   *
   * @param from The Inventory to take ItemStacks from
   * @param to The Inventory to transfer to
   * @param maxAmount The maximum amount of items to transfer, -1 for infinite
   * @param parser The item parser used to set what items to transfer. Can be null.
   * @return The amount of items that got transferred
   */
  public static int transfer(Inventory from, Inventory to, ItemParser parser, int maxAmount) {
    int startAmount = maxAmount < 0 ? Integer.MAX_VALUE : maxAmount;
    int amountToTransfer = startAmount;
    int tmptrans;
    for (int i = 0; i < from.getSize() && amountToTransfer > 0; i++) {
      org.bukkit.inventory.ItemStack item = from.getItem(i);
      if (LogicUtil.nullOrEmpty(item) || (parser != null && !parser.match(item))) {
        continue;
      }
      tmptrans = transfer(item, to, amountToTransfer);
      if (tmptrans > 0) {
        amountToTransfer -= tmptrans;
        from.setItem(i, item);
      }
    }
    return startAmount - amountToTransfer;
  }

  /**
   * Transfers the given ItemStack to multiple slots in the Inventory
   *
   * @param from The ItemStack to transfer
   * @param to The Inventory to transfer to
   * @param maxAmount The maximum amount of the item to transfer, -1 for infinite
   * @return The amount of the item that got transferred
   */
  public static int transfer(org.bukkit.inventory.ItemStack from, Inventory to, int maxAmount) {
    int startAmount = maxAmount < 0 ? Integer.MAX_VALUE : maxAmount;
    if (startAmount == 0 || LogicUtil.nullOrEmpty(from)) {
      return 0;
    }
    int tmptrans;
    int amountToTransfer = startAmount;

    // try to stack to already existing items
    org.bukkit.inventory.ItemStack toitem;
    for (int i = 0; i < to.getSize(); i++) {
      toitem = to.getItem(i);
      if (!LogicUtil.nullOrEmpty(toitem)) {
        tmptrans = transfer(from, toitem, amountToTransfer);
        if (tmptrans > 0) {
          amountToTransfer -= tmptrans;
          to.setItem(i, toitem);
          // everything done?
          if (amountToTransfer <= 0 || LogicUtil.nullOrEmpty(from)){
            break;
          }
        }
      }
    }

    // try to add it to empty slots
    if (amountToTransfer > 0 && from.getAmount() > 0) {
      for (int i = 0; i < to.getSize(); i++) {
        toitem = to.getItem(i);
        if (LogicUtil.nullOrEmpty(toitem)) {
          toitem = emptyItem();
          // Transfer
          tmptrans = transfer(from, toitem, amountToTransfer);
          if (tmptrans > 0) {
            amountToTransfer -= tmptrans;
            to.setItem(i, toitem);
            // everything done?
            if (amountToTransfer <= 0 || LogicUtil.nullOrEmpty(from)) {
              break;
            }
          }
        }
      }
    }
    return startAmount - amountToTransfer;
  }

  /**
   * Tries to transfer items from the Inventory to the ItemStack
   *
   * @param from The Inventory to take an ItemStack from
   * @param to The ItemStack to merge the item taken
   * @param parser The item parser used to set what item to transfer if the receiving item is empty. Can be null.
   * @param maxAmount The maximum amount of the item to transfer, -1 for infinite
   * @return The amount of the item that got transferred
   */
  public static int transfer(Inventory from, org.bukkit.inventory.ItemStack to, ItemParser parser, int maxAmount) {
    int startAmount = maxAmount < 0 ? Integer.MAX_VALUE : maxAmount;
    int amountToTransfer = startAmount;
    for (int i = 0; i < from.getSize() && amountToTransfer > 0; i++) {
      org.bukkit.inventory.ItemStack item = from.getItem(i);
      if (LogicUtil.nullOrEmpty(item)) {
        continue;
      }
      if (LogicUtil.nullOrEmpty(to)) {
        // Parser matching
        if (parser != null && !parser.match(item)) {
          continue;
        }
        // Set item info to this item
        transferInfo(item, to);     
      }
      amountToTransfer -= transfer(item, to, amountToTransfer);
      from.setItem(i, item);
    }
    return startAmount - amountToTransfer;
  }

  /**
   * Merges two ItemStacks together<br>
   * - If from is empty or null, no transfer happens<br>
   * - If to is null, no transfer happens<br>
   * - If to is empty, full transfer occurs
   *
   * @param from The ItemStack to merge
   * @param to The receiving ItemStack
   * @param maxAmount The maximum amount of the item to transfer, -1 for infinite
   * @return The amount of the item that got transferred
   */
  public static int transfer(org.bukkit.inventory.ItemStack from, org.bukkit.inventory.ItemStack to, int maxAmount) {
    if (LogicUtil.nullOrEmpty(from) || to == null) {
      return 0;
    }
    int amountToTransfer = Math.min(maxAmount < 0 ? Integer.MAX_VALUE : maxAmount, from.getAmount());

    // Transfering to an empty item, don't bother doing any stacking logic
    if (LogicUtil.nullOrEmpty(to)) {
      // Limit amount by maximum of the from item
      amountToTransfer = Math.min(amountToTransfer, getMaxSize(from));
      if (amountToTransfer <= 0) {
        return 0;
      }
      // Transfer item information
      transferInfo(from, to);
      // Transfer the amount
      to.setAmount(amountToTransfer);
      subtractAmount(from, amountToTransfer);
      return amountToTransfer;
    }

    // Can we stack?
    amountToTransfer = Math.min(amountToTransfer, getMaxSize(to) - to.getAmount());
    if (amountToTransfer <= 0 || !equalsIgnoreAmount(from, to)) {
      return 0;
    }

    // From and to are equal, we can now go ahead and stack them
    addAmount(to, amountToTransfer);
    subtractAmount(from, amountToTransfer);
    return amountToTransfer;
  }

  /**
   * Transfers the item type, data and enchantments from one item stack to the other
   *
   * @param from which Item Stack to read the info
   * @param to which Item Stack to transfer the info to
   */
  @SuppressWarnings("deprecation")
  public static void transferInfo(org.bukkit.inventory.ItemStack from, org.bukkit.inventory.ItemStack to) {
    // Transfer type, durability and any other remaining metadata information
    to.setTypeId(from.getTypeId());
    to.setDurability(from.getDurability());
    setMetaTag(to, LogicUtil.clone(getMetaTag(from)));
  }

  /**
   * Checks whether two item stacks equal, while ignoring the item amounts
   *
   * @param item1 to check
   * @param item2 to check
   * @return True if the items have the same type, data and enchantments, False if not
   */
  public static boolean equalsIgnoreAmount(org.bukkit.inventory.ItemStack item1, org.bukkit.inventory.ItemStack item2) {
    if (MaterialUtil.getTypeId(item1) != MaterialUtil.getTypeId(item2) || MaterialUtil.getRawData(item1) != MaterialUtil.getRawData(item2)) {
      return false;
    }
    // Metadata checks
    boolean hasMeta = hasMetaTag(item1);
    if (hasMeta != hasMetaTag(item2)) {
      return false;
    } else if (!hasMeta) {
      // No further data to test
      return true;
    }
    if (!item1.getItemMeta().equals(item2.getItemMeta())) {
      return false;
    }

    // Not included in metadata checks: Item attributes (Bukkit needs to update)
    CommonTagList item1Attr = getMetaTag(item1).get("AttributeModifiers", CommonTagList.class);
    CommonTagList item2Attr = getMetaTag(item2).get("AttributeModifiers", CommonTagList.class);
    return LogicUtil.bothNullOrEqual(item1Attr, item2Attr);
  }

  /**
   * Removes certain kinds of items from an inventory
   *
   * @param inventory to remove items from
   * @param item signature of the items to remove
   */
  public static void removeItems(Inventory inventory, org.bukkit.inventory.ItemStack item) {
    removeItems(inventory, MaterialUtil.getTypeId(item), MaterialUtil.getRawData(item), item.getAmount());
  }

  /**
   * Removes certain kinds of items from an inventory
   *
   * @param inventory to remove items from
   * @param itemid of the items to remove
   * @param data of the items to remove, -1 for any data
   * @param amount of items to remove, -1 for infinite amount
   */
  public static void removeItems(Inventory inventory, int itemid, int data, int amount) {
    int countToRemove = amount < 0 ? Integer.MAX_VALUE : amount;
    for (int i = 0; i < inventory.getSize(); i++) {
      org.bukkit.inventory.ItemStack item = inventory.getItem(i);
      if (LogicUtil.nullOrEmpty(item) || MaterialUtil.getTypeId(item) != itemid || (data != -1 && MaterialUtil.getRawData(item) != data)) {
        continue;
      }
      if (item.getAmount() <= countToRemove) {
        countToRemove -= item.getAmount();
        inventory.setItem(i, null);
      } else {
        subtractAmount(item, countToRemove);
        countToRemove = 0;
        inventory.setItem(i, item);
        break;
      }
    }
  }

  /**
   * Obtains an empty item stack that allows mutual changes<br>
   * This is a CraftItemStack with a NMS ItemStack as buffer
   *
   * @return Empty item stack
   */
  public static org.bukkit.inventory.ItemStack emptyItem() {
    return CraftItemStack.asCraftMirror((ItemStack) ItemStackRef.newInstance(Material.AIR, 0, 0));
  }

  /**
   * Kills the old item and spawns a new item in it's place
   *
   * @param item to respawn
   * @return Respawned item
   */
  public static org.bukkit.entity.Item respawnItem(org.bukkit.entity.Item item) {
    item.remove();
    EntityItem oldItemHandle = CommonNMS.getNative(item);
    EntityItem newItemHandle = new EntityItem(oldItemHandle.world, oldItemHandle.locX, oldItemHandle.locY, oldItemHandle.locZ, oldItemHandle.getItemStack());
    newItemHandle.fallDistance = oldItemHandle.fallDistance;
    newItemHandle.fireTicks = oldItemHandle.fireTicks;
    newItemHandle.pickupDelay = oldItemHandle.pickupDelay;
    newItemHandle.motX = oldItemHandle.motX;
    newItemHandle.motY = oldItemHandle.motY;
    newItemHandle.motZ = oldItemHandle.motZ;
    newItemHandle.age = oldItemHandle.age;
    newItemHandle.world.addEntity(newItemHandle);
    return CommonNMS.getItem(newItemHandle);
  }

  /**
   * Gets the contents of an inventory, cloning all the items
   *
   * @param inventory to get the cloned contents of
   * @return Cloned inventory contents array
   */
  public static org.bukkit.inventory.ItemStack[] getClonedContents(Inventory inventory) {
    org.bukkit.inventory.ItemStack[] rval = new org.bukkit.inventory.ItemStack[inventory.getSize()];
    for (int i = 0; i < rval.length; i++) {
      rval[i] = cloneItem(inventory.getItem(i));
    }
    return rval;
  }

  /**
   * Clones a single item
   *
   * @param stack to be cloned, can be null
   * @return Cloned item stack
   */
  public static org.bukkit.inventory.ItemStack cloneItem(org.bukkit.inventory.ItemStack stack) {
    return LogicUtil.clone(stack);
  }

  /**
   * Creates a new itemstack array containing items not referencing the input item stacks
   *
   * @param input array to process
   * @return Cloned item stack array
   */
  public static org.bukkit.inventory.ItemStack[] cloneItems(org.bukkit.inventory.ItemStack[] input) {
    return LogicUtil.cloneAll(input);
  }

  /**
   * Subtracts a certain amount from an item, without limiting to the max stack size
   *
   * @param item
   * @param amount to subtract
   */
  public static void subtractAmount(org.bukkit.inventory.ItemStack item, int amount) {
    addAmount(item, -amount);
  }

  /**
   * Adds a certain amount to an item, without limiting to the max stack size
   *
   * @param item
   * @param amount to add
   */
  public static void addAmount(org.bukkit.inventory.ItemStack item, int amount) {
    item.setAmount(Math.max(item.getAmount() + amount, 0));
  }

  /**
   * Obtains an item of the given type and data in the inventory specified<br>
   * If multiple items with the same type and data exist, their amounts are added together
   *
   * @param inventory to look in
   * @param typeId of the items to look for, -1 for any item
   * @param data of the items to look for, -1 for any data
   * @return Amount of items in the inventory
   */
  public static org.bukkit.inventory.ItemStack findItem(Inventory inventory, int typeId, int data) {
    org.bukkit.inventory.ItemStack rval = null;
    int itemData = data;
    int itemTypeId = typeId;
    for (org.bukkit.inventory.ItemStack item : inventory.getContents()) {
      if (LogicUtil.nullOrEmpty(item)) {
        continue;
      }
      // Compare type Id
      if (itemTypeId == -1) {
        itemTypeId = MaterialUtil.getTypeId(item);
      } else if (itemTypeId != MaterialUtil.getTypeId(item)) {
        continue;
      }
      // Compare data
      if (itemData == -1) {
        itemData = MaterialUtil.getRawData(item);
      } else if (MaterialUtil.getRawData(item) != itemData) {
        continue;
      }
      // addition
      if (rval == null) {
        rval = item.clone();
      } else {
        addAmount(rval, item.getAmount());
      }
    }
    return rval;
  }

  /**
   * Gets the total item count of a given type and data
   *
   * @param inventory to look in
   * @param typeid of the items to look for, -1 for any item
   * @param data of the items to look for, -1 for any data
   * @return Amount of items in the inventory
   */
  public static int getItemCount(Inventory inventory, int typeid, int data) {
    if (typeid < 0) {
      int count = 0;
      for (org.bukkit.inventory.ItemStack item : inventory.getContents()) {
        if (!LogicUtil.nullOrEmpty(item)) {
          count += item.getAmount();
        }
      }
      return count;
    } else {
      org.bukkit.inventory.ItemStack rval = findItem(inventory, typeid, data);
      return rval == null ? 0 : rval.getAmount();
    }
  }

  /**
   * Gets the max stacking size for a given item
   *
   * @param itemId of the item
   * @param def to return for invalid items
   * @return max stacking size
   */
  public static int getMaxSize(int itemId, int def) {
    return getMaxSize(MaterialUtil.getType(itemId), def);
  }

  /**
   * Gets the max stacking size for a given item
   *
   * @param itemType of the item
   * @param def to return for invalid items
   * @return max stacking size
   */
  public static int getMaxSize(Material itemType, int def) {
    Item item = CommonNMS.getItem(itemType);
    return item == null ? def : item.getMaxStackSize();
  }

  /**
   * Gets the max stacking size for a given item
   *
   * @param stack to get the max stacked size
   * @return max stacking size
   */
  public static int getMaxSize(org.bukkit.inventory.ItemStack stack) {
    if (LogicUtil.nullOrEmpty(stack)) {
      return 0;
    } else {
      return getMaxSize(MaterialUtil.getTypeId(stack), 0);
    }
  }

  /**
   * Checks whether an Item stores a metadata tag
   *
   * @param stack to check
   * @return True if a metadata tag is stored, False if not
   */
  public static boolean hasMetaTag(org.bukkit.inventory.ItemStack stack) {
    return CommonNMS.getNative(stack).hasTag();
  }

  /**
   * Obtains the Metadata tag stored in an item.
   * If no metadata is stored, null is returned instead.
   *
   * @param stack to get the metadata tag of
   * @return metadata tag
   */
  public static CommonTagCompound getMetaTag(org.bukkit.inventory.ItemStack stack) {
    return ItemStackRef.tag.get(Conversion.toItemStackHandle.convert(stack));
  }

  /**
   * Sets the Metadata tag stored in an item.
   * If tag is null, all metadata is cleared.
   *
   * @param stack to set the metadata tag of
   * @param tag to set to
   */
  public static void setMetaTag(org.bukkit.inventory.ItemStack stack, CommonTagCompound tag) {
    ItemStackRef.tag.set(Conversion.toItemStackHandle.convert(stack), tag);
  }

  /**
   * Sets the cost of repairing this item
   *
   * @param stack to set the repair cost of
   * @param repairCost to set to
   */
  public static void setRepairCost(org.bukkit.inventory.ItemStack stack, int repairCost) {
    CommonNMS.getNative(stack).setRepairCost(repairCost);
  }

  /**
   * Gets the cost of repairing this item
   *
   * @param stack to get the repair cost of
   * @return repair cost
   */
  public static int getRepairCost(org.bukkit.inventory.ItemStack stack) {
    return CommonNMS.getNative(stack).getRepairCost();
  }

  /**
   * Checks whether an item has a custom display name set
   *
   * @param stack to check
   * @return True if a custom name is set, False if not
   */
  public static boolean hasDisplayName(org.bukkit.inventory.ItemStack stack) {
    return CommonNMS.getNative(stack).hasName();
  }

  /**
   * Gets the current display name of an Item.
   * If no name is set, the default Material name is returned instead.
   *
   * @param stack to get the display name of
   * @return display name
   */
  public static String getDisplayName(org.bukkit.inventory.ItemStack stack) {
    return CommonNMS.getNative(stack).getName();
  }

  /**
   * Sets the current display name of an Item
   *
   * @param stack to set the display name of
   * @param displayName to set to, null to reset to the default
   */
  public static void setDisplayName(org.bukkit.inventory.ItemStack stack, String displayName) {
    if (displayName != null) {
      CommonNMS.getNative(stack).c(displayName);
    } else if (hasDisplayName(stack)) {
      CommonNMS.getNative(stack).tag.remove("display");
    }
  }
}
TOP

Related Classes of com.bergerkiller.bukkit.common.utils.ItemUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.