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