Package forestry.factory.gadgets

Source Code of forestry.factory.gadgets.MachineCarpenter

/*******************************************************************************
* 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 forestry.api.core.ForestryAPI;
import forestry.api.recipes.ICarpenterManager;
import forestry.core.EnumErrorCode;
import forestry.core.config.Config;
import forestry.core.config.Defaults;
import forestry.core.config.ForestryItem;
import forestry.core.fluids.TankManager;
import forestry.core.fluids.tanks.FilteredTank;
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.proxy.Proxies;
import forestry.core.utils.EnumTankLevel;
import forestry.core.utils.InventoryAdapter;
import forestry.core.utils.LiquidHelper;
import forestry.core.utils.ShapedRecipeCustom;
import forestry.core.utils.StackUtils;
import forestry.core.utils.TileInventoryAdapter;
import forestry.core.utils.Utils;
import forestry.factory.gui.ContainerCarpenter;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.ICrafting;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
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.FluidStack;
import net.minecraftforge.fluids.FluidTankInfo;

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

public class MachineCarpenter extends TilePowered implements ISidedInventory, ILiquidTankContainer {

  /* CONSTANTS */
  public final static int SLOT_CRAFTING_1 = 0;
  public final static int SLOT_BOX = 9;
  public final static int SLOT_PRODUCT = 10;
  public final static int SLOT_CAN_INPUT = 11;
  public final static short SLOT_INVENTORY_1 = 12;
  public final static short SLOT_INVENTORY_COUNT = 18;

  /* RECIPE MANAGMENT */
  public static class Recipe {

    private final int packagingTime;
    private final FluidStack liquid;
    private final ItemStack box;
    private final ShapedRecipeCustom internal;

    public Recipe(int packagingTime, FluidStack liquid, ItemStack box, ShapedRecipeCustom internal) {
      this.packagingTime = packagingTime;
      this.liquid = liquid;
      this.box = box;
      this.internal = internal;
    }

    public ItemStack getCraftingResult() {
      return internal.getRecipeOutput();
    }

    public boolean matches(FluidStack resource, ItemStack item, InventoryCrafting inventorycrafting, World world) {

      // Check liquid
      if (liquid != null && resource == null)
        return false;
      if (liquid != null && !liquid.isFluidEqual(resource))
        return false;

      // Check box
      if (box != null && item == null)
        return false;
      if (box != null && !box.isItemEqual(item))
        return false;

      return internal.matches(inventorycrafting, world);
    }

    public boolean hasLiquid(FluidStack resource) {
      if (liquid != null && resource != null)
        return liquid.isFluidEqual(resource);
      else
        return false;
    }

    public boolean hasBox(ItemStack resource) {
      if (box == null && resource == null)
        return true;
      else if (box == null)
        return true;

      if (box.getItemDamage() > 0)
        return box.isItemEqual(resource);
      else
        return box.getItem() == resource.getItem();
    }

    public boolean isIngredient(ItemStack resource) {
      return internal.isIngredient(resource);
    }

    public ItemStack getBox() {
      return box;
    }

    public FluidStack getLiquid() {
      return liquid;
    }

    public IRecipe asIRecipe() {
      return internal;
    }
  }

  public static class RecipeManager implements ICarpenterManager {

    public static ArrayList<MachineCarpenter.Recipe> recipes = new ArrayList<MachineCarpenter.Recipe>();
    public static HashSet<Fluid> recipeFluids = new HashSet<Fluid>();

    @Override
    public void addCrating(ItemStack itemStack) {
      ItemStack uncrated = ((forestry.core.items.ItemCrated) itemStack.getItem()).getContained(itemStack);
      addRecipe(Defaults.CARPENTER_CRATING_CYCLES, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, Defaults.CARPENTER_CRATING_LIQUID_QUANTITY),
          ForestryItem.crate.getItemStack(), itemStack, new Object[] { "###", "###", "###", '#', uncrated });
      addRecipe(null, new ItemStack(uncrated.getItem(), 9, uncrated.getItemDamage()), new Object[] { "#", Character.valueOf('#'), itemStack });
    }

    @Override
    public void addCrating(String toCrate, ItemStack unpack, ItemStack crated) {
      addRecipe(Defaults.CARPENTER_CRATING_CYCLES, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, Defaults.CARPENTER_CRATING_LIQUID_QUANTITY),
          ForestryItem.crate.getItemStack(), crated, new Object[] { "###", "###", "###", '#', toCrate });
      addRecipe(null, new ItemStack(unpack.getItem(), 9, unpack.getItemDamage()), new Object[] { "#", '#', crated });
    }

    @Override
    public void addRecipe(ItemStack box, ItemStack product, Object materials[]) {
      addRecipe(5, null, box, product, materials);
    }

    @Override
    public void addRecipe(int packagingTime, ItemStack box, ItemStack product, Object materials[]) {
      addRecipe(packagingTime, null, box, product, materials);
    }

    @Override
    public void addRecipe(int packagingTime, FluidStack liquid, ItemStack box, ItemStack product, Object materials[]) {
      recipes.add(new Recipe(packagingTime, liquid, box, ShapedRecipeCustom.createShapedRecipe(product, materials)));
      if (liquid != null)
        recipeFluids.add(liquid.getFluid());
    }

    public static Recipe findMatchingRecipe(FluidStack liquid, ItemStack item, InventoryCrafting inventorycrafting, World world) {
      for (int i = 0; i < recipes.size(); i++) {
        Recipe recipe = recipes.get(i);
        if (recipe.matches(liquid, item, inventorycrafting, world))
          return recipe;
      }
      return null;
    }

    public static boolean isResourceLiquid(FluidStack liquid) {
      return recipeFluids.contains(liquid.getFluid());
    }

    public static boolean isBox(ItemStack resource) {
      for (Recipe recipe : recipes) {
        if (StackUtils.isIdenticalItem(recipe.getBox(), resource))
          return true;
      }

      return false;
    }

    @Override
    public Map<Object[], Object[]> getRecipes() {

      HashMap<Object[], Object[]> recipeList = new HashMap<Object[], Object[]>();

      for (Recipe recipe : recipes) {
        recipeList.put(recipe.internal.getIngredients(), new Object[] { recipe.getCraftingResult() });
      }

      return recipeList;
    }
  }

  /* MEMBER */
  @EntityNetData
  public FilteredTank resourceTank;
  private final TankManager tankManager;
  private final TileInventoryAdapter craftingInventory;
  private final TileInventoryAdapter accessibleInventory;
  public MachineCarpenter.Recipe currentRecipe;
  public MachineCarpenter.Recipe lastRecipe;
  public ContainerCarpenter activeContainer;
  private int packageTime;
  private int totalTime;
  private ItemStack currentProduct;
  private ItemStack pendingProduct;

  public ItemStack getBoxStack() {
    return accessibleInventory.getStackInSlot(SLOT_BOX);
  }

  public MachineCarpenter() {
    super(1100, 50, 4000);
    setHints(Config.hints.get("carpenter"));
    resourceTank = new FilteredTank(Defaults.PROCESSOR_TANK_CAPACITY, RecipeManager.recipeFluids);
    craftingInventory = new TileInventoryAdapter(this, 10, "CraftItems");
    accessibleInventory = (TileInventoryAdapter) new TileInventoryAdapter(this, 30, "Items").configureSided(Defaults.FACINGS, SLOT_BOX, 20);

    tankManager = new TankManager(resourceTank);
  }

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

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

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

    nbttagcompound.setInteger("PackageTime", packageTime);
    nbttagcompound.setInteger("PackageTotalTime", totalTime);

    tankManager.writeTanksToNBT(nbttagcompound);

    craftingInventory.writeToNBT(nbttagcompound);
    accessibleInventory.writeToNBT(nbttagcompound);

    // Write pending product
    if (pendingProduct != null) {
      NBTTagCompound nbttagcompoundP = new NBTTagCompound();
      pendingProduct.writeToNBT(nbttagcompoundP);
      nbttagcompound.setTag("PendingProduct", nbttagcompoundP);
    }
    // Write current product
    if (currentProduct != null) {
      NBTTagCompound nbttagcompoundC = new NBTTagCompound();
      currentProduct.writeToNBT(nbttagcompoundC);
      nbttagcompound.setTag("CurrentProduct", nbttagcompoundC);
    }
  }

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

    packageTime = nbttagcompound.getInteger("PackageTime");
    totalTime = nbttagcompound.getInteger("PackageTotalTime");

    tankManager.readTanksFromNBT(nbttagcompound);

    if (nbttagcompound.hasKey("CraftItems"))
      craftingInventory.readFromNBT(nbttagcompound);
    else {
      // FIXME: Legacy conversion for carpenters <= 2.2.2.2
      NBTTagList nbttaglist = nbttagcompound.getTagList("Items", 10);

      for (int j = 0; j < nbttaglist.tagCount(); ++j) {
        NBTTagCompound nbttagcompound2 = nbttaglist.getCompoundTagAt(j);
        int index = nbttagcompound2.getByte("Slot");
        if (index < 9)
          craftingInventory.setInventorySlotContents(index, ItemStack.loadItemStackFromNBT(nbttagcompound2));
      }

    }
    accessibleInventory.readFromNBT(nbttagcompound);

    // Load pending product
    if (nbttagcompound.hasKey("PendingProduct")) {
      NBTTagCompound nbttagcompoundP = nbttagcompound.getCompoundTag("PendingProduct");
      pendingProduct = ItemStack.loadItemStackFromNBT(nbttagcompoundP);
    }
    // Load current product
    if (nbttagcompound.hasKey("CurrentProduct")) {
      NBTTagCompound nbttagcompoundP = nbttagcompound.getCompoundTag("CurrentProduct");
      currentProduct = ItemStack.loadItemStackFromNBT(nbttagcompoundP);
    }

    // Reset recipe according to contents
    ContainerCarpenter container = new ContainerCarpenter(this);
    setCurrentRecipe(RecipeManager.findMatchingRecipe(resourceTank.getFluid(), getBoxStack(), container.craftMatrix, worldObj));
  }

  public void setCurrentRecipe(MachineCarpenter.Recipe currentRecipe) {
    this.currentRecipe = currentRecipe;
    if(currentRecipe != null)
      lastRecipe = currentRecipe;
  }

  @Override
  public void updateServerSide() {

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

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

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

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

    if (currentRecipe == null) {
      ContainerCarpenter container = new ContainerCarpenter(this);
      setCurrentRecipe(MachineCarpenter.RecipeManager.findMatchingRecipe(resourceTank.getFluid(), getBoxStack(), container.craftMatrix, worldObj));
    }

    if (currentRecipe == null)
      setErrorState(EnumErrorCode.NORECIPE);
    else if (!validateResources())
      setErrorState(EnumErrorCode.NORESOURCE);
    else if (energyManager.getTotalEnergyStored() == 0)
      setErrorState(EnumErrorCode.NOPOWER);
    else
      setErrorState(EnumErrorCode.OK);

  }

  @Override
  public boolean workCycle() {

    if (packageTime > 0) {
      packageTime--;

      // Check whether we have become invalid and need to abort production
      if (currentRecipe == null || !currentProduct.isItemEqual(currentRecipe.getCraftingResult()) || !validateResources()) {
        currentProduct = null;
        packageTime = totalTime = 0;
        return false;
      }

      if (packageTime <= 0) {

        pendingProduct = currentProduct;
        currentProduct = null;
        totalTime = 0;

        // Remove resources
        if (!removeResources(currentRecipe))
          return false;

        // Update product display
        if (activeContainer != null)
          activeContainer.updateProductDisplay();

        return tryAddPending();
      }
      return true;
    } else if (pendingProduct != null)
      return tryAddPending();
    else {

      if (currentRecipe != null) {

        if (!validateResources())
          return false;

        // Enough items available, start the process
        packageTime = totalTime = currentRecipe.packagingTime;
        currentProduct = currentRecipe.getCraftingResult();

        // Update product display
        if (activeContainer != null)
          activeContainer.updateProductDisplay();

        return true;
      }

      return false;
    }
  }

  private boolean validateResources() {
    // Check whether liquid is needed and if there is enough available
    if (currentRecipe.liquid != null)
      if (resourceTank.getFluidAmount() < currentRecipe.liquid.amount)
        return false;

    // Check whether boxes are available
    if (currentRecipe.box != null)
      if (accessibleInventory.getStackInSlot(SLOT_BOX) == null)
        return false;

    // Need at least one matched set
    ItemStack[] set = craftingInventory.getStacks(SLOT_CRAFTING_1, 9);
    ItemStack[] stock = accessibleInventory.getStacks(SLOT_INVENTORY_1, SLOT_INVENTORY_COUNT);
    return StackUtils.containsSets(set, stock, true, false) > 0;
  }

  private boolean removeResources(Recipe recipe) {

    // Remove resources
    if (recipe.liquid != null) {
      FluidStack amountDrained = resourceTank.drain(recipe.liquid.amount, false);
      if (amountDrained != null && amountDrained.amount == recipe.liquid.amount)
        resourceTank.drain(recipe.liquid.amount, true);
      else
        return false;
    }
    // Remove boxes
    if (recipe.box != null) {
      ItemStack removed = accessibleInventory.decrStackSize(SLOT_BOX, 1);
      if (removed == null || removed.stackSize == 0)
        return false;
    }

    return removeSets(1, craftingInventory.getStacks(SLOT_CRAFTING_1, 9));
  }

  private boolean removeSets(int count, ItemStack[] set) {
    EntityPlayer player = Proxies.common.getPlayer(worldObj, owner);
    return accessibleInventory.removeSets(count, set, SLOT_INVENTORY_1, SLOT_INVENTORY_COUNT, player, true, true, true);
  }

  private boolean tryAddPending() {
    if (accessibleInventory.getStackInSlot(SLOT_PRODUCT) == null) {
      accessibleInventory.setInventorySlotContents(SLOT_PRODUCT, pendingProduct.copy());
      pendingProduct = null;
      return true;
    }

    if (accessibleInventory.getStackInSlot(SLOT_PRODUCT).isItemEqual(pendingProduct)
        && accessibleInventory.getStackInSlot(SLOT_PRODUCT).stackSize <= accessibleInventory.getStackInSlot(SLOT_PRODUCT).getMaxStackSize() - pendingProduct.stackSize) {
      accessibleInventory.getStackInSlot(SLOT_PRODUCT).stackSize += pendingProduct.stackSize;
      pendingProduct = null;
      return true;
    }

    setErrorState(EnumErrorCode.NOSPACE);
    return false;
  }

  /* STATE INFORMATION */
  @Override
  public boolean isWorking() {
    return packageTime > 0 || pendingProduct != null || currentRecipe != null && validateResources();
  }

  @Override
  public boolean hasWork() {
    if (currentRecipe == null)
      return false;

    // Stop working if the output slot cannot take more
    if (accessibleInventory.getStackInSlot(SLOT_PRODUCT) != null
        && accessibleInventory.getStackInSlot(SLOT_PRODUCT).getMaxStackSize() - accessibleInventory.getStackInSlot(SLOT_PRODUCT).stackSize < currentRecipe
        .getCraftingResult().stackSize)
      return false;

    return validateResources();
  }

  public int getCraftingProgressScaled(int i) {
    if (totalTime == 0)
      return 0;

    return (packageTime * i) / totalTime;

  }

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

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

  /* IINVENTORY */
  @Override
  public int getSizeInventory() {
    return accessibleInventory.getSizeInventory();
  }

  @Override
  public ItemStack getStackInSlot(int i) {
    return accessibleInventory.getStackInSlot(i);
  }

  @Override
  public void setInventorySlotContents(int i, ItemStack itemstack) {
    accessibleInventory.setInventorySlotContents(i, itemstack);
  }

  @Override
  public ItemStack decrStackSize(int i, int j) {
    return accessibleInventory.decrStackSize(i, j);
  }

  @Override
  public ItemStack getStackInSlotOnClosing(int slot) {
    return accessibleInventory.getStackInSlotOnClosing(slot);
  }

  @Override
  public int getInventoryStackLimit() {
    return accessibleInventory.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);
  }

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

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

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

  /**
   * @return Inaccessible crafting inventory for the craft grid.
   */
  public InventoryAdapter getCraftingInventory() {
    return craftingInventory;
  }

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

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

    if (slotIndex == SLOT_PRODUCT)
      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_PRODUCT)
      return false;

    if (slotIndex == SLOT_BOX)
      return RecipeManager.isBox(itemstack);

    if (slotIndex == SLOT_CAN_INPUT)
      return FluidContainerRegistry.isContainer(itemstack);

    if (slotIndex >= SLOT_INVENTORY_1 && slotIndex < SLOT_INVENTORY_1 + SLOT_INVENTORY_COUNT) {
      if (lastRecipe == null)
        return true;
      return lastRecipe.isIngredient(itemstack);
    }

    return false;
  }

  // ILIQUIDCONTAINER IMPLEMENTATION
  @Override
  public int fill(ForgeDirection direction, FluidStack resource, boolean doFill) {
    return tankManager.fill(direction, resource, doFill);
  }

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

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

  public void resetProductDisplay(InventoryCrafting craftMatrix) {
    setCurrentRecipe(RecipeManager.findMatchingRecipe(resourceTank.getFluid(), getBoxStack(), craftMatrix, getWorldObj()));
  }

}
TOP

Related Classes of forestry.factory.gadgets.MachineCarpenter

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.