Package forestry.factory.gadgets

Source Code of forestry.factory.gadgets.MachineFabricator$Recipe

/*******************************************************************************
* 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 java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import forestry.core.EnumErrorCode;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.ICrafting;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.nbt.NBTTagCompound;

import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;

import forestry.api.core.ForestryAPI;
import forestry.api.core.ISpecialInventory;
import forestry.api.recipes.IFabricatorManager;
import forestry.core.config.Defaults;
import forestry.core.gadgets.TileBase;
import forestry.core.gadgets.TilePowered;
import forestry.core.interfaces.ICrafter;
import forestry.core.interfaces.ICraftingPlan;
import forestry.core.interfaces.ILiquidTankContainer;
import forestry.core.network.GuiId;
import forestry.core.proxy.Proxies;
import forestry.core.fluids.tanks.StandardTank;
import forestry.core.fluids.TankManager;
import forestry.core.fluids.tanks.FilteredTank;
import forestry.core.utils.InventoryAdapter;
import forestry.core.utils.ShapedRecipeCustom;
import forestry.core.utils.StackUtils;
import net.minecraftforge.fluids.FluidTankInfo;

public class MachineFabricator extends TilePowered implements ICrafter, ISpecialInventory, ILiquidTankContainer {

  /* RECIPE MANAGMENT */
  public static class Recipe {
    ItemStack plan;

    FluidStack molten;
    ShapedRecipeCustom internal;

    public Recipe(ItemStack plan, FluidStack molten, ShapedRecipeCustom internal) {
      this.plan = plan;
      this.molten = molten;
      this.internal = internal;
    }

    public boolean matches(ItemStack plan) {
      if (this.plan == null)
        return true;

      if (plan == null && this.plan == null)
        return true;
      else if (plan == null && this.plan != null)
        return false;

      if (this.plan.getItemDamage() == Defaults.WILDCARD)
        return plan.getItem() == this.plan.getItem();
      else
        return plan.isItemEqual(this.plan);
    }

    public boolean matches(ItemStack plan, ItemStack[][] resources) {
      if (!this.matches(plan))
        return false;

      return internal.matches(resources);
    }

    public boolean hasLiquid(FluidStack resource) {
      if(resource == null)
        return molten == null;

      if (!resource.isFluidEqual(molten))
        return false;

      return molten.amount <= resource.amount;
    }

    public ItemStack getPlan() {
      return plan;
    }

    public FluidStack getLiquid() {
      return molten;
    }

    public IRecipe asIRecipe() {
      return internal;
    }

  }

  public static class Smelting {
    ItemStack resource;
    FluidStack product;
    int meltingPoint;

    public Smelting(ItemStack resource, FluidStack molten, int meltingPoint) {
      if(resource == null)
        throw new IllegalArgumentException("Resource cannot be null");
      if(molten == null)
        throw new IllegalArgumentException("Molten cannot be null");

      this.resource = resource;
      this.product = molten;
      this.meltingPoint = meltingPoint;
    }

    public boolean matches(ItemStack resource) {
      return this.resource.isItemEqual(resource);
    }

    public boolean matches(FluidStack product) {
      return this.product.isFluidEqual(product);
    }

    public ItemStack getResource() {
      return resource;
    }

    public FluidStack getProduct() {
      return product;
    }

    public int getMeltingPoint() {
      return meltingPoint;
    }
  }

  public static class RecipeManager implements IFabricatorManager {
    public static ArrayList<Recipe> recipes = new ArrayList<Recipe>();
    public static ArrayList<Smelting> smeltings = new ArrayList<Smelting>();

    @Override
    public void addRecipe(ItemStack plan, FluidStack molten, ItemStack result, Object[] pattern) {
      recipes.add(new Recipe(plan, molten, ShapedRecipeCustom.createShapedRecipe(result, pattern)));
    }

    @Override
    public void addSmelting(ItemStack resource, FluidStack molten, int meltingPoint) {
      smeltings.add(new Smelting(resource, molten, meltingPoint));
    }

    public static Recipe findMatchingRecipe(ItemStack plan) {
      for (Recipe recipe : recipes)
        if (recipe.matches(plan))
          return recipe;

      return null;
    }

    public static Recipe findMatchingRecipeIfSmelted(ItemStack plan, FluidStack liquid, ItemStack itemToMelt, ItemStack[] resources) {
      Smelting smelting = findMatchingSmelting(itemToMelt);
      if (smelting == null || (liquid != null && !smelting.matches(liquid)))
        return findMatchingRecipe(plan, liquid, resources);

      FluidStack liquidIfSmelted;
      if (liquid != null) {
        liquidIfSmelted = liquid.copy();
        liquidIfSmelted.amount += smelting.getProduct().amount * itemToMelt.stackSize;
      } else {
        liquidIfSmelted = smelting.getProduct().copy();
        liquidIfSmelted.amount *= itemToMelt.stackSize;
      }
      return findMatchingRecipe(plan, liquidIfSmelted, resources);
    }

    public static Recipe findMatchingRecipe(ItemStack plan, FluidStack liquid, ItemStack[] resources) {
      ItemStack[][] gridResources = new ItemStack[3][3];
      for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
          gridResources[j][i] = resources[i * 3 + j];

      for (Recipe recipe : recipes)
        if (recipe.matches(plan, gridResources))
          if (recipe.hasLiquid(liquid))
            return recipe;

      return null;
    }

    public static boolean isResourceLiquid(FluidStack liquid) {
      for (Recipe recipe : recipes)
        if (recipe.hasLiquid(liquid))
          return true;

      return false;
    }

    public static Smelting findMatchingSmelting(ItemStack resource) {
      if (resource == null)
        return null;

      for (Smelting smelting : smeltings)
        if (smelting.matches(resource))
          return smelting;

      return null;
    }

    public static Smelting findMatchingSmelting(FluidStack product) {
      if (product == null)
        return null;

      for (Smelting smelting : smeltings)
        if (smelting.matches(product))
          return smelting;

      return null;
    }

    @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.internal.getRecipeOutput() });

      return recipeList;
    }

  }

  /* CONSTANTS */
  private static final int MAX_HEAT = 5000;

  public static final short SLOT_METAL = 0;
  public static final short SLOT_PLAN = 1;
  public static final short SLOT_RESULT = 2;
  public static final short SLOT_CRAFTING_1 = 3;
  public static final short SLOT_INVENTORY_1 = 12;
  public static final short SLOT_INVENTORY_COUNT = 18;

  /* MEMBER */
  private final TankManager tankManager;
  private FilteredTank moltenTank;
  private final InventoryAdapter inventory = new InventoryAdapter(30, "Items");
  private int heat = 0;
  private int guiMeltingPoint = 0;

  private FluidStack pendingSmelt;

  public MachineFabricator() {
    super(1100, 50, 3300);
    Fluid liquidGlass = FluidRegistry.getFluid(Defaults.LIQUID_GLASS);
    moltenTank = new FilteredTank(2 * Defaults.BUCKET_VOLUME, liquidGlass);
    moltenTank.tankMode = StandardTank.TankMode.INTERNAL;
    tankManager = new TankManager(moltenTank);
  }

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

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

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

    nbttagcompound.setInteger("Heat", heat);

    // Tank
    tankManager.writeTanksToNBT(nbttagcompound);

    // Pending Smelt
    if (pendingSmelt != null) {
      NBTTagCompound smelt = new NBTTagCompound();
      pendingSmelt.writeToNBT(smelt);
      nbttagcompound.setTag("PendingSmelt", smelt);
    }

    // / Inventory
    inventory.writeToNBT(nbttagcompound);
  }

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

    heat = nbttagcompound.getInteger("Heat");

    // Tank
    tankManager.readTanksFromNBT(nbttagcompound);

    // Pending Smelt
    if (nbttagcompound.hasKey("PendingSmelt")) {
      NBTTagCompound smelt = nbttagcompound.getCompoundTag("PendingSmelt");
      pendingSmelt = FluidStack.loadFluidStackFromNBT(smelt);
    }

    // / Inventory
    inventory.readFromNBT(nbttagcompound);

  }

  /* UPDATING */
  @Override
  public void updateServerSide() {
    // Add pending smelt
    if (pendingSmelt != null) {

      int filled = moltenTank.fill(pendingSmelt, true);
      pendingSmelt.amount -= filled;

      if (pendingSmelt.amount <= 0)
        pendingSmelt = null;
      // Smelt if necessary and possible
    } else if (moltenTank.getFluidAmount() < moltenTank.getCapacity() && inventory.getStackInSlot(SLOT_METAL) != null) {
      Smelting smelt = RecipeManager.findMatchingSmelting(inventory.getStackInSlot(SLOT_METAL));
      if (smelt != null && smelt.meltingPoint <= heat) {

        this.decrStackSize(SLOT_METAL, 1);
        pendingSmelt = smelt.product.copy();
      }
    } else if (moltenTank.getFluidAmount() > 0) {
      // Remove smelt if we have gone below melting point
      Smelting smelt = RecipeManager.findMatchingSmelting(moltenTank.getFluid());
      if (smelt != null && heat < smelt.meltingPoint)
        moltenTank.drain(5, true);
    }

    this.dissipateHeat();

    if (energyManager.getTotalEnergyStored() == 0 && heat == 0) {
      setErrorState(EnumErrorCode.NOPOWER);
    } else if (getErrorState() == EnumErrorCode.NOPOWER) {
      setErrorState(EnumErrorCode.OK);
    }
  }

  @Override
  public boolean workCycle() {
    return addHeat(25);
  }

  private boolean addHeat(int addition) {
    if (this.heat >= MAX_HEAT)
      return false;

    this.heat += addition;
    if (this.heat > MAX_HEAT)
      this.heat = MAX_HEAT;

    return true;
  }

  private void dissipateHeat() {
    if (heat > 2500)
      this.heat -= 2;
    else if (heat > 0)
      this.heat--;
  }

  public Object[] getPlan() {
    if (inventory.getStackInSlot(SLOT_PLAN) == null)
      return null;

    Recipe myRecipe = RecipeManager.findMatchingRecipe(inventory.getStackInSlot(SLOT_PLAN));
    if (myRecipe == null)
      return null;

    return myRecipe.internal.getIngredients();
  }

  private Recipe getRecipe() {
    return RecipeManager.findMatchingRecipe(inventory.getStackInSlot(SLOT_PLAN), moltenTank.getFluid(),
        inventory.getStacks(SLOT_CRAFTING_1, 9));
  }

  /* ICRAFTER */
  @Override
  public boolean canTakeStack(int slotIndex) {
    return true;
  }

  @Override
  public ItemStack getResult() {
    Recipe myRecipe = getRecipe();

    if (myRecipe == null)
      return null;

    return myRecipe.internal.getRecipeOutput().copy();
  }

  @Override
  public ItemStack takenFromSlot(int slotIndex, boolean consumeRecipe, EntityPlayer player) {
    if(slotIndex != SLOT_RESULT)
      return null;

    Recipe myRecipe = getRecipe();
    if (myRecipe == null)
      return null;

    FluidStack liquid = myRecipe.molten;

    // Remove resources
    if (removeFromInventory(1, inventory.getStacks(SLOT_CRAFTING_1, 9), player, false)) {
      removeFromInventory(1, inventory.getStacks(SLOT_CRAFTING_1, 9), player, true);
      moltenTank.drain(liquid.amount, true);
    } else if (consumeRecipe) {
      removeFromCraftMatrix(myRecipe);
      moltenTank.drain(liquid.amount, true);
    } else
      return null;

    ItemStack result = myRecipe.internal.getRecipeOutput().copy();
    // Damage plan
    if (inventory.getStackInSlot(SLOT_PLAN) != null) {
      Item planItem = inventory.getStackInSlot(SLOT_PLAN).getItem();
      if (planItem instanceof ICraftingPlan)
        inventory.setInventorySlotContents(SLOT_PLAN, ((ICraftingPlan) planItem).planUsed(inventory.getStackInSlot(SLOT_PLAN), result));
    }

    // Return result
    return result;
  }

  private void removeFromCraftMatrix(Recipe recipe) {

    for (int i = 0; i < 9; i++) {
      if (inventory.getStackInSlot(SLOT_CRAFTING_1 + i) == null)
        continue;
      inventory.decrStackSize(SLOT_CRAFTING_1 + i, 1);
    }

  }

  private boolean removeFromInventory(int count, ItemStack[] set, EntityPlayer player, boolean doRemove) {
    if (doRemove) {
      return inventory.removeSets(count, set, SLOT_INVENTORY_1, SLOT_INVENTORY_COUNT, player, true, true, true);
    } else {
      ItemStack[] stock = inventory.getStacks(SLOT_INVENTORY_1, SLOT_INVENTORY_COUNT);
      return StackUtils.containsSets(set, stock) >= count;
    }
  }

  @Override
  public boolean isWorking() {
    return this.heat <= MAX_HEAT;
  }

  @Override
  public boolean hasWork() {
    Recipe recipe = RecipeManager.findMatchingRecipeIfSmelted(inventory.getStackInSlot(SLOT_PLAN), moltenTank.getFluid(), inventory.getStackInSlot(SLOT_METAL),
        inventory.getStacks(SLOT_CRAFTING_1, 9));
    return recipe != null;
  }

  public int getHeatScaled(int i) {
    return (heat * i) / MAX_HEAT;
  }

  public int getMeltingPoint() {
    if (moltenTank.getFluidAmount() > 0) {
      Smelting smelt = RecipeManager.findMatchingSmelting(moltenTank.getFluid());
      if (smelt != null)
        return smelt.meltingPoint;
    } else if (this.getStackInSlot(SLOT_METAL) != null) {
      Smelting smelt = RecipeManager.findMatchingSmelting(this.getStackInSlot(SLOT_METAL));
      if (smelt != null)
        return smelt.meltingPoint;
    }

    return 0;
  }

  public int getMeltingPointScaled(int i) {
    // / For SMP clients
    if (guiMeltingPoint > 0)
      return (guiMeltingPoint * i) / MAX_HEAT;

    int meltingPoint = getMeltingPoint();

    if (meltingPoint <= 0)
      return 0;
    else
      return (meltingPoint * i) / MAX_HEAT;
  }

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

    if (i == messageId)
      heat = j;
    else if (i == messageId + 1)
      guiMeltingPoint = j;
  }

  public void sendGUINetworkData(Container container, ICrafting iCrafting) {
    int messageId = tankManager.maxMessageId() + 1;
    iCrafting.sendProgressBarUpdate(container, messageId, heat);
    iCrafting.sendProgressBarUpdate(container, messageId + 1, getMeltingPoint());
  }

  // / ISPECIALINVENTORY
  @Override
  public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) {
    if (from == ForgeDirection.UP && RecipeManager.findMatchingSmelting(stack) != null)
      return inventory.addStack(stack, SLOT_METAL, 1, false, doAdd);
    return inventory.addStack(stack, SLOT_INVENTORY_1, SLOT_INVENTORY_COUNT, false, doAdd);
  }

  @Override
  public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) {
    ItemStack taken;
    if (doRemove) {
      EntityPlayer player = Proxies.common.getPlayer(worldObj, owner);
      taken = this.takenFromSlot(SLOT_RESULT, false, player);
    } else {
      taken = this.getResult();
    }

    if (taken != null)
      return new ItemStack[] { taken };
    else
      return new ItemStack[0];
  }

  // / 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 int getInventoryStackLimit() {
    return inventory.getInventoryStackLimit();
  }

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

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

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

  @Override
  public int fill(ForgeDirection from, FluidStack resource, boolean doFill) {
    return tankManager.fill(from, 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 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);
  }

}
TOP

Related Classes of forestry.factory.gadgets.MachineFabricator$Recipe

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.