Package xk.xact.core.tileentities

Source Code of xk.xact.core.tileentities.TileCrafter

package xk.xact.core.tileentities;

import appeng.api.IItemList;
import appeng.api.WorldCoord;
import appeng.api.me.tiles.IGridTileEntity;
import appeng.api.me.tiles.INonSignalBlock;
import appeng.api.me.tiles.IStorageAware;
import appeng.api.me.util.IGridInterface;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.mcft.copy.betterstorage.api.ICrateStorage;
import net.mcft.copy.betterstorage.api.ICrateWatcher;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeDirection;
import xk.xact.api.CraftingHandler;
import xk.xact.api.ICraftingDevice;
import xk.xact.client.gui.GuiCrafter;
import xk.xact.client.gui.GuiCrafting;
import xk.xact.config.ConfigurationManager;
import xk.xact.gui.ContainerCrafter;
import xk.xact.inventory.Inventory;
import xk.xact.inventory.InventoryUtils;
import xk.xact.plugin.PluginManager;
import xk.xact.recipes.CraftRecipe;
import xk.xact.recipes.RecipeUtils;
import xk.xact.util.Utils;

import java.util.ArrayList;
import java.util.List;

/**
* @author Xhamolk_
*/
public class TileCrafter extends TileMachine implements IInventory, ICraftingDevice, ICrateWatcher, IStorageAware, INonSignalBlock, IGridTileEntity {

  /*
  Available Inventories:
    This should be able to pull items from adjacent chests.

  Crafting mechanism:
    The CraftRecipe object knows the ingredients and their position on the crafting grid.
    If the required items are present on the resources buffer, then
     (per operation) each ingredient will be placed into a fake crafting grid.
     The recipe will be crafted.
     Finally, the remaining items on the crafting grid will be placed back on the resources.
   */

  /**
   * Holds the recipes' outputs
   */
  public final Inventory results;

  /**
   * The inventory that holds the circuits.
   */
  public final Inventory circuits; // size = 4

  /**
   * The inventory that holds the crafting grid's contents.
   */
  public final Inventory craftGrid;

  /**
   * The resources inventory.
   * You can access this inventory through pipes/tubes.
   */
  public final Inventory resources; // size = 3*9 = 27

  // Used to trigger state updates on the next tick.
  private boolean stateUpdatePending = false;

  // Whether if the neighbors have changed, so this machine should update on the next tick.
  private boolean neighborsUpdatePending = false;

  // Used by GuiCrafter to update it's internal state.
  // Should only be accessed client-side for rendering purposes.
  public boolean recentlyUpdated = false;

  public TileCrafter() {
    this.results = new Inventory( getRecipeCount(), "Results" );
    this.circuits = new Inventory( 4, "Encoded Recipes" ) {
      @Override
      public void onInventoryChanged() {
        TileCrafter.this.updateRecipes();
        stateUpdatePending = true;
        recentlyUpdated = true;
      }
    };
    this.craftGrid = new Inventory( 9, "CraftingGrid" ) {
      @Override
      public void onInventoryChanged() {
        TileCrafter.this.updateRecipes();
        stateUpdatePending = true;
        recentlyUpdated = true;
      }
    };
    this.resources = new Inventory( 3 * 9, "Resources" ) {
      @Override
      public void onInventoryChanged() {
        TileCrafter.this.onInventoryChanged();
      }
    };
  }

  @Override // the items to be dropped when the block is destroyed.
  public ArrayList<ItemStack> getDropItems() {
    ArrayList<ItemStack> list = new ArrayList<ItemStack>();
    for( int i = 0; i < this.circuits.getSizeInventory(); i++ ) {
      ItemStack stack = circuits.getStackInSlotOnClosing( i );
      if( stack != null )
        list.add( stack );
    }
    for( int i = 0; i < this.resources.getSizeInventory(); i++ ) {
      ItemStack stack = resources.getStackInSlotOnClosing( i );
      if( stack != null )
        list.add( stack );
    }
    return list;
  }

  public Container getContainerFor(EntityPlayer player) {
    return new ContainerCrafter( this, player );
  }

  @SideOnly(Side.CLIENT)
  public GuiContainer getGuiContainerFor(EntityPlayer player) {
    return new GuiCrafter( this, player );
  }

  @Override
  public void onBlockUpdate(int type) {
    switch( type ) {
      case 0: // Block update
        neighborsUpdatePending = true;
        break;
      case 1: // Tile change
        stateUpdatePending = true;
        break;
    }
  }

  @Override
  public void validate() {
    super.validate();
    neighborsUpdatePending = true;
    fireLoadEventAE();
  }

  @Override
  public void invalidate() {
    super.invalidate();
    for( int i = 0; i < adjacentCrates.length; i++ ) {
      ICrateStorage crate = adjacentCrates[i];
      if( crate != null ) {
        crate.unregisterCrateWatcher( this );
        adjacentCrates[i] = null;
      }
    }
    fireUnloadEventAE();
  }

  ///////////////
  ///// Current State (requires updates)

  public boolean[] craftableRecipes = new boolean[getRecipeCount()];

  private CraftRecipe[] recipes = new CraftRecipe[getRecipeCount()];

  /**
   * The current state of the recipes loaded into this machine.
   */
  public boolean[][] recipeStates = new boolean[getRecipeCount()][9];

  @Override
  public void updateEntity() { // It was 5!
    if( worldObj.getWorldTime() % 40 != 0 ) { // 4 checks per second might be enough.
      return;
    }

    updateIfChangesDetected();
  }

  // Gets the recipe's result.
  public ItemStack getRecipeResult(int slot) {
    CraftRecipe recipe = this.getRecipe( slot );
    return recipe == null ? null : recipe.getResult();
  }

  // updates the stored recipe results.
  public void updateRecipes() {
    for( int i = 0; i < getRecipeCount(); i++ ) {
      if( i == 4 ) {
        recipes[i] = RecipeUtils.getRecipe( craftGrid.getContents(), this.worldObj );
        if( recipes[i] != null ) {
          if( this.worldObj != null && this.worldObj.isRemote ) { // client-side only
            notifyClientOfRecipeChanged();
          }
        }
      } else {
        ItemStack stack = this.circuits.getStackInSlot( i );
        if( stack == null )
          recipes[i] = null;
        else
          recipes[i] = RecipeUtils.getRecipe( stack, this.worldObj );
      }
    }

    for( int i = 0; i < getRecipeCount(); i++ ) {
      ItemStack stack = recipes[i] == null ? null : recipes[i].getResult();
      results.setInventorySlotContents( i, stack );
    }
  }

  // Updates the states of the recipes.
  public void updateState() {
    if( worldObj.isRemote ) {
      return; // don't do this client-side.
    }
    for( int i = 0; i < getRecipeCount(); i++ ) {
      // if the recipe can be crafted.
      craftableRecipes[i] = (recipes[i] != null) && getHandler().canCraft( this.getRecipe( i ), null );
      recipeStates[i] = getHandler().getMissingIngredientsArray( recipes[i] );
    }
  }

  // Used to trigger updates if changes have been detected.
  private void updateIfChangesDetected() {
    if( neighborsUpdatePending && !worldObj.isRemote ) {
      checkForAdjacentCrates();
      neighborsUpdatePending = false;
    }

    if( stateUpdatePending ) {
      updateState();
      stateUpdatePending = false;
    }
  }

  ///////////////
  ///// ICraftingDevice

  @Override
  @SuppressWarnings( "unchecked" )
  public List getAvailableInventories() {
    // Pulling from adjacent inventories
    List list = Utils.getAdjacentInventories( this.worldObj, this.xCoord, this.yCoord, this.zCoord );
    // The internal inventory is always the top priority.
    list.add( 0, resources );
    return list;
//    List<IInventory> list = Utils.getAdjacentInventories( worldObj, xCoord, yCoord, zCoord );
//    list.add( 0, resources );
//    return list.toArray( new IInventory[0] );
//    return Arrays.asList( resources );
  }

  @Override
  public int getRecipeCount() {
    return 5;
  }

  @Override
  public boolean canCraft(int index) {
    if( index < 0 || index > getRecipeCount() )
      return false;
    updateIfChangesDetected();
    return craftableRecipes[index];
  }

  @Override
  public CraftRecipe getRecipe(int index) {
    if( index < 0 || index > getRecipeCount() )
      return null;

    return recipes[index];
  }


  private CraftingHandler handler;

  @Override
  public CraftingHandler getHandler() {
    if( handler == null )
      handler = CraftingHandler.createCraftingHandler( this );
    return handler;
  }

  @Override
  public World getWorld() {
    return this.worldObj;
  }

  ///////////////
  ///// IInventory: provide access to the resources inventory


  @Override
  public int getSizeInventory() {
    return resources.getSizeInventory();
  }

  @Override
  public ItemStack getStackInSlot(int var1) {
    return resources.getStackInSlot( var1 );
  }

  @Override
  public ItemStack decrStackSize(int var1, int var2) {
    return resources.decrStackSize( var1, var2 );
  }

  @Override
  public ItemStack getStackInSlotOnClosing(int var1) {
    return resources.getStackInSlotOnClosing( var1 );
  }

  @Override
  public void setInventorySlotContents(int var1, ItemStack var2) {
    resources.setInventorySlotContents( var1, var2 );
  }

  @Override
  public String getInvName() {
    return resources.getInvName();
  }

  @Override
  public boolean isInvNameLocalized() {
    return false// Not a clue what this does.
  }

  @Override
  public int getInventoryStackLimit() {
    return 64;
  }

  @Override
  public boolean isUseableByPlayer(EntityPlayer var1) {
    return true;
  }

  @Override
  public void onInventoryChanged() { // this is called when adding stuff through pipes/tubes/etc
    super.onInventoryChanged();
    stateUpdatePending = true;
    recentlyUpdated = true;
  }

  @Override
  public void openChest() {
  }

  @Override
  public void closeChest() {
  }

  @Override
  public boolean isItemValidForSlot(int slot, ItemStack itemstack) {
    return true// Whether if an item can be placed at the slot
  }

  ///////////////
  ///// NBT

  @Override
  public void readFromNBT(NBTTagCompound compound) {
    super.readFromNBT( compound );
    resources.readFromNBT( compound );
    circuits.readFromNBT( compound );
    craftGrid.readFromNBT( compound );
    updateRecipes();
    stateUpdatePending = true;
  }

  @Override
  public void writeToNBT(NBTTagCompound compound) {
    super.writeToNBT( compound );
    resources.writeToNBT( compound );
    circuits.writeToNBT( compound );
    craftGrid.writeToNBT( compound );
  }

  //////////
  ///// Recipe Deque

  @SideOnly(Side.CLIENT)
  private void notifyClientOfRecipeChanged() {
    GuiScreen screen = Minecraft.getMinecraft().currentScreen;
    if( screen != null && screen instanceof GuiCrafting ) {
      ((GuiCrafting) screen).pushRecipe( recipes[4] );
    }
  }

  // ---------- Pulling from Adjacent Inventories ---------- //

  @SuppressWarnings("unchecked")
  public static List getAdjacentInventories(TileCrafter machine) {
    List<TileEntity> tiles = Utils.getAdjacentTileEntities( machine.worldObj, machine.xCoord, machine.yCoord, machine.zCoord );
    List<Object> adjacentInventories = new ArrayList<Object>();
    for( TileEntity tile : tiles ) {
      if( tile != null && InventoryUtils.isValidInventory( tile ) )
        adjacentInventories.add( tile );
    }
    return adjacentInventories;
  }

  // ---------- Better Storage integration ---------- //

  private ICrateStorage[] adjacentCrates = new ICrateStorage[6];

  @Override
  public void onCrateItemsModified(ItemStack stack) {
    stateUpdatePending = true;
  }

  private void checkForAdjacentCrates() {
    if( !ConfigurationManager.ENABLE_BETTER_STORAGE_PLUGIN )
      return;

    boolean foundChanges = false;

    for( int i = 0; i < 6; i++ ) {
      int x = xCoord + ForgeDirection.VALID_DIRECTIONS[i].offsetX;
      int y = yCoord + ForgeDirection.VALID_DIRECTIONS[i].offsetY;
      int z = zCoord + ForgeDirection.VALID_DIRECTIONS[i].offsetZ;

      TileEntity tile = worldObj.getBlockTileEntity( x, y, z );
      if( tile != null && tile instanceof ICrateStorage ) {
        if( adjacentCrates[i] == null ) {
          adjacentCrates[i] = (ICrateStorage) tile;
          adjacentCrates[i].registerCrateWatcher( this );
          foundChanges = true;
        }
      } else if( adjacentCrates[i] != null  ) {
        adjacentCrates[i] = null;
        foundChanges = true;
      }
    }
    if( foundChanges )
      stateUpdatePending = true;
  }

  // ---------- Applied Energistics integration ---------- //

  @Override
  public WorldCoord getLocation() {
    return new WorldCoord( xCoord, yCoord, zCoord );
  }

  @Override
  public boolean isValid() {
    return true;
  }

  @Override
  public void setPowerStatus(boolean hasPower) { }

  @Override
  public boolean isPowered() {
    return true;
  }

  @Override
  public IGridInterface getGrid() {
    return null;
  }

  @Override
  public void setGrid(IGridInterface gi) { }

  @Override
  public void onNetworkInventoryChange(IItemList iss) {
    stateUpdatePending = true;
  }

  // Connectivity events

  private void fireLoadEventAE() {
    if( PluginManager.aeProxy != null ) {
      PluginManager.aeProxy.fireTileLoadEvent( this );
    }
  }

  private void fireUnloadEventAE() {
    if( PluginManager.aeProxy != null ) {
      PluginManager.aeProxy.fireTileUnloadEvent( this );
    }
  }

}
TOP

Related Classes of xk.xact.core.tileentities.TileCrafter

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.