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