package openmods.utils;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import java.util.Collection;
import java.util.List;
import javax.annotation.Nullable;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.ShapedRecipes;
import net.minecraft.item.crafting.ShapelessRecipes;
import net.minecraftforge.oredict.OreDictionary;
import net.minecraftforge.oredict.ShapedOreRecipe;
import net.minecraftforge.oredict.ShapelessOreRecipe;
import openmods.reflection.FieldAccess;
public class RecipeUtils {
public static class InputBuilder {
private static final ItemStack[] EMPTY_SLOT = new ItemStack[0];
private static final Function<ItemStack, ItemStack> COPY_TRANSFORM = new Function<ItemStack, ItemStack>() {
@Override
@Nullable
public ItemStack apply(@Nullable ItemStack input) {
return input != null? input.copy() : null;
}
};
private final ItemStack[][] slots;
public InputBuilder(int size) {
slots = new ItemStack[size][];
}
public void add(int slot, ItemStack stack) {
slots[slot] = stack == null? EMPTY_SLOT : new ItemStack[] { stack.copy() };
}
public void add(int slot, ItemStack[] stacks) {
slots[slot] = CollectionUtils.transform(stacks, COPY_TRANSFORM);
}
public void add(int slot, Collection<ItemStack> stacks) {
slots[slot] = CollectionUtils.transform(stacks, COPY_TRANSFORM);
}
public ItemStack[][] build() {
for (int i = 0; i < slots.length; i++)
if (slots[i] == null) slots[i] = EMPTY_SLOT;
return slots;
}
}
private static final ItemStack[] EMPTY_ITEM_STACK_ARRAY = new ItemStack[0];
private static FieldAccess<Integer> shapedOreRecipeWidth = FieldAccess.create(ShapedOreRecipe.class, "width");
private static FieldAccess<Integer> shapedOreRecipeHeight = FieldAccess.create(ShapedOreRecipe.class, "height");
@SuppressWarnings("unchecked")
public static List<IRecipe> getVanillaRecipes() {
return CraftingManager.getInstance().getRecipeList();
}
public static IRecipe getFirstRecipeForItemStack(ItemStack resultingItem) {
for (IRecipe recipe : getVanillaRecipes()) {
if (recipe == null) continue;
ItemStack result = recipe.getRecipeOutput();
if (result != null && result.isItemEqual(resultingItem)) return recipe;
}
return null;
}
public static ItemStack[] getFirstRecipeForItem(ItemStack resultingItem) {
final IRecipe recipe = getFirstRecipeForItemStack(resultingItem);
if (recipe == null) return null;
Object[] input = getRecipeInput(recipe);
return input != null? convertToStacks(input) : null;
}
public static ItemStack[] convertToStacks(Object[] input) {
ItemStack[] result = new ItemStack[input.length];
for (int i = 0; i < input.length; i++)
result[i] = convertToStack(input[i]);
return result;
}
public static ItemStack convertToStack(Object obj) {
ItemStack entry = null;
if (obj instanceof ItemStack) {
entry = (ItemStack)obj;
} else if (obj instanceof List) {
@SuppressWarnings("unchecked")
List<ItemStack> list = (List<ItemStack>)obj;
entry = CollectionUtils.getRandom(list);
}
if (entry == null) return null;
entry = entry.copy();
if (entry.getItemDamage() == OreDictionary.WILDCARD_VALUE) entry.setItemDamage(0);
return entry;
}
@SuppressWarnings("unchecked")
public static Object[] getRecipeInput(IRecipe recipe) {
if (recipe instanceof ShapelessOreRecipe) return ((ShapelessOreRecipe)recipe).getInput().toArray();
else if (recipe instanceof ShapedOreRecipe) return getShapedOreRecipe((ShapedOreRecipe)recipe);
else if (recipe instanceof ShapedRecipes) return ((ShapedRecipes)recipe).recipeItems;
else if (recipe instanceof ShapelessRecipes) return ((ShapelessRecipes)recipe).recipeItems.toArray(EMPTY_ITEM_STACK_ARRAY);
return null;
}
private static Object[] getShapedOreRecipe(ShapedOreRecipe recipe) {
final int width = shapedOreRecipeWidth.get(recipe);
Object[] input = recipe.getInput();
int inputIndex = 0;
Object[] grid = new Object[9];
for (int y = 0; y < 3; y++) {
for (int x = 0; x < 3; x++) {
final int outputIndex = y * 3 + x;
if (x < width && inputIndex < input.length) {
grid[outputIndex] = input[inputIndex];
inputIndex++;
} else {
grid[outputIndex] = null;
}
}
}
return grid;
}
@SuppressWarnings("unchecked")
private static void addOreRecipeEntry(InputBuilder builder, int slot, Object value) {
if (value instanceof ItemStack) builder.add(slot, (ItemStack)value);
else if (value instanceof Collection) {
List<ItemStack> variants = Lists.newArrayList();
for (ItemStack stack : (Collection<ItemStack>)value) {
if (stack.getItemDamage() == OreDictionary.WILDCARD_VALUE) {
final Item item = stack.getItem();
item.getSubItems(item, null, variants);
} else {
variants.add(stack);
}
}
builder.add(slot, variants);
}
}
public static ItemStack[][] getFullRecipeInput(IRecipe recipe) {
if (recipe instanceof ShapelessOreRecipe) return getFullRecipeInput(((ShapelessOreRecipe)recipe));
else if (recipe instanceof ShapedOreRecipe) return getFullRecipeInput((ShapedOreRecipe)recipe);
else if (recipe instanceof ShapedRecipes) return getFullRecipeInput((ShapedRecipes)recipe);
else if (recipe instanceof ShapelessRecipes) return getFullRecipeInput((ShapelessRecipes)recipe);
return null;
}
public static ItemStack[][] getFullRecipeInput(ShapelessOreRecipe recipe) {
final List<Object> inputs = recipe.getInput();
final int size = inputs.size();
InputBuilder builder = new InputBuilder(size);
for (int i = 0; i < size; i++) {
final Object input = inputs.get(i);
addOreRecipeEntry(builder, i, input);
}
return builder.build();
}
public static ItemStack[][] getFullRecipeInput(ShapedOreRecipe recipe) {
final InputBuilder builder = new InputBuilder(9);
final int width = shapedOreRecipeWidth.get(recipe);
final int height = shapedOreRecipeHeight.get(recipe);
final Object[] input = recipe.getInput();
int inputIndex = 0;
for (int row = 0; row < height; row++) {
for (int column = 0; column < width; column++) {
final int outputIndex = row * 3 + column;
addOreRecipeEntry(builder, outputIndex, input[inputIndex]);
inputIndex++;
}
}
return builder.build();
}
public static ItemStack[][] getFullRecipeInput(ShapedRecipes recipe) {
final InputBuilder builder = new InputBuilder(9);
final ItemStack[] input = recipe.recipeItems;
int inputIndex = 0;
for (int row = 0; row < recipe.recipeHeight; row++) {
for (int column = 0; column < recipe.recipeWidth; column++) {
final int outputIndex = row * 3 + column;
builder.add(outputIndex, input[inputIndex]);
inputIndex++;
}
}
return builder.build();
}
public static ItemStack[][] getFullRecipeInput(ShapelessRecipes recipe) {
final InputBuilder builder = new InputBuilder(9);
@SuppressWarnings("unchecked")
final List<ItemStack> input = recipe.recipeItems;
for (int i = 0; i < recipe.getRecipeSize(); i++)
builder.add(i, input.get(i));
return builder.build();
}
}