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