package crazypants.enderio.machine.recipe; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import net.minecraft.item.ItemStack; import org.apache.commons.io.IOUtils; import crazypants.enderio.Log; import crazypants.enderio.config.Config; public class RecipeConfig { //---------------------------------------------- Loading ------------ public static RecipeConfig loadRecipeConfig(String coreFileName, String customFileName, CustomTagHandler customHandler) { File coreFile = new File(Config.configDirectory, coreFileName); String defaultVals = null; try { defaultVals = readRecipes(coreFile, coreFileName, true); } catch (IOException e) { Log.error("Could not load default recipes file " + coreFile + " from EnderIO jar: " + e.getMessage()); e.printStackTrace(); return null; } if(!coreFile.exists()) { Log.error("Could not load default recipes from " + coreFile + " as the file does not exist."); return null; } RecipeConfig config; try { config = RecipeConfigParser.parse(defaultVals, customHandler); } catch (Exception e) { Log.error("Error parsing " + coreFileName); return null; } File userFile = new File(Config.configDirectory, customFileName); String userConfigStr = null; try { userConfigStr = readRecipes(userFile, customFileName, false); if(userConfigStr == null || userConfigStr.trim().length() == 0) { Log.error("Empty user config file: " + userFile.getAbsolutePath()); } else { RecipeConfig userConfig = RecipeConfigParser.parse(userConfigStr, customHandler); config.merge(userConfig); } } catch (Exception e) { Log.error("Could not load user defined recipes from file: " + customFileName); e.printStackTrace(); } return config; } public static String readRecipes(File copyTo, String fileName, boolean replaceIfExists) throws IOException { if(!replaceIfExists && copyTo.exists()) { return readStream(new FileInputStream(copyTo)); } InputStream in = RecipeConfig.class.getResourceAsStream("/assets/enderio/config/" + fileName); if(in == null) { Log.error("Could load default AlloySmelter recipes."); throw new IOException("Could not resource /assets/enderio/config/" + fileName + " form classpath. "); } String output = readStream(in); BufferedWriter writer = null; try { writer = new BufferedWriter(new FileWriter(copyTo, false)); writer.write(output.toString()); } finally { IOUtils.closeQuietly(writer); } return output.toString(); } private static String readStream(InputStream in) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(in)); StringBuilder output = new StringBuilder(); try { String line = reader.readLine(); while (line != null) { output.append(line); output.append("\n"); line = reader.readLine(); } } finally { IOUtils.closeQuietly(reader); } return output.toString(); } //---------------------------------------------- Class ------------ private boolean dumpItemRegistery = false; private boolean dumpOreDictionary = false; private boolean enabled = true; private Map<String, RecipeGroup> recipeGroups = new HashMap<String, RecipeConfig.RecipeGroup>(); public RecipeConfig() { } public void merge(RecipeConfig userConfig) { if(userConfig.dumpItemRegistery) { dumpItemRegistery = true; } if(userConfig.dumpOreDictionary) { dumpOreDictionary = true; } for (RecipeGroup group : userConfig.getRecipeGroups().values()) { if(!group.enabled) { if(recipeGroups.remove(group.name) != null) { Log.info("Disabled core recipe group " + group.name + " due to user config."); } } else { RecipeGroup modifyGroup = recipeGroups.get(group.name); if(modifyGroup == null) { Log.info("Added user defined recipe group " + group.name); modifyGroup = new RecipeGroup(group.name); recipeGroups.put(group.name, modifyGroup); } for (RecipeElement recipe : group.recipes.values()) { if(recipe.isValid()) { if(modifyGroup.recipes.containsKey(recipe.name)) { Log.info("Replacing core recipe " + recipe.name + " with user defined recipe."); } else { Log.info("Added user defined recipe " + recipe.name); } modifyGroup.addRecipe(recipe); } else { Log.info("Removed recipe " + recipe.name + " due to user config."); modifyGroup.recipes.remove(recipe.name); } } } } } public RecipeGroup createRecipeGroup(String name) { return new RecipeGroup(name); } public void addRecipeGroup(RecipeGroup group) { if(group.isNameValid()) { recipeGroups.put(group.getName(), group); } } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public void setRecipeGroups(Map<String, RecipeGroup> recipeGroups) { this.recipeGroups = recipeGroups; } public boolean isDumpItemRegistery() { return dumpItemRegistery; } public void setDumpItemRegistery(boolean dumpItemRegistery) { this.dumpItemRegistery = dumpItemRegistery; } public boolean isDumpOreDictionary() { return dumpOreDictionary; } public void setDumpOreDictionary(boolean dumpOreDictionary) { this.dumpOreDictionary = dumpOreDictionary; } public List<Recipe> getRecipes(boolean isRecipePerInput) { List<Recipe> result = new ArrayList<Recipe>(32); for (RecipeGroup rg : recipeGroups.values()) { if(rg.isEnabled() && rg.isValid()) { result.addAll(rg.createRecipes(isRecipePerInput)); } } return result; } public List<Recipe> getRecipesForGroup(String group, boolean isRecipePerInput) { RecipeGroup grp = recipeGroups.get(group); if(grp == null) { return Collections.emptyList(); } return grp.createRecipes(isRecipePerInput); } public Map<String, RecipeGroup> getRecipeGroups() { return recipeGroups; } public static class RecipeGroup { private final String name; private Map<String, RecipeElement> recipes = new LinkedHashMap<String, RecipeElement>(); private boolean enabled = true; public RecipeGroup(String name) { if(name != null) { name = name.trim(); if (name.length() <= 0) { name = null; } } this.name = name; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public RecipeElement createRecipe(String name) { return new RecipeElement(name); } public void addRecipe(RecipeElement recipe) { recipes.put(recipe.name, recipe); } public String getName() { return name; } public List<Recipe> createRecipes(boolean isRecipePerInput) { List<Recipe> result = new ArrayList<Recipe>(recipes.size()); for (RecipeElement recipe : recipes.values()) { if(recipe.isValid()) { result.addAll(recipe.createRecipes(isRecipePerInput)); } } return result; } public boolean isValid() { return isNameValid() && !recipes.isEmpty(); } public boolean isNameValid() { return name != null; } @Override public String toString() { return "RecipeGroup [name=" + name + ", recipes=" + recipes + ", enabled=" + enabled + "]"; } } public static class RecipeElement { private List<RecipeInput> inputs = new ArrayList<RecipeInput>(); private List<RecipeOutput> outputs = new ArrayList<RecipeOutput>(); private int energyRequired; private RecipeBonusType bonusType = RecipeBonusType.MULTIPLY_OUTPUT; private String name; private boolean allowMissing = false; private boolean invalidated = false; private RecipeElement(String name) { this.name = name; } public void addInput(RecipeInput input) { inputs.add(input); } public void addInput(ItemStack stack, boolean useMetadata) { inputs.add(new RecipeInput(stack, useMetadata)); } public void addOutput(RecipeOutput output) { outputs.add(output); } public List<Recipe> createRecipes(boolean isRecipePerInput) { RecipeOutput[] outputArr = outputs.toArray(new RecipeOutput[outputs.size()]); RecipeInput[] inputArr = inputs.toArray(new RecipeInput[inputs.size()]); List<Recipe> result = new ArrayList<Recipe>(); if(isRecipePerInput) { for (RecipeInput input : inputs) { result.add(new Recipe(input, energyRequired, bonusType, outputArr)); } } else { for (RecipeOutput output : outputs) { result.add(new Recipe(output, energyRequired, bonusType, inputArr)); } } return result; } public boolean isValid() { return !invalidated && !inputs.isEmpty() && !outputs.isEmpty(); } public float getEnergyRequired() { return energyRequired; } public void setEnergyRequired(int energyRequired) { this.energyRequired = energyRequired; } public RecipeBonusType getBonusType() { return bonusType; } public void setBonusType(RecipeBonusType bonusType) { this.bonusType = bonusType; } public void setAllowMissing(boolean allowMissing) { this.allowMissing = allowMissing; } public boolean allowMissing() { return allowMissing; } public void invalidate() { invalidated = true; } @Override public String toString() { return "Recipe [" + (invalidated ? "INVALID " : "") + "input=" + inputs + ", outputs=" + outputs + ", energyRequired=" + energyRequired + ", bonusType=" + bonusType + "]"; } } }