From 08e6a656b89a46afcbb7f5b073b14fd42b3ebbfe Mon Sep 17 00:00:00 2001 From: AlgorithmX2 Date: Mon, 10 Feb 2014 23:51:25 -0600 Subject: [PATCH] Added Basic Quartz and Tool Recipes. Added Custom Recipes. --- core/Api.java | 9 + core/Registration.java | 14 +- core/features/AEFeature.java | 2 +- recipes/Ingredient.java | 69 +++++-- recipes/RecipeData.java | 18 ++ recipes/RecipeHandler.java | 263 +++++++++++++++++++------- recipes/Recipes/ShapedRecipe.java | 257 +++++++++++++++++++++++++ recipes/Recipes/ShapelessRecipe.java | 143 ++++++++++++++ recipes/handlers/OreRegistration.java | 33 ++++ recipes/handlers/Pureify.java | 44 +++++ recipes/handlers/Shaped.java | 50 ++++- recipes/handlers/Shapeless.java | 24 ++- recipes/loader/ConfigLoader.java | 25 +++ recipes/loader/JarLoader.java | 23 +++ 14 files changed, 879 insertions(+), 95 deletions(-) create mode 100644 recipes/RecipeData.java create mode 100644 recipes/Recipes/ShapedRecipe.java create mode 100644 recipes/Recipes/ShapelessRecipe.java create mode 100644 recipes/handlers/OreRegistration.java create mode 100644 recipes/handlers/Pureify.java create mode 100644 recipes/loader/ConfigLoader.java create mode 100644 recipes/loader/JarLoader.java diff --git a/core/Api.java b/core/Api.java index a72fca94a..dc772348f 100644 --- a/core/Api.java +++ b/core/Api.java @@ -12,12 +12,14 @@ import appeng.api.networking.IGridBlock; import appeng.api.networking.IGridConnection; import appeng.api.networking.IGridNode; import appeng.api.parts.IPartHelper; +import appeng.api.recipes.IRecipeHandler; import appeng.api.storage.IStorageHelper; import appeng.core.api.ApiPart; import appeng.core.api.ApiStorage; import appeng.core.features.registries.RegistryContainer; import appeng.me.GridConnection; import appeng.me.GridNode; +import appeng.recipes.RecipeHandler; import appeng.util.Platform; public class Api implements IAppEngApi @@ -94,4 +96,11 @@ public class Api implements IAppEngApi { return new GridConnection( a, b, ForgeDirection.UNKNOWN ); } + + @Override + public IRecipeHandler createNewRecipeHandler() + { + return new RecipeHandler(); + } + } diff --git a/core/Registration.java b/core/Registration.java index 42d8d8a78..3045337fb 100644 --- a/core/Registration.java +++ b/core/Registration.java @@ -7,6 +7,8 @@ import net.minecraft.util.WeightedRandomChestContent; import net.minecraft.world.biome.BiomeGenBase; import net.minecraftforge.common.ChestGenHooks; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.oredict.RecipeSorter; +import net.minecraftforge.oredict.RecipeSorter.Category; import appeng.api.AEApi; import appeng.api.config.Upgrades; import appeng.api.definitions.Blocks; @@ -109,6 +111,10 @@ import appeng.me.cache.SpatialPylonCache; import appeng.me.cache.TickManagerCache; import appeng.me.storage.AEExternalHandler; import appeng.recipes.RecipeHandler; +import appeng.recipes.Recipes.ShapedRecipe; +import appeng.recipes.Recipes.ShapelessRecipe; +import appeng.recipes.loader.ConfigLoader; +import appeng.recipes.loader.JarLoader; import appeng.recipes.ores.OreDictionaryHandler; import com.google.common.collect.ArrayListMultimap; @@ -137,6 +143,9 @@ public class Registration public void PreInit(FMLPreInitializationEvent event) { + RecipeSorter.register( "AE2-Shaped", ShapedRecipe.class, Category.SHAPED, "" ); + RecipeSorter.register( "AE2-Shapeless", ShapelessRecipe.class, Category.SHAPELESS, "" ); + MinecraftForge.EVENT_BUS.register( OreDictionaryHandler.instance ); Items items = appeng.core.Api.instance.items(); @@ -402,7 +411,10 @@ public class Registration public void Init(FMLInitializationEvent event) { - recipeHandler.parseRecipes( "" ); + if ( AEConfig.instance.isFeatureEnabled( AEFeature.CustomRecipes ) ) + recipeHandler.parseRecipes( new ConfigLoader( AppEng.instance.getConfigPath() ), "index.recipe" ); + else + recipeHandler.parseRecipes( new JarLoader( "/assets/appliedenergistics2/recipes/" ), "index.recipe" ); IPartHelper ph = AEApi.instance().partHelper(); ph.registerNewLayer( "appeng.api.parts.layers.LayerIEnergySink", "ic2.api.energy.tile.IEnergySink" ); diff --git a/core/features/AEFeature.java b/core/features/AEFeature.java index 3b5c9a15a..925be8804 100644 --- a/core/features/AEFeature.java +++ b/core/features/AEFeature.java @@ -46,7 +46,7 @@ public enum AEFeature DuplicateItems("Misc", false), Profiler("Services"), VersionChecker("Services"), Debug("Misc", false), Creative("Misc"), - Logging("Misc"), IntegrationLogging("Misc", false); + Logging("Misc"), IntegrationLogging("Misc", false), CustomRecipes("Misc", false); String Category; boolean visible = true; diff --git a/recipes/Ingredient.java b/recipes/Ingredient.java index 46004c888..cd929b3d6 100644 --- a/recipes/Ingredient.java +++ b/recipes/Ingredient.java @@ -1,5 +1,7 @@ package appeng.recipes; +import java.util.List; + import net.minecraft.block.Block; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -8,6 +10,7 @@ import appeng.core.AppEng; import appeng.items.materials.MaterialType; import appeng.items.parts.ItemPart; import appeng.items.parts.PartType; +import cpw.mods.fml.common.registry.GameRegistry; public class Ingredient { @@ -18,7 +21,12 @@ public class Ingredient final public String itemName; final public int meta; - public Ingredient(RecipeHandler handler, String input) throws RecipeError { + final public int qty; + + public Ingredient(RecipeHandler handler, String input, int qty) throws RecipeError { + + // works no matter wat! + this.qty = qty; if ( input.equals( "_" ) ) { @@ -103,19 +111,35 @@ public class Ingredient if ( isAir ) throw new RegistrationError( "Found blank item and expected a real item." ); - Object o = Item.itemRegistry.getObject( nameSpace + ":" + itemName ); - if ( o instanceof Item ) - return new ItemStack( (Item) o, 1, meta ); - if ( o instanceof Block ) - return new ItemStack( (Block) o, 1, meta ); + if ( nameSpace.equalsIgnoreCase( "oreDictionary" ) ) + throw new RegistrationError( "Recipe format expected a single item, but got a set of items." ); - o = Item.itemRegistry.getObject( nameSpace + ":item." + itemName ); - if ( o instanceof Item ) - return new ItemStack( (Item) o, 1, meta ); + Block blk = GameRegistry.findBlock( nameSpace, itemName ); + if ( blk == null ) + blk = GameRegistry.findBlock( nameSpace, "tile." + itemName ); - o = Item.itemRegistry.getObject( nameSpace + ":tile." + itemName ); - if ( o instanceof Block ) - return new ItemStack( (Block) o, 1, meta ); + if ( blk != null ) + return new ItemStack( blk, qty, meta ); + + Item it = GameRegistry.findItem( nameSpace, itemName ); + if ( it == null ) + it = GameRegistry.findItem( nameSpace, "item." + itemName ); + + if ( it != null ) + return new ItemStack( it, qty, meta ); + + /* + * Object o = Item.itemRegistry.getObject( nameSpace + ":" + itemName ); if ( o instanceof Item ) return new + * ItemStack( (Item) o, qty, meta ); + * + * if ( o instanceof Block ) return new ItemStack( (Block) o, qty, meta ); + * + * o = Item.itemRegistry.getObject( nameSpace + ":item." + itemName ); if ( o instanceof Item ) return new + * ItemStack( (Item) o, qty, meta ); + * + * o = Block.blockRegistry.getObject( nameSpace + ":tile." + itemName ); if ( o instanceof Block && (!(o + * instanceof BlockAir)) ) return new ItemStack( (Block) o, qty, meta ); + */ throw new MissingIngredientError( "Unable to find item: " + toString() ); } @@ -126,4 +150,25 @@ public class Ingredient return nameSpace + ":" + itemName + ":" + meta; } + public ItemStack[] getSet() throws RegistrationError, MissingIngredientError + { + if ( nameSpace.equalsIgnoreCase( "oreDictionary" ) ) + { + List ores = OreDictionary.getOres( itemName ); + ItemStack[] set = ores.toArray( new ItemStack[ores.size()] ); + + // clone and set qty. + for (int x = 0; x < set.length; x++) + { + ItemStack is = set[x].copy(); + is.stackSize = qty; + set[x] = is; + } + + return set; + } + + return new ItemStack[] { getItemStack() }; + } + } diff --git a/recipes/RecipeData.java b/recipes/RecipeData.java new file mode 100644 index 000000000..16a89fe0f --- /dev/null +++ b/recipes/RecipeData.java @@ -0,0 +1,18 @@ +package appeng.recipes; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +import appeng.recipes.handlers.CraftHandler; + +public class RecipeData +{ + + final public HashMap aliases = new HashMap(); + final public List Handlers = new LinkedList(); + + public boolean crash = true; + public boolean erroronmissing = true; + +} diff --git a/recipes/RecipeHandler.java b/recipes/RecipeHandler.java index 5a7ceb176..4f53ed1ce 100644 --- a/recipes/RecipeHandler.java +++ b/recipes/RecipeHandler.java @@ -1,102 +1,139 @@ package appeng.recipes; -import java.io.DataInputStream; -import java.io.InputStream; +import java.io.BufferedReader; import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map.Entry; -import net.minecraft.client.Minecraft; -import net.minecraft.util.ResourceLocation; - +import appeng.api.recipes.IRecipeHandler; +import appeng.api.recipes.IRecipeLoader; import appeng.core.AELog; -import appeng.core.AppEng; import appeng.recipes.handlers.CraftHandler; import appeng.recipes.handlers.Grind; +import appeng.recipes.handlers.OreRegistration; +import appeng.recipes.handlers.Pureify; import appeng.recipes.handlers.Shaped; +import appeng.recipes.handlers.Shapeless; import appeng.recipes.handlers.Smelt; -public class RecipeHandler +public class RecipeHandler implements IRecipeHandler { - HashMap aliases = new HashMap(); - List Handlers = new LinkedList(); - List tokens = new LinkedList(); + final public List tokens = new LinkedList(); + final RecipeData data; - boolean crash = true; - boolean erroronmissing = true; - - private void addCrafting(CraftHandler ch) - { - Handlers.add( ch ); + public RecipeHandler() { + data = new RecipeData(); } + RecipeHandler(RecipeHandler parent) { + data = parent.data; + } + + private void addCrafting(CraftHandler ch) + { + data.Handlers.add( ch ); + } + + @Override public void registerHandlers() { + HashMap processed = new HashMap(); try { - for (CraftHandler ch : Handlers) + for (CraftHandler ch : data.Handlers) { try { ch.register(); + + Class clz = ch.getClass(); + Integer i = processed.get( clz ); + if ( i == null ) + processed.put( clz, 1 ); + else + processed.put( clz, i + 1 ); } catch (RegistrationError e) { AELog.warning( "Unable to regsiter a recipe." ); AELog.error( e ); - if ( crash ) throw e; + if ( data.crash ) + throw e; } catch (MissingIngredientError e) { - if ( erroronmissing ) + if ( data.erroronmissing ) { AELog.warning( "Unable to regsiter a recipe." ); - AELog.error( e ); - if ( crash ) throw e; + AELog.error( e ); + if ( data.crash ) + throw e; } } } } - catch( Throwable e ) + catch (Throwable e) { AELog.error( e ); - if ( crash ) - throw new RuntimeException(e); + if ( data.crash ) + throw new RuntimeException( e ); + } + + for (Entry e : processed.entrySet()) + { + AELog.info( "Recipes Loading: " + e.getKey().getSimpleName() + ": " + e.getValue() + " loaded." ); } } public String alias(String in) { - String out = aliases.get( in ); + String out = data.aliases.get( in ); if ( out != null ) return out; return in; } - - public void parseRecipes(String path) + + @Override + public void parseRecipes(IRecipeLoader loader, String path) { try { - ResourceLocation r = new ResourceLocation(AppEng.instance.modid, path ); - InputStream in = Minecraft.getMinecraft().getResourceManager().getResource(r).getInputStream(); - DataInputStream reader = new DataInputStream(in); - + BufferedReader reader = null; + try + { + reader = loader.getFile( path ); + } + catch (Exception err) + { + AELog.warning( "Error Loading Recipe File:" + path ); + AELog.error( err ); + return; + } + boolean inQuote = false; - + boolean inComment = false; + String token = ""; int line = 0; - - while ( in.available() > 0) + + int val = -1; + while ((val = reader.read()) != -1) { - char c = reader.readChar(); - + char c = (char) val; + if ( c == '\n' ) line++; - - if ( inQuote ) + + if ( inComment ) + { + if ( c == '\n' || c == '\r' ) + inComment = false; + } + else if ( inQuote ) { switch (c) { @@ -115,7 +152,7 @@ public class RecipeHandler inQuote = !inQuote; break; case ',': - + if ( token.length() > 0 ) { tokens.add( token ); @@ -123,44 +160,49 @@ public class RecipeHandler } token = ""; break; - + case '=': - - processTokens( path,line ); - + + processTokens( loader, path, line ); + if ( token.length() > 0 ) tokens.add( token ); token = ""; - + break; - + + case '#': + inComment = true; + // then add a token if you can... + case '\n': case '\t': case '\r': case ' ': - + if ( token.length() > 0 ) tokens.add( token ); token = ""; - + break; default: token = token + c; } } - + } - processTokens( path,line ); + reader.close(); + processTokens( loader, path, line ); } - catch( Throwable e ) + catch (Throwable e) { AELog.error( e ); - if ( crash ) - throw new RuntimeException(e); + if ( data.crash ) + throw new RuntimeException( e ); } } - private void processTokens(String file, int line) throws RecipeError + private void processTokens(IRecipeLoader loader, String file, int line) throws RecipeError { try { @@ -175,34 +217,38 @@ public class RecipeHandler if ( operation.equals( "alias" ) ) { if ( tokens.size() == 3 && tokens.indexOf( "->" ) == 1 ) - aliases.put( tokens.get( 0 ), tokens.get( 2 ) ); + data.aliases.put( tokens.get( 0 ), tokens.get( 2 ) ); else throw new RecipeError( "Alias must have exactly 1 input and 1 output." ); } - else if ( operation.equals( "crash" )&& ( tokens.get( 0 ).equals("true") || tokens.get( 0 ).equals("false") )) + else if ( operation.equals( "group" ) ) { - if ( tokens.size() == 1 ) + List pre = tokens.subList( 0, split - 1 ); + List post = tokens.subList( split, tokens.size() ); + + List> inputs = parseLines( pre ); + + if ( inputs.size() >= 1 && post.size() == 1 ) { - crash = tokens.get(0).equals("true"); + } else - throw new RecipeError( "crash must be true or false explicitly." ); + throw new RecipeError( "Group must have exactly 1 output, and 1 or more inputs." ); } - else if ( operation.equals( "erroronmissing" ) ) + else if ( operation.equals( "ore" ) ) { - if ( tokens.size() == 1 && ( tokens.get( 0 ).equals("true") || tokens.get( 0 ).equals("false") )) + List pre = tokens.subList( 0, split - 1 ); + List post = tokens.subList( split, tokens.size() ); + + List> inputs = parseLines( pre ); + + if ( inputs.size() == 1 && inputs.get( 0 ).size() > 0 && post.size() == 1 ) { - erroronmissing = tokens.get(0).equals("true"); + CraftHandler ch = new OreRegistration( inputs.get( 0 ), post.get( 0 ) ); + addCrafting( ch ); } else - throw new RecipeError( "erroronmissing must be true or false explicitly." ); - } - else if ( operation.equals( "import" ) ) - { - if ( tokens.size() == 1 ) - parseRecipes( tokens.get(0) ); - else - throw new RecipeError( "Import must have exactly 1 input." ); + throw new RecipeError( "Group must have exactly 1 output, and 1 or more inputs in a single row." ); } else { @@ -216,8 +262,12 @@ public class RecipeHandler if ( operation.equals( "shaped" ) ) ch = new Shaped(); + else if ( operation.equals( "shapeless" ) ) + ch = new Shapeless(); else if ( operation.equals( "smelt" ) ) ch = new Smelt(); + else if ( operation.equals( "pureify" ) ) + ch = new Pureify(); else if ( operation.equals( "grind" ) ) ch = new Grind(); @@ -231,14 +281,45 @@ public class RecipeHandler } } else - throw new RecipeError( tokens.toString() + "; recipe without an output." ); + { + String operation = tokens.remove( 0 ).toLowerCase(); + + if ( operation.equals( "crash" ) && (tokens.get( 0 ).equals( "true" ) || tokens.get( 0 ).equals( "false" )) ) + { + if ( tokens.size() == 1 ) + { + data.crash = tokens.get( 0 ).equals( "true" ); + } + else + throw new RecipeError( "crash must be true or false explicitly." ); + } + else if ( operation.equals( "erroronmissing" ) ) + { + if ( tokens.size() == 1 && (tokens.get( 0 ).equals( "true" ) || tokens.get( 0 ).equals( "false" )) ) + { + data.erroronmissing = tokens.get( 0 ).equals( "true" ); + } + else + throw new RecipeError( "erroronmissing must be true or false explicitly." ); + } + else if ( operation.equals( "import" ) ) + { + if ( tokens.size() == 1 ) + (new RecipeHandler( this )).parseRecipes( loader, tokens.get( 0 ) ); + else + throw new RecipeError( "Import must have exactly 1 input." ); + } + else + throw new RecipeError( operation + ": " + tokens.toString() + "; recipe without an output." ); + } } catch (RecipeError e) { - AELog.warning( "Recipe Error near line:" + line + " in "+file+" with: " + tokens.toString() ); + AELog.warning( "Recipe Error near line:" + line + " in " + file + " with: " + tokens.toString() ); AELog.error( e ); - if ( crash ) throw e; + if ( data.crash ) + throw e; } tokens.clear(); @@ -249,17 +330,38 @@ public class RecipeHandler List> out = new LinkedList>(); List cList = new LinkedList(); + boolean hasQty = false; + int qty = 1; + for (String v : subList) { if ( v.equals( "," ) ) { + if ( hasQty ) + throw new RecipeError( "Qty found with no item." ); if ( !cList.isEmpty() ) out.add( cList ); cList = new LinkedList(); } else { - cList.add( new Ingredient( this, v ) ); + if ( isNumber( v ) ) + { + if ( hasQty ) + throw new RecipeError( "Qty found with no item." ); + hasQty = true; + qty = Integer.parseInt( v ); + } + else + { + if ( hasQty ) + { + cList.add( new Ingredient( this, v, qty ) ); + hasQty = false; + } + else + cList.add( new Ingredient( this, v, 1 ) ); + } } } @@ -268,4 +370,19 @@ public class RecipeHandler return out; } + + private boolean isNumber(String v) + { + if ( v.length() <= 0 ) + return false; + + int l = v.length(); + for (int x = 0; x < l; x++) + { + if ( !Character.isDigit( v.charAt( x ) ) ) + return false; + } + + return true; + } } diff --git a/recipes/Recipes/ShapedRecipe.java b/recipes/Recipes/ShapedRecipe.java new file mode 100644 index 000000000..7c2c18205 --- /dev/null +++ b/recipes/Recipes/ShapedRecipe.java @@ -0,0 +1,257 @@ +package appeng.recipes.Recipes; + +import java.util.ArrayList; +import java.util.HashMap; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.world.World; +import net.minecraftforge.oredict.OreDictionary; + +public class ShapedRecipe implements IRecipe +{ + + // Added in for future ease of change, but hard coded for now. + private static final int MAX_CRAFT_GRID_WIDTH = 3; + private static final int MAX_CRAFT_GRID_HEIGHT = 3; + + private ItemStack output = null; + private Object[] input = null; + private int width = 0; + private int height = 0; + private boolean mirrored = true; + + public ShapedRecipe(ItemStack result, Object... recipe) { + output = result.copy(); + + String shape = ""; + int idx = 0; + + if ( recipe[idx] instanceof Boolean ) + { + mirrored = (Boolean) recipe[idx]; + if ( recipe[idx + 1] instanceof Object[] ) + { + recipe = (Object[]) recipe[idx + 1]; + } + else + { + idx = 1; + } + } + + if ( recipe[idx] instanceof String[] ) + { + String[] parts = ((String[]) recipe[idx++]); + + for (String s : parts) + { + width = s.length(); + shape += s; + } + + height = parts.length; + } + else + { + while (recipe[idx] instanceof String) + { + String s = (String) recipe[idx++]; + shape += s; + width = s.length(); + height++; + } + } + + if ( width * height != shape.length() ) + { + String ret = "Invalid shaped ore recipe: "; + for (Object tmp : recipe) + { + ret += tmp + ", "; + } + ret += output; + throw new RuntimeException( ret ); + } + + HashMap itemMap = new HashMap(); + + for (; idx < recipe.length; idx += 2) + { + Character chr = (Character) recipe[idx]; + Object in = recipe[idx + 1]; + + if ( in instanceof ItemStack ) + { + itemMap.put( chr, ((ItemStack) in).copy() ); + } + else if ( in instanceof ItemStack[] ) + { + ItemStack[] a = (ItemStack[]) in; + if ( a.length == 1 ) + itemMap.put( chr, a[0] ); + else + itemMap.put( chr, a ); + } + else if ( in instanceof String ) + { + itemMap.put( chr, OreDictionary.getOres( (String) in ) ); + } + else + { + String ret = "Invalid shaped ore recipe: "; + for (Object tmp : recipe) + { + ret += tmp + ", "; + } + ret += output; + throw new RuntimeException( ret ); + } + } + + input = new Object[width * height]; + int x = 0; + for (char chr : shape.toCharArray()) + { + input[x++] = itemMap.get( chr ); + } + } + + @Override + public ItemStack getCraftingResult(InventoryCrafting var1) + { + return output.copy(); + } + + @Override + public int getRecipeSize() + { + return input.length; + } + + @Override + public ItemStack getRecipeOutput() + { + return output; + } + + @Override + public boolean matches(InventoryCrafting inv, World world) + { + for (int x = 0; x <= MAX_CRAFT_GRID_WIDTH - width; x++) + { + for (int y = 0; y <= MAX_CRAFT_GRID_HEIGHT - height; ++y) + { + if ( checkMatch( inv, x, y, false ) ) + { + return true; + } + + if ( mirrored && checkMatch( inv, x, y, true ) ) + { + return true; + } + } + } + + return false; + } + + @SuppressWarnings("unchecked") + private boolean checkMatch(InventoryCrafting inv, int startX, int startY, boolean mirror) + { + for (int x = 0; x < MAX_CRAFT_GRID_WIDTH; x++) + { + for (int y = 0; y < MAX_CRAFT_GRID_HEIGHT; y++) + { + int subX = x - startX; + int subY = y - startY; + Object target = null; + + if ( subX >= 0 && subY >= 0 && subX < width && subY < height ) + { + if ( mirror ) + { + target = input[width - subX - 1 + subY * width]; + } + else + { + target = input[subX + subY * width]; + } + } + + ItemStack slot = inv.getStackInRowAndColumn( x, y ); + + if ( target instanceof ItemStack ) + { + if ( !checkItemEquals( (ItemStack) target, slot ) ) + { + return false; + } + } + else if ( target instanceof ItemStack[] ) + { + boolean matched = false; + + for (ItemStack item : (ItemStack[]) target) + { + matched = matched || checkItemEquals( item, slot ); + } + + if ( !matched ) + { + return false; + } + } + else if ( target instanceof ArrayList ) + { + boolean matched = false; + + for (ItemStack item : (ArrayList) target) + { + matched = matched || checkItemEquals( item, slot ); + } + + if ( !matched ) + { + return false; + } + } + else if ( target == null && slot != null ) + { + return false; + } + } + } + + return true; + } + + private boolean checkItemEquals(ItemStack target, ItemStack input) + { + if ( input == null && target != null || input != null && target == null ) + { + return false; + } + return (target.getItem() == input.getItem() && (target.getItemDamage() == OreDictionary.WILDCARD_VALUE || target.getItemDamage() == input + .getItemDamage())); + } + + public ShapedRecipe setMirrored(boolean mirror) + { + mirrored = mirror; + return this; + } + + /** + * Returns the input for this recipe, any mod accessing this value should never manipulate the values in this array + * as it will effect the recipe itself. + * + * @return The recipes input vales. + */ + public Object[] getInput() + { + return this.input; + } +} \ No newline at end of file diff --git a/recipes/Recipes/ShapelessRecipe.java b/recipes/Recipes/ShapelessRecipe.java new file mode 100644 index 000000000..eddca79f7 --- /dev/null +++ b/recipes/Recipes/ShapelessRecipe.java @@ -0,0 +1,143 @@ +package appeng.recipes.Recipes; + +import java.util.ArrayList; +import java.util.Iterator; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.world.World; +import net.minecraftforge.oredict.OreDictionary; + +public class ShapelessRecipe implements IRecipe +{ + + private ItemStack output = null; + private ArrayList input = new ArrayList(); + + public ShapelessRecipe(ItemStack result, Object... recipe) { + output = result.copy(); + for (Object in : recipe) + { + if ( in instanceof ItemStack ) + { + input.add( ((ItemStack) in).copy() ); + } + else if ( in instanceof ItemStack[] ) + { + ItemStack[] a = (ItemStack[]) in; + if ( a.length == 1 ) + input.add( a[0] ); + else + input.add( a ); + } + else if ( in instanceof String ) + { + input.add( OreDictionary.getOres( (String) in ) ); + } + else + { + String ret = "Invalid shapeless ore recipe: "; + for (Object tmp : recipe) + { + ret += tmp + ", "; + } + ret += output; + throw new RuntimeException( ret ); + } + } + } + + @Override + public int getRecipeSize() + { + return input.size(); + } + + @Override + public ItemStack getRecipeOutput() + { + return output; + } + + @Override + public ItemStack getCraftingResult(InventoryCrafting var1) + { + return output.copy(); + } + + @SuppressWarnings("unchecked") + @Override + public boolean matches(InventoryCrafting var1, World world) + { + ArrayList required = new ArrayList( input ); + + for (int x = 0; x < var1.getSizeInventory(); x++) + { + ItemStack slot = var1.getStackInSlot( x ); + + if ( slot != null ) + { + boolean inRecipe = false; + Iterator req = required.iterator(); + + while (req.hasNext()) + { + boolean match = false; + + Object next = req.next(); + + if ( next instanceof ItemStack ) + { + match = checkItemEquals( (ItemStack) next, slot ); + } + else if ( next instanceof ItemStack[] ) + { + for (ItemStack item : (ItemStack[]) next) + { + match = match || checkItemEquals( item, slot ); + } + } + else if ( next instanceof ArrayList ) + { + for (ItemStack item : (ArrayList) next) + { + match = match || checkItemEquals( item, slot ); + } + } + + if ( match ) + { + inRecipe = true; + required.remove( next ); + break; + } + } + + if ( !inRecipe ) + { + return false; + } + } + } + + return required.isEmpty(); + } + + private boolean checkItemEquals(ItemStack target, ItemStack input) + { + return (target.getItem() == input.getItem() && (target.getItemDamage() == OreDictionary.WILDCARD_VALUE || target.getItemDamage() == input + .getItemDamage())); + } + + /** + * Returns the input for this recipe, any mod accessing this value should never manipulate the values in this array + * as it will effect the recipe itself. + * + * @return The recipes input vales. + */ + public ArrayList getInput() + { + return this.input; + } +} \ No newline at end of file diff --git a/recipes/handlers/OreRegistration.java b/recipes/handlers/OreRegistration.java new file mode 100644 index 000000000..6f16a25ce --- /dev/null +++ b/recipes/handlers/OreRegistration.java @@ -0,0 +1,33 @@ +package appeng.recipes.handlers; + +import java.util.List; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.OreDictionary; +import appeng.recipes.Ingredient; +import appeng.recipes.MissingIngredientError; +import appeng.recipes.RegistrationError; + +public class OreRegistration extends CraftHandler +{ + + List inputs; + String name; + + public OreRegistration(List in, String out) { + inputs = in; + name = out; + } + + @Override + public void register() throws RegistrationError, MissingIngredientError + { + for (Ingredient i : inputs) + { + for (ItemStack is : i.getSet()) + { + OreDictionary.registerOre( name, is ); + } + } + } +} diff --git a/recipes/handlers/Pureify.java b/recipes/handlers/Pureify.java new file mode 100644 index 000000000..c5ca8d37a --- /dev/null +++ b/recipes/handlers/Pureify.java @@ -0,0 +1,44 @@ +package appeng.recipes.handlers; + +import java.util.List; + +import appeng.recipes.Ingredient; +import appeng.recipes.MissingIngredientError; +import appeng.recipes.RecipeError; +import appeng.recipes.RegistrationError; + +public class Pureify extends CraftHandler +{ + + Ingredient in; + Ingredient out; + + @Override + public void setup(List> input, List> output) throws RecipeError + { + if ( input.size() == 1 && output.size() == 1 ) + { + List inputList = input.get( 0 ); + List outputList = output.get( 0 ); + if ( inputList.size() == 1 && outputList.size() == 1 ) + { + in = inputList.get( 0 ); + out = outputList.get( 0 ); + return; + } + } + throw new RecipeError( "Pureify recipe can only have a single input and output." ); + } + + @Override + public void register() throws RegistrationError, MissingIngredientError + { + if ( in.getSet() == null ) + throw new RegistrationError( in.toString() + ": Pureify Input is not a valid item." ); + + if ( out.getItemStack().getItem() == null ) + throw new RegistrationError( out.toString() + ": Pureify Output is not a valid item." ); + + } + +} diff --git a/recipes/handlers/Shaped.java b/recipes/handlers/Shaped.java index 2e695ed75..bd0576db0 100644 --- a/recipes/handlers/Shaped.java +++ b/recipes/handlers/Shaped.java @@ -1,10 +1,16 @@ package appeng.recipes.handlers; +import java.util.ArrayList; import java.util.List; +import net.minecraft.item.ItemStack; +import appeng.core.AELog; import appeng.recipes.Ingredient; +import appeng.recipes.MissingIngredientError; import appeng.recipes.RecipeError; import appeng.recipes.RegistrationError; +import appeng.recipes.Recipes.ShapedRecipe; +import cpw.mods.fml.common.registry.GameRegistry; public class Shaped extends CraftHandler { @@ -20,12 +26,12 @@ public class Shaped extends CraftHandler { if ( output.size() == 1 && output.get( 0 ).size() == 1 ) { - rows = inputs.size(); - if ( rows > 0 && inputs.size() <= 3 ) + rows = input.size(); + if ( rows > 0 && input.size() <= 3 ) { - cols = inputs.get( 0 ).size(); - for (int x = 0; x < inputs.size(); x++) - if ( inputs.get( x ).size() != cols ) + cols = input.get( 0 ).size(); + for (int x = 0; x < input.size(); x++) + if ( input.get( x ).size() != cols ) throw new RecipeError( "all rows in a shaped crafting recipe must contain the same number of ingredients." ); inputs = input; @@ -39,8 +45,40 @@ public class Shaped extends CraftHandler } @Override - public void register() throws RegistrationError + public void register() throws RegistrationError, MissingIngredientError { + char first = 'A'; + List args = new ArrayList(); + for (int y = 0; y < rows; y++) + { + String row = ""; + for (int x = 0; x < cols; x++) + { + if ( inputs.get( y ).get( x ).isAir ) + row = row + " "; + else + { + row = row + first; + args.add( first ); + args.add( inputs.get( y ).get( x ).getSet() ); + + first++; + } + } + args.add( y, new String( row ) ); + } + + ItemStack outIS = output.getItemStack(); + + try + { + GameRegistry.addRecipe( new ShapedRecipe( outIS, args.toArray( new Object[args.size()] ) ) ); + } + catch (Throwable e) + { + AELog.error( e ); + throw new RegistrationError( "Error while adding shaped recipe." ); + } } } diff --git a/recipes/handlers/Shapeless.java b/recipes/handlers/Shapeless.java index 0505698d0..497bde0b1 100644 --- a/recipes/handlers/Shapeless.java +++ b/recipes/handlers/Shapeless.java @@ -1,10 +1,16 @@ package appeng.recipes.handlers; +import java.util.ArrayList; import java.util.List; +import net.minecraft.item.ItemStack; +import appeng.core.AELog; import appeng.recipes.Ingredient; +import appeng.recipes.MissingIngredientError; import appeng.recipes.RecipeError; import appeng.recipes.RegistrationError; +import appeng.recipes.Recipes.ShapelessRecipe; +import cpw.mods.fml.common.registry.GameRegistry; public class Shapeless extends CraftHandler { @@ -17,7 +23,7 @@ public class Shapeless extends CraftHandler { if ( output.size() == 1 && output.get( 0 ).size() == 1 ) { - if ( inputs.size() == 1 ) + if ( input.size() == 1 ) { inputs = input.get( 0 ); this.output = output.get( 0 ).get( 0 ); @@ -30,8 +36,22 @@ public class Shapeless extends CraftHandler } @Override - public void register() throws RegistrationError + public void register() throws RegistrationError, MissingIngredientError { + List args = new ArrayList(); + for (Ingredient i : inputs) + args.add( i.getSet() ); + ItemStack outIS = output.getItemStack(); + + try + { + GameRegistry.addRecipe( new ShapelessRecipe( outIS, args.toArray( new Object[args.size()] ) ) ); + } + catch (Throwable e) + { + AELog.error( e ); + throw new RegistrationError( "Erro while adding shapeless recipe." ); + } } } diff --git a/recipes/loader/ConfigLoader.java b/recipes/loader/ConfigLoader.java new file mode 100644 index 000000000..c4ccc460f --- /dev/null +++ b/recipes/loader/ConfigLoader.java @@ -0,0 +1,25 @@ +package appeng.recipes.loader; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; + +import appeng.api.recipes.IRecipeLoader; + +public class ConfigLoader implements IRecipeLoader +{ + + private String rootPath; + + public ConfigLoader(String s) { + rootPath = s; + } + + @Override + public BufferedReader getFile(String s) throws Exception + { + File f = new File( rootPath + s ); + return new BufferedReader( new InputStreamReader( new FileInputStream( f ), "UTF-8" ) ); + } +} diff --git a/recipes/loader/JarLoader.java b/recipes/loader/JarLoader.java new file mode 100644 index 000000000..6b9f6c839 --- /dev/null +++ b/recipes/loader/JarLoader.java @@ -0,0 +1,23 @@ +package appeng.recipes.loader; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +import appeng.api.recipes.IRecipeLoader; + +public class JarLoader implements IRecipeLoader +{ + + private String rootPath; + + public JarLoader(String s) { + rootPath = s; + } + + @Override + public BufferedReader getFile(String s) throws Exception + { + return new BufferedReader( new InputStreamReader( getClass().getResourceAsStream( rootPath + s ), "UTF-8" ) ); + } + +}