Package forestry.factory.gadgets

Source Code of forestry.factory.gadgets.MachineBottler$RecipeManager

/*******************************************************************************
* Copyright (c) 2011-2014 SirSengir.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v3
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-3.0.txt
*
* Various Contributors including, but not limited to:
* SirSengir (original work), CovertJaguar, Player, Binnie, MysteriousAges
******************************************************************************/
package forestry.factory.gadgets;

import buildcraft.api.statements.ITriggerExternal;
import forestry.api.core.ForestryAPI;
import forestry.api.recipes.ICraftingProvider;
import forestry.core.EnumErrorCode;
import forestry.core.config.Config;
import forestry.core.config.Defaults;
import forestry.core.fluids.TankManager;
import forestry.core.fluids.tanks.StandardTank;
import forestry.core.gadgets.TileBase;
import forestry.core.gadgets.TilePowered;
import forestry.core.interfaces.ILiquidTankContainer;
import forestry.core.network.EntityNetData;
import forestry.core.network.GuiId;
import forestry.core.triggers.ForestryTrigger;
import forestry.core.utils.EnumTankLevel;
import forestry.core.utils.InventoryAdapter;
import forestry.core.utils.LiquidHelper;
import forestry.core.utils.StackUtils;
import forestry.core.utils.Utils;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.ICrafting;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidContainerRegistry;
import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTankInfo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Stack;

public class MachineBottler extends TilePowered implements ISidedInventory, ILiquidTankContainer {

  /* CONSTANTS */
  public static final short SLOT_RESOURCE = 0;
  public static final short SLOT_PRODUCT = 1;
  public static final short SLOT_CAN = 2;

  public static final short CYCLES_FILLING_DEFAULT = 5;

  /* RECIPE MANAGMENT */
  public static class Recipe {
    public final int cyclesPerUnit;
    public final FluidStack input;
    public final ItemStack can;
    public final ItemStack bottled;

    public Recipe(int cyclesPerUnit, FluidStack input, ItemStack can, ItemStack bottled) {
      this.cyclesPerUnit = cyclesPerUnit;
      this.input = input;
      this.can = can;
      this.bottled = bottled;
    }

    public boolean matches(FluidStack res, ItemStack empty) {
      return input.isFluidEqual(res) && res.amount >= input.amount && can.isItemEqual(empty);
    }

    public boolean hasInput(FluidStack res) {
      return input.isFluidEqual(res);
    }
  }

  public static class RecipeManager implements ICraftingProvider {
    public static ArrayList<MachineBottler.Recipe> recipes = new ArrayList<MachineBottler.Recipe>();

    /**
     *
     * @param res
     * @param empty
     * @return Recipe matching both res and empty, null if none
     */
    public static Recipe findMatchingRecipe(FluidStack res, ItemStack empty) {
      // We need both ingredients
      if (res == null || empty == null)
        return null;

      for (int i = 0; i < recipes.size(); i++) {
        Recipe recipe = recipes.get(i);
        if (recipe.matches(res, empty))
          return recipe;
      }

      // No recipe matched. See if the liquid dictionary has anything.
      if(FluidContainerRegistry.isEmptyContainer(empty)) {
        ItemStack filled = FluidContainerRegistry.fillFluidContainer(res, empty);
        if(filled != null) {
          FluidStack fluidStack = FluidContainerRegistry.getFluidForFilledItem(filled);
          Recipe recipe = new Recipe(CYCLES_FILLING_DEFAULT, fluidStack, empty, filled);
          recipes.add(recipe);
          return recipe;
        }
      }

      return null;
    }

    /**
     *
     * @param res
     * @return true if any recipe has a matching input
     */
    public static boolean isInput(FluidStack res) {
      if (res == null)
        return false;
      return FluidRegistry.isFluidRegistered(res.getFluid());
    }

    @Override
    public Map<Object[], Object[]> getRecipes() {
      HashMap<Object[], Object[]> recipeList = new HashMap<Object[], Object[]>();

      for (Recipe recipe : recipes)
        recipeList.put(new Object[] { recipe.input, recipe.can }, new Object[] { recipe.bottled });

      return recipeList;
    }
  }

  @EntityNetData
  public StandardTank resourceTank;
  private final TankManager tankManager;

  private final InventoryAdapter inventory = new InventoryAdapter(3, "Items");

  private boolean productPending = false;

  private Recipe currentRecipe;
  private final Stack<ItemStack> pendingProducts = new Stack<ItemStack>();
  private int fillingTime;
  private int fillingTotalTime;

  public MachineBottler() {
    super(1100, 50, 4000);
    setHints(Config.hints.get("bottler"));
    resourceTank = new StandardTank(Defaults.PROCESSOR_TANK_CAPACITY);
    tankManager = new TankManager(resourceTank);
  }

  @Override
  public String getInventoryName() {
    return getUnlocalizedName();
  }

  @Override
  public void openGui(EntityPlayer player, TileBase tile) {
    player.openGui(ForestryAPI.instance, GuiId.BottlerGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord);
  }

  /* SAVING & LOADING */
  @Override
  public void writeToNBT(NBTTagCompound nbttagcompound) {
    super.writeToNBT(nbttagcompound);

    nbttagcompound.setInteger("FillingTime", fillingTime);
    nbttagcompound.setInteger("FillingTotalTime", fillingTotalTime);
    nbttagcompound.setBoolean("ProductPending", productPending);

    tankManager.writeTanksToNBT(nbttagcompound);
    inventory.writeToNBT(nbttagcompound);

    NBTTagList nbttaglist = new NBTTagList();
    ItemStack[] offspring = pendingProducts.toArray(new ItemStack[pendingProducts.size()]);
    for (int i = 0; i < offspring.length; i++)
      if (offspring[i] != null) {
        NBTTagCompound nbttagcompound1 = new NBTTagCompound();
        nbttagcompound1.setByte("Slot", (byte) i);
        offspring[i].writeToNBT(nbttagcompound1);
        nbttaglist.appendTag(nbttagcompound1);
      }
    nbttagcompound.setTag("PendingProducts", nbttaglist);
  }

  @Override
  public void readFromNBT(NBTTagCompound nbttagcompound) {
    super.readFromNBT(nbttagcompound);

    fillingTime = nbttagcompound.getInteger("FillingTime");
    fillingTotalTime = nbttagcompound.getInteger("FillingTotalTime");
    productPending = nbttagcompound.getBoolean("ProductPending");

    tankManager.readTanksFromNBT(nbttagcompound);

    inventory.readFromNBT(nbttagcompound);

    NBTTagList nbttaglist = nbttagcompound.getTagList("PendingProducts", 10);
    for (int i = 0; i < nbttaglist.tagCount(); i++) {
      NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i);
      pendingProducts.add(ItemStack.loadItemStackFromNBT(nbttagcompound1));
    }

    checkRecipe();
  }

  @Override
  public void updateServerSide() {
    if (worldObj.getTotalWorldTime() % 20 * 10 != 0)
      return;

    // Check if we have suitable items waiting in the item slot
    if (inventory.getStackInSlot(SLOT_CAN) != null) {
      FluidContainerData container = LiquidHelper.getLiquidContainer(inventory.getStackInSlot(SLOT_CAN));
      if (container != null && RecipeManager.isInput(container.fluid)) {

        inventory.setInventorySlotContents(SLOT_CAN, StackUtils.replenishByContainer(this, inventory.getStackInSlot(SLOT_CAN), container, resourceTank));
        if (inventory.getStackInSlot(SLOT_CAN).stackSize <= 0)
          inventory.setInventorySlotContents(SLOT_CAN, null);
      }
    }

    checkRecipe();
    if (getErrorState() == EnumErrorCode.NORECIPE && currentRecipe != null)
      setErrorState(EnumErrorCode.OK);

    if (energyManager.getTotalEnergyStored() == 0) {
      setErrorState(EnumErrorCode.NOPOWER);
      return;
    }
  }

  @Override
  public boolean workCycle() {

    checkRecipe();

    // If we add pending products, we skip to the next work cycle.
    if (tryAddPending())
      return false;

    if (!pendingProducts.isEmpty())
      return false;

    // Continue work if nothing needs to be added
    if (fillingTime <= 0)
      return false;

    if (currentRecipe == null) {
      setErrorState(EnumErrorCode.NORECIPE);
      return false;
    }

    fillingTime--;
    // Still not done, return
    if (fillingTime > 0) {
      setErrorState(EnumErrorCode.OK);
      return true;
    }

    // We are done, add products to queue and remove resources
    pendingProducts.push(currentRecipe.bottled.copy());

    inventory.decrStackSize(SLOT_RESOURCE, 1);
    resourceTank.drain(currentRecipe.input.amount, true);
    checkRecipe();
    resetRecipe();

    while (tryAddPending())
      ;
    return true;
  }

  public void checkRecipe() {
    Recipe sameRec = RecipeManager.findMatchingRecipe(resourceTank.getFluid(), inventory.getStackInSlot(SLOT_RESOURCE));

    if (sameRec == null)
      setErrorState(EnumErrorCode.NORECIPE);

    if (currentRecipe != sameRec) {
      currentRecipe = sameRec;
      resetRecipe();
    }
  }

  private void resetRecipe() {
    if (currentRecipe == null) {
      fillingTime = 0;
      fillingTotalTime = 0;
      return;
    }

    fillingTime = currentRecipe.cyclesPerUnit;
    fillingTotalTime = currentRecipe.cyclesPerUnit;
  }

  private boolean tryAddPending() {
    if (pendingProducts.isEmpty())
      return false;

    ItemStack next = pendingProducts.peek();
    if (addProduct(next, true)) {
      pendingProducts.pop();
      return true;
    }

    setErrorState(EnumErrorCode.NOSPACE);
    return false;
  }

  private boolean addProduct(ItemStack product, boolean all) {
    return inventory.tryAddStack(product, SLOT_PRODUCT, 1, all);
  }

  // / STATE INFORMATION
  @Override
  public boolean isWorking() {
    return fillingTime > 0;
  }

  @Override
  public boolean hasResourcesMin(float percentage) {
    if (inventory.getStackInSlot(SLOT_RESOURCE) == null)
      return false;

    return ((float) inventory.getStackInSlot(SLOT_RESOURCE).stackSize / (float) inventory.getStackInSlot(SLOT_RESOURCE).getMaxStackSize()) > percentage;
  }

  @Override
  public boolean hasWork() {
    return currentRecipe != null;
  }

  public int getFillProgressScaled(int i) {
    if (fillingTotalTime == 0)
      return 0;

    return (fillingTime * i) / fillingTotalTime;

  }

  public int getResourceScaled(int i) {
    return (resourceTank.getFluidAmount() * i) / Defaults.PROCESSOR_TANK_CAPACITY;
  }

  @Override
  public EnumTankLevel getPrimaryLevel() {
    return Utils.rateTankLevel(getResourceScaled(100));
  }

  /* SMP GUI */
  public void getGUINetworkData(int i, int j) {
    i -= tankManager.maxMessageId() + 1;
    switch (i) {
    case 0:
      fillingTime = j;
      break;
    case 1:
      fillingTotalTime = j;
      break;
    }
  }

  public void sendGUINetworkData(Container container, ICrafting iCrafting) {
    int i = tankManager.maxMessageId() + 1;
    iCrafting.sendProgressBarUpdate(container, i, fillingTime);
    iCrafting.sendProgressBarUpdate(container, i + 1, fillingTotalTime);
  }

  /* IINVENTORY */
  @Override public int getSizeInventory() { return inventory.getSizeInventory(); }
  @Override public ItemStack getStackInSlot(int i) { return inventory.getStackInSlot(i); }
  @Override public ItemStack decrStackSize(int i, int j) { return inventory.decrStackSize(i, j); }
  @Override public void setInventorySlotContents(int i, ItemStack itemstack) { inventory.setInventorySlotContents(i, itemstack); }
  @Override public ItemStack getStackInSlotOnClosing(int slot) { return inventory.getStackInSlotOnClosing(slot); }
  @Override public int getInventoryStackLimit() { return inventory.getInventoryStackLimit(); }
  @Override public void openInventory() {}
  @Override public void closeInventory() {}

  /**
   * TODO: just a specialsource workaround
   */
  @Override
  public boolean isUseableByPlayer(EntityPlayer player) {
    return super.isUseableByPlayer(player);
  }

  /**
   * TODO: just a specialsource workaround
   */
  @Override
  public boolean hasCustomInventoryName() {
    return super.hasCustomInventoryName();
  }

  /**
   * TODO: just a specialsource workaround
   */
  @Override
  public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) {
    return super.isItemValidForSlot(slotIndex, itemstack);
  }

  /**
   * TODO: just a specialsource workaround
   */
  @Override
  public boolean canInsertItem(int i, ItemStack itemstack, int j) {
    return super.canInsertItem(i, itemstack, j);
  }

  /**
   * TODO: just a specialsource workaround
   */
  @Override
  public boolean canExtractItem(int i, ItemStack itemstack, int j) {
    return super.canExtractItem(i, itemstack, j);
  }

  /**
   * TODO: just a specialsource workaround
   */
  @Override
  public int[] getAccessibleSlotsFromSide(int side) {
    return super.getAccessibleSlotsFromSide(side);
  }

  /* ISIDEDINVENTORY */
  @Override
  public InventoryAdapter getInternalInventory() {
    return inventory;
  }

  @Override
  protected boolean canTakeStackFromSide(int slotIndex, ItemStack itemstack, int side) {

    if(!super.canTakeStackFromSide(slotIndex, itemstack, side))
      return false;

    return slotIndex == SLOT_PRODUCT;
  }

  @Override
  protected boolean canPutStackFromSide(int slotIndex, ItemStack itemstack, int side) {

    if(!super.canPutStackFromSide(slotIndex, itemstack, side))
      return false;

    if(slotIndex == SLOT_RESOURCE)
      return FluidContainerRegistry.isEmptyContainer(itemstack);

    if(slotIndex == SLOT_CAN) {
      FluidContainerData container = LiquidHelper.getLiquidContainer(itemstack);
      return container != null && RecipeManager.isInput(container.fluid);
    }

    return false;
  }

  /* ILIQUIDCONTAINER */
  @Override
  public TankManager getTankManager() {
    return tankManager;
  }

  @Override
  public int fill(ForgeDirection from, FluidStack resource, boolean doFill) {
    return tankManager.fill(from, resource, doFill);
  }

  public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) {
    return tankManager.drain(from, resource, doDrain);
  }

  @Override
  public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) {
    return tankManager.drain(from, maxDrain, doDrain);
  }

  @Override
  public boolean canFill(ForgeDirection from, Fluid fluid) {
    return tankManager.canFill(from, fluid);
  }

  @Override
  public boolean canDrain(ForgeDirection from, Fluid fluid) {
    return tankManager.canDrain(from, fluid);
  }

  @Override
  public FluidTankInfo[] getTankInfo(ForgeDirection from) {
    return tankManager.getTankInfo(from);
  }

  // ITRIGGERPROVIDER
  @Override
  public LinkedList<ITriggerExternal> getCustomTriggers() {
    LinkedList<ITriggerExternal> res = new LinkedList<ITriggerExternal>();
    res.add(ForestryTrigger.lowResource25);
    res.add(ForestryTrigger.lowResource10);
    return res;
  }

}
TOP

Related Classes of forestry.factory.gadgets.MachineBottler$RecipeManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.