package resonantinduction.mechanical.fluid; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import net.minecraft.block.Block; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; import resonantinduction.mechanical.fluid.network.IFluidRecipeCrafter; import resonantinduction.mechanical.fluid.network.FluidRecipeInfo.SimpleFluidRecipe; import calclavia.lib.utility.FluidHelper; import com.builtbroken.common.Pair; import com.builtbroken.common.Triple; /** * Handles all kinds of process involving mixing Fluids with other fluids and/or Items, Blocks, * ItemStack, or Liquids * * @author DarkGuardsman */ public class FluidCraftingHandler { /** Map of results of two different liquids merging */ public static HashMap, Object> fluidMergeResults = new HashMap, Object>(); static { registerRecipe(FluidRegistry.LAVA, FluidRegistry.WATER, Block.obsidian); registerRecipe(FluidRegistry.WATER, FluidRegistry.LAVA, Block.cobblestone); } /** * Creates a very basic A + B = C result for mixing two objects together. Suggest that the use * of a SimpleFluidRecipe i used instead to create a more refined fluid mixing that takes into * account ratios, and fluid volumes */ public static void registerRecipe(Object a, Object b, Object c) { if (a != null && b != null && c != null) { registerFluidRecipe(new SimpleFluidRecipe(a, b, c)); } } public static void registerFluidRecipe(SimpleFluidRecipe recipe) { if (recipe != null && recipe.recipeObjectA != null && recipe.recipeObjectB != null && recipe.recipeObjectC != null) { if (!fluidMergeResults.containsKey(new Pair(recipe.recipeObjectA, recipe.recipeObjectB))) { fluidMergeResults.put(new Pair(recipe.recipeObjectA, recipe.recipeObjectB), recipe); } if (recipe.canBeReversed) { if (!fluidMergeResults.containsKey(new Pair(recipe.recipeObjectB, recipe.recipeObjectA))) { fluidMergeResults.put(new Pair(recipe.recipeObjectB, recipe.recipeObjectA), recipe); } } } } public static void loadPotionRecipes() { // TODO load the process by which a potion would be created threw fliud crafting } /** * Does the fluid recipe crafting for the crafter object. Requires that the object fully use all * methods from the #IFluidRecipeCrafter * * @param crafter - crafting object, recommend it be a tile but can be anything as long as the * method are used correctly. In some recipe cases when the setRecipeObjectContent nothing will * be used. If result is null assume not crafting was performed. If there is a result the * crafter couldn't use the output to reduce the input values. From here the IFluidRecipeCrafter * will need to process the output and decress the input values correctly */ public static void craft(IFluidRecipeCrafter crafter) { Object received = crafter.getReceivingObjectStack(); int receivedVolume = 0; Object input = crafter.getInputObjectStack(); int inputVolume = 0; if (crafter != null && received != null && input != null) { // Trip input values so they will match the correct mapped values if (received instanceof FluidStack) { receivedVolume = ((FluidStack) received).amount; received = FluidHelper.getStack((FluidStack) received, 1); } if (received instanceof ItemStack) { receivedVolume = ((ItemStack) received).stackSize; ((ItemStack) received).stackSize = 1; } if (input instanceof FluidStack) { inputVolume = ((FluidStack) input).amount; input = FluidHelper.getStack((FluidStack) input, 1); } if (input instanceof ItemStack) { receivedVolume = ((ItemStack) input).stackSize; ((ItemStack) input).stackSize = 1; } // Get result Object result = fluidMergeResults.containsKey(new Pair(crafter.getReceivingObjectStack(), crafter.getInputObjectStack())); // reset stack sized if (received instanceof FluidStack) { ((FluidStack) received).amount = receivedVolume; } if (received instanceof ItemStack) { ((ItemStack) received).stackSize = receivedVolume; } if (input instanceof FluidStack) { ((FluidStack) input).amount = inputVolume; } if (input instanceof ItemStack) { ((ItemStack) input).stackSize = inputVolume; } if (result != null) { if (result instanceof SimpleFluidRecipe) { Triple> re = ((SimpleFluidRecipe) result).mix(crafter.getInputObjectStack(), crafter.getInputObjectStack()); crafter.setRecipeObjectContent(received, re.getA(), input, re.getB(), re.getC().left(), re.getC().right()); } } crafter.setRecipeObjectContent(received, 0, input, 0, result, 0); } } /** Merges two fluids together that don't result in damage to the network */ public static FluidStack mergeFluidStacks(FluidStack stackOne, FluidStack stackTwo) { FluidStack resultStack = null; if (stackTwo != null && stackOne != null && stackOne.isFluidEqual(stackTwo)) { resultStack = stackOne.copy(); resultStack.amount += stackTwo.amount; } else if (stackOne == null && stackTwo != null) { resultStack = stackTwo.copy(); } else if (stackOne != null && stackTwo == null) { resultStack = stackOne.copy(); } else if (stackTwo != null && stackOne != null && !stackOne.isFluidEqual(stackTwo)) { System.out.println("preforming fluid merge event"); Object result = fluidMergeResults.get(new Pair(stackOne.getFluid(), stackTwo.getFluid())); /* Try to merge fluids by mod defined rules first */ if (result != null) { System.out.println("result = " + result.toString()); if (result instanceof Fluid) { resultStack = new FluidStack(((Fluid) result).getID(), stackOne.amount + stackTwo.amount); } else if (result instanceof FluidStack) { resultStack = ((FluidStack) result).copy(); resultStack.amount = stackOne.amount + stackTwo.amount; } else if (result instanceof String && ((String) result).startsWith("Liquid:")) { resultStack = new FluidStack(FluidRegistry.getFluid(((String) result).replace("Liquid:", "")), stackOne.amount + stackTwo.amount); } else if (result instanceof SimpleFluidRecipe) { Triple> re = ((SimpleFluidRecipe) result).mix(stackOne, stackTwo); if (re.getC().left() instanceof FluidStack) { resultStack = FluidHelper.getStack((FluidStack) re.getC().left(), re.getC().right()); } else if (re.getC().left() instanceof FluidStack) { resultStack = new FluidStack((Fluid) re.getC().left(), re.getC().right()); } } } if (resultStack == null) { System.out.println("Merging fluids into a waste fluid stack"); Fluid waste = FluidRegistry.getFluid("waste"); if (waste == null) { System.out.println("[FluidNetworkHelper] Attempted to merge two fluids into a waste fluid stack but Forge fluid registry return null for waste. Possible that waste fluid was disabled or not registered correctly."); return null; } /* If both liquids are waste then copy fluidStack lists then merge */ if (stackTwo.fluidID == waste.getID() && stackOne.fluidID == waste.getID()) { List stacks = new ArrayList(); stacks.addAll(getStacksFromWaste(stackOne.copy())); stacks.addAll(getStacksFromWaste(stackTwo.copy())); resultStack = createNewWasteStack(stacks.toArray(new FluidStack[stacks.size()])); } else { resultStack = createNewWasteStack(stackOne.copy(), stackTwo.copy()); } } } return resultStack; } /** Gets the fluidStacks that make up a waste FluidStack */ public static List getStacksFromWaste(FluidStack wasteStack) { List stacks = new ArrayList(); if (wasteStack.fluidID == FluidRegistry.getFluidID("waste")) { for (int i = 1; i <= wasteStack.tag.getInteger("liquids"); i++) { FluidStack readStack = FluidStack.loadFluidStackFromNBT(wasteStack.tag.getCompoundTag("Liquid" + i)); if (readStack != null) { stacks.add(readStack); } } } return stacks; } /** Creates a new waste stack from the listed fluidStacks */ public static FluidStack createNewWasteStack(FluidStack... liquids) { FluidStack stack = new FluidStack(FluidRegistry.getFluid("waste"), 0); stack.tag = new NBTTagCompound(); if (liquids != null) { int count = 0; for (int i = 0; i < liquids.length; i++) { if (liquids[i] != null) { if (!liquids[i].getFluid().equals(stack.getFluid())) { count++; stack.tag.setCompoundTag("Liquids" + count, liquids[i].writeToNBT(new NBTTagCompound())); stack.amount += liquids[i].amount; } else { for (FluidStack loadStack : getStacksFromWaste(liquids[i])) { count++; stack.tag.setCompoundTag("Liquids" + count, loadStack.writeToNBT(new NBTTagCompound())); stack.amount += loadStack.amount; } } } } stack.tag.setInteger("liquids", count); } return stack; } /** * Gets the result of the merge of the two fluids, order of merge does matter and will produce * different results. * * @param stackOne - Receiving fluid, eg the one that is not moving * @param stackTwo - Flowing fluid, eg the one moving into the first fluid * @return Object result of the merge, can be anything from string, ItemStack, Item, Block, or * enum action */ public static Object getMergeResult(FluidStack stackOne, FluidStack stackTwo) { FluidStack sampleStackOne, sampleStackTwo; if (stackOne != null && stackTwo != null && !stackOne.equals(stackTwo)) { sampleStackOne = FluidHelper.getStack(stackOne, 1); sampleStackTwo = FluidHelper.getStack(stackTwo, 1); if (fluidMergeResults.containsKey(new Pair(sampleStackOne, sampleStackTwo))) { return fluidMergeResults.get(new Pair(sampleStackOne, sampleStackTwo)); } } return null; } }