    001    package net.minecraftforge.oredict;
    002
    003    import java.util.ArrayList;
    004    import java.util.HashMap;
    005    import java.util.Map;
    006    import java.util.Map.Entry;
    007
    008    import net.minecraft.block.Block;
    009    import net.minecraft.item.crafting.IRecipe;
    010    import net.minecraft.inventory.InventoryCrafting;
    011    import net.minecraft.item.Item;
    012    import net.minecraft.item.ItemStack;
    013    import net.minecraft.item.crafting.ShapedRecipes;
    014    import net.minecraft.world.World;
    015
    016    public class ShapedOreRecipe implements IRecipe
    017    {
    018        //Added in for future ease of change, but hard coded for now.
    019        private static final int MAX_CRAFT_GRID_WIDTH = 3;
    020        private static final int MAX_CRAFT_GRID_HEIGHT = 3;
    021
    022        private ItemStack output = null;
    023        private Object[] input = null;
    024        private int width = 0;
    025        private int height = 0;
    026        private boolean mirrored = true;
    027
    028        public ShapedOreRecipe(Block     result, Object... recipe){ this(new ItemStack(result), recipe); }
    029        public ShapedOreRecipe(Item      result, Object... recipe){ this(new ItemStack(result), recipe); }
    030        public ShapedOreRecipe(ItemStack result, Object... recipe)
    031        {
    032            output = result.copy();
    033
    034            String shape = "";
    035            int idx = 0;
    036
    037            if (recipe[idx] instanceof Boolean)
    038            {
    039                mirrored = (Boolean)recipe[idx];
    040                if (recipe[idx+1] instanceof Object[])
    041                {
    042                    recipe = (Object[])recipe[idx+1];
    043                }
    044                else
    045                {
    046                    idx = 1;
    047                }
    048            }
    049
    050            if (recipe[idx] instanceof String[])
    051            {
    052                String[] parts = ((String[])recipe[idx++]);
    053
    054                for (String s : parts)
    055                {
    056                    width = s.length();
    057                    shape += s;
    058                }
    059
    060                height = parts.length;
    061            }
    062            else
    063            {
    064                while (recipe[idx] instanceof String)
    065                {
    066                    String s = (String)recipe[idx++];
    067                    shape += s;
    068                    width = s.length();
    069                    height++;
    070                }
    071            }
    072
    073            if (width * height != shape.length())
    074            {
    075                String ret = "Invalid shaped ore recipe: ";
    076                for (Object tmp :  recipe)
    077                {
    078                    ret += tmp + ", ";
    079                }
    080                ret += output;
    081                throw new RuntimeException(ret);
    082            }
    083
    084            HashMap<Character, Object> itemMap = new HashMap<Character, Object>();
    085
    086            for (; idx < recipe.length; idx += 2)
    087            {
    088                Character chr = (Character)recipe[idx];
    089                Object in = recipe[idx + 1];
    090                Object val = null;
    091
    092                if (in instanceof ItemStack)
    093                {
    094                    itemMap.put(chr, ((ItemStack)in).copy());
    095                }
    096                else if (in instanceof Item)
    097                {
    098                    itemMap.put(chr, new ItemStack((Item)in));
    099                }
    100                else if (in instanceof Block)
    101                {
    102                    itemMap.put(chr, new ItemStack((Block)in, 1, -1));
    103                }
    104                else if (in instanceof String)
    105                {
    106                    itemMap.put(chr, OreDictionary.getOres((String)in));
    107                }
    108                else
    109                {
    110                    String ret = "Invalid shaped ore recipe: ";
    111                    for (Object tmp :  recipe)
    112                    {
    113                        ret += tmp + ", ";
    114                    }
    115                    ret += output;
    116                    throw new RuntimeException(ret);
    117                }
    118            }
    119
    120            input = new Object[width * height];
    121            int x = 0;
    122            for (char chr : shape.toCharArray())
    123            {
    124                input[x++] = itemMap.get(chr);
    125            }
    126        }
    127
    128        ShapedOreRecipe(ShapedRecipes recipe, Map<ItemStack, String> replacements)
    129        {
    130            output = recipe.getRecipeOutput();
    131            width = recipe.recipeWidth;
    132            height = recipe.recipeHeight;
    133
    134            input = new Object[recipe.recipeItems.length];
    135
    136            for(int i = 0; i < input.length; i++)
    137            {
    138                ItemStack ingred = recipe.recipeItems[i];
    139
    140                if(ingred == null) continue;
    141
    142                input[i] = recipe.recipeItems[i];
    143
    144                for(Entry<ItemStack, String> replace : replacements.entrySet())
    145                {
    146                    if(OreDictionary.itemMatches(replace.getKey(), ingred, true))
    147                    {
    148                        input[i] = OreDictionary.getOres(replace.getValue());
    149                        break;
    150                    }
    151                }
    152            }
    153        }
    154
    155        @Override
    156        public ItemStack getCraftingResult(InventoryCrafting var1){ return output.copy(); }
    157
    158        @Override
    159        public int getRecipeSize(){ return input.length; }
    160
    161        @Override
    162        public ItemStack getRecipeOutput(){ return output; }
    163
    164        @Override
    165        public boolean matches(InventoryCrafting inv, World world)
    166        {
    167            for (int x = 0; x <= MAX_CRAFT_GRID_WIDTH - width; x++)
    168            {
    169                for (int y = 0; y <= MAX_CRAFT_GRID_HEIGHT - height; ++y)
    170                {
    171                    if (checkMatch(inv, x, y, true))
    172                    {
    173                        return true;
    174                    }
    175
    176                    if (mirrored && checkMatch(inv, x, y, false))
    177                    {
    178                        return true;
    179                    }
    180                }
    181            }
    182
    183            return false;
    184        }
    185
    186        private boolean checkMatch(InventoryCrafting inv, int startX, int startY, boolean mirror)
    187        {
    188            for (int x = 0; x < MAX_CRAFT_GRID_WIDTH; x++)
    189            {
    190                for (int y = 0; y < MAX_CRAFT_GRID_HEIGHT; y++)
    191                {
    192                    int subX = x - startX;
    193                    int subY = y - startY;
    194                    Object target = null;
    195
    196                    if (subX >= 0 && subY >= 0 && subX < width && subY < height)
    197                    {
    198                        if (mirror)
    199                        {
    200                            target = input[width - subX - 1 + subY * width];
    201                        }
    202                        else
    203                        {
    204                            target = input[subX + subY * width];
    205                        }
    206                    }
    207
    208                    ItemStack slot = inv.getStackInRowAndColumn(x, y);
    209
    210                    if (target instanceof ItemStack)
    211                    {
    212                        if (!checkItemEquals((ItemStack)target, slot))
    213                        {
    214                            return false;
    215                        }
    216                    }
    217                    else if (target instanceof ArrayList)
    218                    {
    219                        boolean matched = false;
    220
    221                        for (ItemStack item : (ArrayList<ItemStack>)target)
    222                        {
    223                            matched = matched || checkItemEquals(item, slot);
    224                        }
    225
    226                        if (!matched)
    227                        {
    228                            return false;
    229                        }
    230                    }
    231                    else if (target == null && slot != null)
    232                    {
    233                        return false;
    234                    }
    235                }
    236            }
    237
    238            return true;
    239        }
    240
    241        private boolean checkItemEquals(ItemStack target, ItemStack input)
    242        {
    243            if (input == null && target != null || input != null && target == null)
    244            {
    245                return false;
    246            }
    247            return (target.itemID == input.itemID && (target.getItemDamage() == -1 || target.getItemDamage() == input.getItemDamage()));
    248        }
    249
    250        public ShapedOreRecipe setMirrored(boolean mirror)
    251        {
    252            mirrored = mirror;
    253            return this;
    254        }
    255    }