Package forestry.factory.gadgets

Source Code of forestry.factory.gadgets.MachineFermenter

/*******************************************************************************
* 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.fuels.FuelManager;
import forestry.api.recipes.IFermenterManager;
import forestry.api.recipes.IVariableFermentable;
import forestry.core.EnumErrorCode;
import forestry.core.config.Config;
import forestry.core.config.Defaults;
import forestry.core.fluids.TankManager;
import forestry.core.fluids.tanks.FilteredTank;
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.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTankInfo;

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

public class MachineFermenter extends TilePowered implements ISidedInventory, ILiquidTankContainer {

  // / CONSTANTS
  public static final short SLOT_RESOURCE = 0;
  public static final short SLOT_FUEL = 1;
  public static final short SLOT_CAN_OUTPUT = 2;
  public static final short SLOT_CAN_INPUT = 3;
  public static final short SLOT_INPUT = 4;

  // / RECIPE MANAGMENT
  public static class Recipe {

    public final ItemStack resource;
    public final int fermentationValue;
    public final float modifier;
    public final FluidStack output;
    public final FluidStack liquid;

    public Recipe(ItemStack resource, int fermentationValue, float modifier, FluidStack output, FluidStack liquid) {
      this.resource = resource;
      this.fermentationValue = fermentationValue;
      this.modifier = modifier;
      this.output = output;
      this.liquid = liquid;

      if (resource == null)
        throw new NullPointerException("Fermenter Resource cannot be null!");

      if (output == null)
        throw new NullPointerException("Fermenter Output cannot be null!");

      if (liquid == null)
        throw new NullPointerException("Fermenter Liquid cannot be null!");
    }

    public boolean matches(ItemStack res, FluidStack liqu) {
      // No recipe without resource!
      if (res == null)
        return false;

      if (resource.getItem() != res.getItem())
        return false;
      if (resource.getItemDamage() != Defaults.WILDCARD && resource.getItemDamage() != res.getItemDamage())
        return false;

      // No liquid required
      if (liquid == null)
        return true;

      // Liquid required but none given
      if (liquid != null && liqu == null)
        return false;

      // Wrong liquid
      if (!liquid.isFluidEqual(liqu))
        return false;

      // Enough liquid
      if (liquid.amount <= liqu.amount)
        return true;

      return false;
    }
  }

  public static class RecipeManager implements IFermenterManager {

    public static ArrayList<MachineFermenter.Recipe> recipes = new ArrayList<MachineFermenter.Recipe>();
    public static HashSet<Fluid> recipeFluidInputs = new HashSet<Fluid>();
    public static HashSet<Fluid> recipeFluidOutputs = new HashSet<Fluid>();

    @Override
    public void addRecipe(ItemStack resource, int fermentationValue, float modifier, FluidStack output, FluidStack liquid) {
      recipes.add(new Recipe(resource, fermentationValue, modifier, output, liquid));
      if (liquid != null)
        recipeFluidInputs.add(liquid.getFluid());
      if (output != null)
        recipeFluidOutputs.add(output.getFluid());
    }

    @Override
    public void addRecipe(ItemStack resource, int fermentationValue, float modifier, FluidStack output) {
      addRecipe(resource, fermentationValue, modifier, output, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000));
    }

    public static Recipe findMatchingRecipe(ItemStack res, FluidStack liqu) {
      for (int i = 0; i < recipes.size(); i++) {
        Recipe recipe = recipes.get(i);
        if (recipe.matches(res, liqu))
          return recipe;
      }
      return null;
    }

    public static boolean isResource(ItemStack resource) {
      for (int i = 0; i < recipes.size(); i++) {
        Recipe recipe = recipes.get(i);
        if (recipe.resource.getItemDamage() == Defaults.WILDCARD
            && recipe.resource.getItem() == resource.getItem()) {
          return true;
        } else if (recipe.resource.isItemEqual(resource)) {
          return true;
        }
      }
      return false;
    }

    public static boolean isLiquidResource(FluidStack liquid) {
      return recipeFluidInputs.contains(liquid.getFluid());
    }

    public static boolean isLiquidProduct(FluidStack liquid) {
      return recipeFluidOutputs.contains(liquid.getFluid());
    }

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

      for (Recipe recipe : recipes) {
        recipeList.put(new Object[] { recipe.resource, recipe.liquid }, new Object[] { recipe.output });
      }

      return recipeList;
    }
  }
  @EntityNetData
  public FilteredTank resourceTank;
  @EntityNetData
  public FilteredTank productTank;

  private final TankManager tankManager;

  private final InventoryAdapter inventory = new InventoryAdapter(5, "Items");
  private Recipe currentRecipe;
  private float currentResourceModifier;
  public int fermentationTime = 0;
  public int fermentationTotalTime = 0;
  public int fuelBurnTime = 0;
  public int fuelTotalTime = 0;
  public int fuelCurrentFerment = 0;

  public MachineFermenter() {
    super(2000, 150, 8000);
    setHints(Config.hints.get("fermenter"));
    resourceTank = new FilteredTank(Defaults.PROCESSOR_TANK_CAPACITY, RecipeManager.recipeFluidInputs);
    resourceTank.tankMode = StandardTank.TankMode.INPUT;
    productTank = new FilteredTank(Defaults.PROCESSOR_TANK_CAPACITY, RecipeManager.recipeFluidOutputs);
    productTank.tankMode = StandardTank.TankMode.OUTPUT;
    tankManager = new TankManager(resourceTank, productTank);
  }

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

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

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

    nbttagcompound.setInteger("FermentationTime", fermentationTime);
    nbttagcompound.setInteger("FermentationTotalTime", fermentationTotalTime);
    nbttagcompound.setInteger("FuelBurnTime", fuelBurnTime);
    nbttagcompound.setInteger("FuelTotalTime", fuelTotalTime);
    nbttagcompound.setInteger("FuelCurrentFerment", fuelCurrentFerment);

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

  }

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

    fermentationTime = nbttagcompound.getInteger("FermentationTime");
    fermentationTotalTime = nbttagcompound.getInteger("FermentationTotalTime");
    fuelBurnTime = nbttagcompound.getInteger("FuelBurnTime");
    fuelTotalTime = nbttagcompound.getInteger("FuelTotalTime");
    fuelCurrentFerment = nbttagcompound.getInteger("FuelCurrentFerment");

    tankManager.readTanksFromNBT(nbttagcompound);
    inventory.readFromNBT(nbttagcompound);
  }

  @Override
  public void updateServerSide() {

    // Check if we have suitable items waiting in the item slot
    if (inventory.getStackInSlot(SLOT_INPUT) != null) {

      FluidContainerData container = LiquidHelper.getLiquidContainer(inventory.getStackInSlot(SLOT_INPUT));
      if (container != null && RecipeManager.isLiquidResource(container.fluid)) {

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

      }
    }
    // Can/capsule input/output needs to be handled here.
    if (inventory.getStackInSlot(SLOT_CAN_INPUT) != null) {
      FluidContainerData container = LiquidHelper.getEmptyContainer(inventory.getStackInSlot(SLOT_CAN_INPUT), productTank.getFluid());

      if (container != null) {
        inventory.setInventorySlotContents(SLOT_CAN_OUTPUT, bottleIntoContainer(inventory.getStackInSlot(SLOT_CAN_INPUT), inventory.getStackInSlot(SLOT_CAN_OUTPUT), container,
            productTank));
        if (inventory.getStackInSlot(SLOT_CAN_INPUT).stackSize <= 0)
          inventory.setInventorySlotContents(SLOT_CAN_INPUT, null);
      }
    }

    if (worldObj.getTotalWorldTime() % 20 * 10 != 0)
      return;


    if (RecipeManager.findMatchingRecipe(inventory.getStackInSlot(SLOT_RESOURCE), resourceTank.getFluid()) != null) {
      if (resourceTank.getFluidAmount() < fuelCurrentFerment)
        setErrorState(EnumErrorCode.NORESOURCE);
      else
        setErrorState(EnumErrorCode.OK);
    } else if (inventory.getStackInSlot(SLOT_FUEL) == null && fuelBurnTime <= 0)
      setErrorState(EnumErrorCode.NOFUEL);
    else if (energyManager.getTotalEnergyStored() == 0)
      setErrorState(EnumErrorCode.NOPOWER);
    else
      setErrorState(EnumErrorCode.NORECIPE);
  }

  @Override
  public boolean workCycle() {

    if (currentRecipe == null) {
      checkRecipe();
      resetRecipe();

      if (currentRecipe != null) {
        currentResourceModifier = determineResourceMod(inventory.getStackInSlot(SLOT_RESOURCE));
        decrStackSize(SLOT_RESOURCE, 1);
        return true;
      } else
        return false;

      // If we have burnTime left, just decrease it.
    } else if (fuelBurnTime > 0) {
      if (resourceTank.getFluidAmount() < fuelCurrentFerment)
        return false;

      // Nothing to do, return
      if (fermentationTime <= 0)
        return false;

      int fermented = Math.min(fermentationTime, this.fuelCurrentFerment);

      // input are checked, add output if possible
      if (!addProduct(new FluidStack(currentRecipe.output,
          Math.round(fermented * currentRecipe.modifier * currentResourceModifier)))) {
        return false; // the output tank is too full, TODO: check/add error code?
      }

      fuelBurnTime--;
      resourceTank.drain(fuelCurrentFerment, true);
      fermentationTime -= this.fuelCurrentFerment;

      // Not done yet
      if (fermentationTime > 0)
        return true;

      currentRecipe = null;
      return true;

    } else { // out of fuel

      // Use only fuel that provides value
      fuelBurnTime = fuelTotalTime = determineFuelValue(getFuelStack());
      if (fuelBurnTime > 0) {
        this.fuelCurrentFerment = determineFermentPerCycle(getFuelStack());
        decrStackSize(1, 1);
        return true;
      } else {
        this.fuelCurrentFerment = 0;
        return false;
      }
    }
  }

  private boolean addProduct(FluidStack output) {
    int amount = productTank.fill(output, false);

    if (amount == output.amount) {
      productTank.fill(output, true);

      return true;
    } else {
      return false;
    }
  }

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

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

  private void resetRecipe() {
    if (currentRecipe == null) {
      fermentationTime = 0;
      fermentationTotalTime = 0;
      return;
    }

    fermentationTime = currentRecipe.fermentationValue;
    fermentationTotalTime = currentRecipe.fermentationValue;
  }

  /**
   * Returns the burnTime an item of the passed ItemStack provides
   *
   * @param item
   * @return
   */
  private int determineFuelValue(ItemStack item) {
    if (item == null)
      return 0;

    if (FuelManager.fermenterFuel.containsKey(item))
      return FuelManager.fermenterFuel.get(item).burnDuration;
    else
      return 0;
  }

  private int determineFermentPerCycle(ItemStack item) {
    if (item == null)
      return 0;

    if (FuelManager.fermenterFuel.containsKey(item))
      return FuelManager.fermenterFuel.get(item).fermentPerCycle;
    else
      return 0;
  }

  private float determineResourceMod(ItemStack itemstack) {
    if (!(itemstack.getItem() instanceof IVariableFermentable))
      return 1.0f;

    return ((IVariableFermentable) itemstack.getItem()).getFermentationModifier(itemstack);
  }

  @Override
  public boolean isWorking() {
    if (currentRecipe == null
        && RecipeManager.findMatchingRecipe(inventory.getStackInSlot(SLOT_RESOURCE), resourceTank.getFluid()) == null)
      return false;
    if (fuelBurnTime > 0)
      return resourceTank.getFluidAmount() > 0 && productTank.getFluidAmount() < Defaults.PROCESSOR_TANK_CAPACITY;
      else
        return determineFuelValue(getFuelStack()) > 0;
  }

  @Override
  public boolean hasResourcesMin(float percentage) {
    if (this.getFermentationStack() == null)
      return false;

    return ((float) getFermentationStack().stackSize / (float) getFermentationStack().getMaxStackSize()) > percentage;
  }

  @Override
  public boolean hasFuelMin(float percentage) {
    if (this.getFuelStack() == null)
      return false;

    return ((float) getFuelStack().stackSize / (float) getFuelStack().getMaxStackSize()) > percentage;
  }

  @Override
  public boolean hasWork() {
    if (this.getFuelStack() == null && fuelBurnTime <= 0)
      return false;
    else if (fuelBurnTime <= 0)
      if (RecipeManager.findMatchingRecipe(inventory.getStackInSlot(SLOT_RESOURCE), resourceTank.getFluid()) == null)
        return false;

    if (this.getFermentationStack() == null && fermentationTime <= 0)
      return false;
    else if (fermentationTime <= 0)
      if (RecipeManager.findMatchingRecipe(inventory.getStackInSlot(SLOT_RESOURCE), resourceTank.getFluid()) == null)
        return false;

    if (resourceTank.getFluidAmount() <= fuelCurrentFerment)
      return false;

    if (productTank.getFluidAmount() >= productTank.getCapacity())
      return false;

    return true;
  }

  public int getBurnTimeRemainingScaled(int i) {
    if (fuelTotalTime == 0)
      return 0;

    return (fuelBurnTime * i) / fuelTotalTime;
  }

  public int getFermentationProgressScaled(int i) {
    if (fermentationTotalTime == 0)
      return 0;

    return (fermentationTime * i) / fermentationTotalTime;
  }

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

  public int getProductScaled(int i) {
    return (productTank.getFluidAmount() * i) / Defaults.PROCESSOR_TANK_CAPACITY;
  }

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

  @Override
  public EnumTankLevel getSecondaryLevel() {
    return Utils.rateTankLevel(getProductScaled(100));
  }

  public ItemStack getFermentationStack() {
    return inventory.getStackInSlot(SLOT_RESOURCE);
  }

  public ItemStack getFuelStack() {
    return inventory.getStackInSlot(SLOT_FUEL);
  }

  /* SMP GUI */
  public void getGUINetworkData(int i, int j) {
    int firstMessageId = tankManager.maxMessageId() + 1;

    if (i == firstMessageId)
      fuelBurnTime = j;
    else if (i == firstMessageId + 1)
      fuelTotalTime = j;
    else if (i == firstMessageId + 2)
      fermentationTime = j;
    else  if (i == firstMessageId + 3)
      fermentationTotalTime = j;
  }

  public void sendGUINetworkData(Container container, ICrafting iCrafting) {
    int firstMessageId = tankManager.maxMessageId() + 1;

    iCrafting.sendProgressBarUpdate(container, firstMessageId, fuelBurnTime);
    iCrafting.sendProgressBarUpdate(container, firstMessageId + 1, fuelTotalTime);
    iCrafting.sendProgressBarUpdate(container, firstMessageId + 2, fermentationTime);
    iCrafting.sendProgressBarUpdate(container, firstMessageId + 3, fermentationTotalTime);
  }

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

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

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

    if (slotIndex == SLOT_CAN_OUTPUT)
      return true;

    return false;
  }

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

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

    if (slotIndex == SLOT_RESOURCE && RecipeManager.isResource(itemstack))
      return true;


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

    if (slotIndex == SLOT_CAN_INPUT && LiquidHelper.isEmptyContainer(itemstack)) {
      return true;
    }
    if (slotIndex == SLOT_FUEL && FuelManager.fermenterFuel.containsKey(itemstack))
      return true;

    return false;
  }

  @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);
  }

  /* ILiquidTankContainer */
  @Override
  public int fill(ForgeDirection from, FluidStack resource, boolean doFill) {
    return resourceTank.fill(resource, doFill);
  }

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

  @Override
  public FluidStack drain(ForgeDirection from, int quantityMax, boolean doEmpty) {
    return productTank.drain(quantityMax, doEmpty);
  }

  @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 TankManager getTankManager() {
    return tankManager;
  }

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

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

Related Classes of forestry.factory.gadgets.MachineFermenter

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.