Package com.bergerkiller.bukkit.common.inventory

Source Code of com.bergerkiller.bukkit.common.inventory.CraftRecipe

package com.bergerkiller.bukkit.common.inventory;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.bukkit.Material;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;

import com.bergerkiller.bukkit.common.reflection.classes.RecipeRef;
import com.bergerkiller.bukkit.common.utils.BlockUtil;
import com.bergerkiller.bukkit.common.utils.ItemUtil;
import com.bergerkiller.bukkit.common.utils.LogicUtil;
import com.bergerkiller.bukkit.common.utils.MaterialUtil;
import com.bergerkiller.bukkit.common.utils.MathUtil;

public class CraftRecipe {
  private final ItemStack[] input;
  private final ItemStack[] output;

  private CraftRecipe(Collection<ItemStack> input, ItemStack output) {
    // Convert the input
    List<ItemStack> newinput = new ArrayList<ItemStack>(input.size());
    boolean create;
    for (ItemStack item : input) {
      if (LogicUtil.nullOrEmpty(item)) {
        continue;
      }
      item = item.clone();
      if (item.getDurability() == Short.MAX_VALUE) {
        item.setDurability((short) -1);
      }

      create = true;
      for (ItemStack newitem : newinput) {
        if (ItemUtil.equalsIgnoreAmount(item, newitem)) {
          ItemUtil.addAmount(newitem, 1);
          create = false;
          break;
        }
      }
      if (create) {
        item.setAmount(1);
        newinput.add(item);
      }
    }
    this.input = newinput.toArray(new ItemStack[0]);

    // Convert the output
    List<ItemStack> newoutput = new ArrayList<ItemStack>(1);
    newoutput.add(output.clone());
    // Deal with special cases that demand an additional item (added elsewhere)
    for (ItemStack stack : newinput) {
      if (BlockUtil.isType(stack, Material.LAVA_BUCKET, Material.WATER_BUCKET, Material.MILK_BUCKET)) {
        newoutput.add(new ItemStack(Material.BUCKET, stack.getAmount()));
      }
    }
    this.output = newoutput.toArray(new ItemStack[0]);
  }

  /**
   * Gets the input item at the index specified
   *
   * @param index of the item
   * @return input Item
   */
  public ItemStack getInput(int index) {
    return this.input[index];
  }

  /**
   * Gets all the input items
   *
   * @return input Items
   */
  public ItemStack[] getInput() {
    return this.input;
  }

  /**
   * Gets all the output items
   *
   * @return output Items
   */
  public ItemStack[] getOutput() {
    return this.output;
  }

  /**
   * Gets the total amount of items, this adds all the amounts of all the items together<br>
   * <b>This is not the length of the Input item array!</b>
   *
   * @return Input item amount
   */
  public int getInputSize() {
    int count = 0;
    for (ItemStack item : this.input) {
      count += item.getAmount();
    }
    return count;
  }

  /**
   * Gets the total amount of items, this adds all the amounts of all the items together<br>
   * <b>This is not the length of the Output item array!</b>
   *
   * @return Output item amount
   */
  public int getOutputSize() {
    int count = 0;
    for (ItemStack item : this.output) {
      count += item.getAmount();
    }
    return count;
  }

  /**
   * Checks whether the input items of this recipe are contained within an Inventory
   *
   * @param inventory to check
   * @return True if the items are available, False if not
   */
  public boolean containsInput(Inventory inventory) {
    for (ItemStack item : this.input) {
      if (ItemUtil.getItemCount(inventory, MaterialUtil.getTypeId(item), MaterialUtil.getRawData(item)) < item.getAmount()) {
        return false;
      }
    }
    return true;
  }

  /**
   * Performs this recipe multiple times in the inventory specified
   *
   * @param inventory to craft in
   * @param itemlimit the max amount of resulting items
   * @return the amount of resulting items that were crafted
   */
  public int craftItems(Inventory inventory, int itemlimit) {
    int lim = MathUtil.floor((double) itemlimit / (double) this.output[0].getAmount());
    return this.craft(inventory, lim) * this.output[0].getAmount();
  }

  /**
   * Performs this recipe once in the inventory specified
   *
   * @param inventory to craft in
   * @return True if crafting occurred, False if not
   */
  public boolean craft(Inventory inventory) {
    return craft(inventory, 1) == 1;
  }

  /**
   * Performs this recipe multiple times in the inventory specified
   *
   * @param inventory to craft in
   * @param limit the amount of times it can craft
   * @return the amount of times it crafted
   */
  public int craft(Inventory inventory, int limit) {
    // Before cloning everything, check whether we can craft at all
    if (!this.containsInput(inventory)) {
      return 0;
    }

    // Create a (temporary) clone of the inventory to work with
    final ItemStack[] items = inventory.getContents();
    final int size = items.length;
    final Inventory inventoryClone = new InventoryBaseImpl(items, true);
    int amount, i;

    // Craft items until the limit is reached, or crafting is impossible
    // Below is the craftloop label, which is used to break out of crafting
    craftloop:
    for (amount = 0; amount < limit; amount++) {
      // input item check
      if (!this.containsInput(inventoryClone)) {
        break;
      }

      // remove ingredients from inventory
      for (ItemStack item : this.input) {
        ItemUtil.removeItems(inventoryClone, item);
      }

      // add resulting items to inventory
      for (ItemStack item : this.output) {
        ItemStack cloned = ItemUtil.cloneItem(item);
        ItemUtil.transfer(cloned, inventoryClone, Integer.MAX_VALUE);
        // Could not add result (full), unsuccessful
        if (!LogicUtil.nullOrEmpty(cloned)) {
          break craftloop;
        }
      }

      // Crafting was successful, transfer items over
      // Be sure NOT to produce new ItemStack instances!
      for (i = 0; i < size; i++) {
        ItemStack newItem = inventoryClone.getItem(i);
        if (LogicUtil.nullOrEmpty(newItem)) {
          items[i] = null;
        } else if (items[i] == null) {
          items[i] = newItem.clone();
        } else {
          // Transfer info and amount
          ItemUtil.transferInfo(newItem, items[i]);
          items[i].setAmount(newItem.getAmount());
        }
      }
    }

    // Update input inventory with the new items
    inventory.setContents(items);
    return amount;
  }

  /**
   * Creates a new Craft Recipe from an IRecipe instance.
   * This method is not recommended to be used.
   *
   * @param recipe to use
   * @return the CraftRecipe, or null on failure
   */
  public static CraftRecipe create(Object recipe) {
    final ItemStack output = RecipeRef.getOutput(recipe);
    if (RecipeRef.SHAPED_TEMPLATE.isInstance(recipe)) {
      return create(RecipeRef.shapedInput.get(recipe), output);
    } else if (RecipeRef.SHAPELESS_TEMPLATE.isInstance(recipe)) {
      return create(RecipeRef.shapelessInput.get(recipe), output);
    } else {
      return null;
    }
  }

  public static CraftRecipe create(Collection<ItemStack> input, ItemStack output) {
    if (LogicUtil.nullOrEmpty(input) || LogicUtil.nullOrEmpty(output)) {
      return null;
    } else {
      CraftRecipe rval = new CraftRecipe(input, output);
      // Check that input and output are not causing a loop
      // For example Sandstone has an infinite crafting loop going on
      // (You can craft 4 Sandstone using 4 Sandstone...yeah)
      if (rval.input.length == 1 && rval.output.length == 1 && MaterialUtil.getTypeId(rval.input[0]) == MaterialUtil.getTypeId(rval.output[0])) {
        return null;
      }
      return rval;
    }
  }
}
TOP

Related Classes of com.bergerkiller.bukkit.common.inventory.CraftRecipe

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.