/*******************************************************************************
* AbyssalCraft
* Copyright (c) 2012 - 2017 Shinoow.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v3
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-3.0.txt
*
* Contributors:
* Shinoow - implementation
******************************************************************************/
package com.shinoow.abyssalcraft.api.recipe;
import java.util.List;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraftforge.oredict.OreDictionary;
import com.google.common.collect.Lists;
import com.shinoow.abyssalcraft.api.APIUtils;
public class MaterializerRecipes {
private static final MaterializerRecipes materializerBase = new MaterializerRecipes();
/** The list of materialization results. */
private List<Materialization> materializationList = Lists.newArrayList();
public static MaterializerRecipes instance()
{
return materializerBase;
}
private MaterializerRecipes()
{
}
public void materialize(ItemStack[] input, ItemStack output){
materialize(new Materialization(input, output));
}
public void materialize(Materialization materialization){
materializationList.add(materialization);
}
/**
* Fetches a list of things that can be materialized based off of the Crystal Bag contents
* @param stack Crystal Bag to check for crystals
* @return A list of ItemStacks containing what can be materialized
*/
public List<ItemStack> getMaterializationResult(ItemStack stack){
ItemStack[] inventory = extractItemsFromBag(stack);
if(inventory == null) return null;
List<ItemStack> displayList = Lists.newArrayList();
for(Materialization mat : materializationList)
if(arrayContainsOtherArray(inventory, mat.input))
displayList.add(mat.output);
return displayList;
}
/**
* Attempts to materialize an ItemStack
* @param output ItemStack to materialize
* @param bag Crystal Bag to use crystals from
*/
public void processMaterialization(ItemStack output, ItemStack bag){
ItemStack[] inventory = extractItemsFromBag(bag);
if(inventory == null) return;
Materialization mat = getMaterializationFor(output);
if(mat == null) return;
List<ItemStack> recipe = Lists.newArrayList(mat.input);
for(int i = 0; i < inventory.length; i++)
for(ItemStack recipeItem : recipe){
ItemStack invItem = inventory[i];
if(areStacksEqual(invItem, recipeItem))
if(invItem.getCount() >= recipeItem.getCount()){
invItem.shrink(recipeItem.getCount());
if(invItem.isEmpty()) inventory[i] = ItemStack.EMPTY;
recipe.remove(recipeItem);
break;
} else {
recipeItem.shrink(invItem.getCount());
inventory[i] = ItemStack.EMPTY;
break;
}
}
if(recipe.isEmpty())
replaceBagContents(bag, inventory);
}
/**
* Fetches the materialization recipe for a specific ItemStack
* @param output Recipe output to find a recipe for
* @return A materialization recipe if one exists, otherwise null
*/
private Materialization getMaterializationFor(ItemStack output){
for(Materialization mat : materializationList)
if(areStacksEqual(output, mat.output)) return mat;
return null;
}
/**
* Helper method for fetching the stored content of a Crystal Bag
* @param bag Crystal Bag to extract crystals from
* @return An array of ItemStacks (provided the bag has an inventory, and it's contents are only crystals), otherwise null
*/
private ItemStack[] extractItemsFromBag(ItemStack bag){
ItemStack[] inventory = null;
if(bag.getTagCompound() == null)
bag.setTagCompound(new NBTTagCompound());
if(bag.getTagCompound().hasKey("ItemInventory")){
NBTTagList items = bag.getTagCompound().getTagList("ItemInventory", 10);
inventory = new ItemStack[items.tagCount()];
for (int i = 0; i < items.tagCount(); ++i)
{
NBTTagCompound item = items.getCompoundTagAt(i);
// byte slot = item.getByte("Slot");
inventory[i] = new ItemStack(item);
}
}
if(inventory == null) return null;
for(ItemStack item : inventory)
if(!APIUtils.isCrystal(item)) return null;
return inventory;
}
/**
* Updates the contents of the Crystal Bag (after consuming crystals to materialize stuff)
* @param bag Crystal Bag ItemStack
* @param inventory New inventory content to replace the old
*/
private void replaceBagContents(ItemStack bag, ItemStack[] inventory){
if(!bag.hasTagCompound())
bag.setTagCompound(new NBTTagCompound());
NBTTagCompound tag = new NBTTagCompound();
bag.writeToNBT(tag);
NBTTagList items = new NBTTagList();
for(int i = 0; i < inventory.length; i++)
if(!inventory[i].isEmpty()){
NBTTagCompound item = new NBTTagCompound();
item.setInteger("Slot", i);
inventory[i].writeToNBT(item);
items.appendTag(item);
}
tag.setTag("ItemInventory", items);
bag.deserializeNBT(tag);
}
private boolean areStacksEqual(ItemStack par1ItemStack, ItemStack par2ItemStack)
{
if(par1ItemStack.isEmpty() || par2ItemStack.isEmpty()) return false;
return par2ItemStack.getItem() == par1ItemStack.getItem() && (par2ItemStack.getItemDamage() == OreDictionary.WILDCARD_VALUE || par2ItemStack.getItemDamage() == par1ItemStack.getItemDamage());
}
/**
* Compares two arrays, checking if the first one contains the contents of the second
* @param array1 First array
* @param array2 Second array
* @return True if the first array contains the contents of the second, otherwise false
*/
private boolean arrayContainsOtherArray(ItemStack[] array1, ItemStack[] array2){
List<ItemStack> inventory = Lists.newArrayList(array1);
List<ItemStack> recipe = Lists.newArrayList(array2);
if(inventory.size() >= recipe.size())
for(ItemStack invItem : inventory)
for(ItemStack recipeItem : recipe)
if(areStacksEqual(invItem, recipeItem))
if(invItem.getCount() >= recipeItem.getCount()){
invItem.shrink(recipeItem.getCount());
if(invItem.isEmpty()) invItem = ItemStack.EMPTY;
recipe.remove(recipeItem);
break;
} else {
recipeItem.shrink(invItem.getCount());
invItem = ItemStack.EMPTY;
break;
}
return recipe.isEmpty();
}
public List<Materialization> getMaterializationList()
{
return materializationList;
}
}