/******************************************************************************* * AbyssalCraft * Copyright (c) 2012 - 2017 Shinoow. * 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 * * Contributors: * Shinoow - implementation ******************************************************************************/ package com.shinoow.abyssalcraft.common.blocks.tile; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; import net.minecraft.inventory.ISidedInventory; import net.minecraft.inventory.ItemStackHelper; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.ITickable; import net.minecraft.util.NonNullList; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextComponentTranslation; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.shinoow.abyssalcraft.api.AbyssalCraftAPI; import com.shinoow.abyssalcraft.api.AbyssalCraftAPI.FuelType; import com.shinoow.abyssalcraft.api.item.ACItems; import com.shinoow.abyssalcraft.api.recipe.CrystallizerRecipes; import com.shinoow.abyssalcraft.common.blocks.BlockCrystallizer; public class TileEntityCrystallizer extends TileEntity implements ISidedInventory, ITickable { private static final int[] slotsTop = new int[] {0}; private static final int[] slotsBottom = new int[] {2, 1, 3}; private static final int[] slotsSides = new int[] {1}; /** * The ItemStacks that hold the items currently being used in the crystallizer */ private NonNullList<ItemStack> crystallizerItemStacks = NonNullList.<ItemStack>withSize(4, ItemStack.EMPTY); /** The number of ticks that the crystallizer will keep doing it's thing */ public int crystallizerShapeTime; /** * The number of ticks that a fresh copy of the currently-thingy item would keep the crystalizer stuffing for */ public int currentItemShapingTime; /** The number of ticks that the current item has been cooking for */ public int crystallizerFormTime; private String containerName; /** * Returns the number of slots in the inventory. */ @Override public int getSizeInventory() { return crystallizerItemStacks.size(); } /** * Returns the stack in slot i */ @Override public ItemStack getStackInSlot(int par1) { return crystallizerItemStacks.get(par1); } /** * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a * new stack. */ @Override public ItemStack decrStackSize(int par1, int par2) { return ItemStackHelper.getAndSplit(crystallizerItemStacks, par1, par2); } /** * When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem - * like when you close a workbench GUI. */ @Override public ItemStack removeStackFromSlot(int par1) { return ItemStackHelper.getAndRemove(crystallizerItemStacks, par1); } /** * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections). */ @Override public void setInventorySlotContents(int par1, ItemStack par2ItemStack) { crystallizerItemStacks.set(par1, par2ItemStack); if (par2ItemStack != null && par2ItemStack.getCount() > getInventoryStackLimit()) par2ItemStack.setCount(getInventoryStackLimit()); } /** * Returns the name of the inventory */ @Override public String getName() { return hasCustomName() ? containerName : "container.abyssalcraft.crystallizer"; } /** * Returns if the inventory is named */ @Override public boolean hasCustomName() { return containerName != null && containerName.length() > 0; } public void func_145951_a(String par1) { containerName = par1; } @Override public void readFromNBT(NBTTagCompound par1) { super.readFromNBT(par1); crystallizerItemStacks = NonNullList.withSize(getSizeInventory(), ItemStack.EMPTY); ItemStackHelper.loadAllItems(par1, crystallizerItemStacks); crystallizerShapeTime = par1.getShort("ShapeTime"); crystallizerFormTime = par1.getShort("FormTime"); currentItemShapingTime = getCrystallizationTime(crystallizerItemStacks.get(1)); if (par1.hasKey("CustomName", 8)) containerName = par1.getString("CustomName"); } @Override public NBTTagCompound writeToNBT(NBTTagCompound par1) { super.writeToNBT(par1); par1.setShort("ShapeTime", (short)crystallizerShapeTime); par1.setShort("FormTime", (short)crystallizerFormTime); ItemStackHelper.saveAllItems(par1, crystallizerItemStacks); if (hasCustomName()) par1.setString("CustomName", containerName); return par1; } /** * Returns the maximum stack size for a inventory slot. */ @Override public int getInventoryStackLimit() { return 64; } /** * Returns an integer between 0 and the passed value representing how close the current item is to being completely * cooked */ @SideOnly(Side.CLIENT) public int getFormProgressScaled(int par1) { return crystallizerFormTime * par1 / 200; } /** * Returns an integer between 0 and the passed value representing how much burn time is left on the current fuel * item, where 0 means that the item is exhausted and the passed value means that the item is fresh */ @SideOnly(Side.CLIENT) public int getShapeTimeRemainingScaled(int par1) { if (currentItemShapingTime == 0) currentItemShapingTime = 200; return crystallizerShapeTime * par1 / currentItemShapingTime; } /** * Furnace isBurning */ public boolean isCrystallizing() { return crystallizerShapeTime > 0; } @Override public void update() { boolean flag = crystallizerShapeTime > 0; boolean flag1 = false; if (crystallizerShapeTime > 0) --crystallizerShapeTime; if (!world.isRemote) { if (crystallizerShapeTime == 0 && canCrystallize()) { currentItemShapingTime = crystallizerShapeTime = getCrystallizationTime(crystallizerItemStacks.get(1)); if (crystallizerShapeTime > 0) { flag1 = true; if (!crystallizerItemStacks.get(1).isEmpty()) { crystallizerItemStacks.get(1).shrink(1); if (crystallizerItemStacks.get(1).isEmpty()) crystallizerItemStacks.set(1, crystallizerItemStacks.get(1).getItem().getContainerItem(crystallizerItemStacks.get(1))); } } } if (isCrystallizing() && canCrystallize()) { ++crystallizerFormTime; if (crystallizerFormTime == 200) { crystallizerFormTime = 0; crystalizeItem(); flag1 = true; } } else crystallizerFormTime = 0; if (flag != crystallizerShapeTime > 0) { flag1 = true; BlockCrystallizer.updateCrystallizerBlockState(crystallizerShapeTime > 0, world, pos); } } if (flag1) markDirty(); } /** * Returns true if the crystallizer can crystallize an item, i.e. has a source item, destination stack isn't full, etc. */ private boolean canCrystallize() { if (crystallizerItemStacks.get(0).isEmpty() || CrystallizerRecipes.instance().getCrystallizationResult(crystallizerItemStacks.get(0)) == null) return false; else { ItemStack[] itemstack = CrystallizerRecipes.instance().getCrystallizationResult(crystallizerItemStacks.get(0)); if(itemstack[0].isEmpty() && itemstack[1].isEmpty() || itemstack[0].isEmpty()) return false; if(crystallizerItemStacks.get(2).isEmpty() && crystallizerItemStacks.get(3).isEmpty()) return true; if(itemstack[1].isEmpty()){ if(crystallizerItemStacks.get(2).isEmpty() || crystallizerItemStacks.get(2).isItemEqual(itemstack[0])) return true; if(!crystallizerItemStacks.get(2).isItemEqual(itemstack[0])) return false; } else { if(crystallizerItemStacks.get(2).isEmpty() && !crystallizerItemStacks.get(3).isItemEqual(itemstack[1])) return false; if(crystallizerItemStacks.get(2).isEmpty() && crystallizerItemStacks.get(3).isEmpty() || crystallizerItemStacks.get(2).isEmpty() && crystallizerItemStacks.get(3).isItemEqual(itemstack[1]) || crystallizerItemStacks.get(2).isItemEqual(itemstack[0]) && crystallizerItemStacks.get(3).isEmpty() && !crystallizerItemStacks.get(2).isEmpty() || crystallizerItemStacks.get(2).isItemEqual(itemstack[0]) && crystallizerItemStacks.get(3).isItemEqual(itemstack[1])) return true; if(!crystallizerItemStacks.get(2).isItemEqual(itemstack[0]) && crystallizerItemStacks.get(3).isEmpty()) return false; if(!crystallizerItemStacks.get(2).isItemEqual(itemstack[0]) && !crystallizerItemStacks.get(3).isItemEqual(itemstack[1])) return false; } int result = crystallizerItemStacks.get(2).getCount() + itemstack[0].getCount(); int result2 = crystallizerItemStacks.get(3).getCount() + itemstack[1].getCount(); return result <= getInventoryStackLimit() && result2 <= getInventoryStackLimit() && result <= crystallizerItemStacks.get(2).getMaxStackSize() && result2 <= crystallizerItemStacks.get(3).getMaxStackSize(); } } /** * Turn one item from the crystallizer source stack into the appropriate crystallized item in the crystallizer result stack */ public void crystalizeItem() { if (canCrystallize()) { ItemStack[] itemstack = CrystallizerRecipes.instance().getCrystallizationResult(crystallizerItemStacks.get(0)); Map<ItemStack, ItemStack> testList = new HashMap<ItemStack, ItemStack>(); testList.put(itemstack[0], itemstack[1]); Iterator<?> iterator = testList.entrySet().iterator(); if (crystallizerItemStacks.get(2).isEmpty()) crystallizerItemStacks.set(2, itemstack[0].copy()); else if (crystallizerItemStacks.get(2).getItem() == itemstack[0].getItem()) crystallizerItemStacks.get(2).grow(itemstack[0].getCount()); if(iterator.hasNext() && !itemstack[1].isEmpty()) if (crystallizerItemStacks.get(3).isEmpty()) crystallizerItemStacks.set(3, itemstack[1].copy()); else if (crystallizerItemStacks.get(3).getItem() == itemstack[1].getItem()) crystallizerItemStacks.get(3).grow(itemstack[1].getCount()); crystallizerItemStacks.get(0).shrink(1); if (crystallizerItemStacks.get(0).getCount() <= 0) crystallizerItemStacks.set(0, ItemStack.EMPTY); } } /** * Returns the number of ticks that the supplied fuel item will keep the furnace burning, or 0 if the item isn't * fuel */ // TODO: create new fuel types public static int getCrystallizationTime(ItemStack par1ItemStack) { if (par1ItemStack.isEmpty()) return 0; else { Item item = par1ItemStack.getItem(); if (item == ACItems.dread_fragment) return 100; if (item == ACItems.dreaded_shard_of_abyssalnite) return 1000; if (item == ACItems.dreaded_chunk_of_abyssalnite) return 1600; if (item == Items.BLAZE_POWDER) return 1200; if (item == Items.BLAZE_ROD) return 2400; if (item == ACItems.methane) return 10000; return AbyssalCraftAPI.getFuelValue(par1ItemStack, FuelType.CRYSTALLIZER); } } public static boolean isItemFuel(ItemStack par1ItemStack) { /** * Returns the number of ticks that the supplied fuel item will keep the furnace burning, or 0 if the item isn't * fuel */ return getCrystallizationTime(par1ItemStack) > 0; } /** * Do not make give this method the name canInteractWith because it clashes with Container */ @Override public boolean isUsableByPlayer(EntityPlayer par1EntityPlayer) { return world.getTileEntity(pos) != this ? false : par1EntityPlayer.getDistanceSq(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D) <= 64.0D; } @Override public void openInventory(EntityPlayer player) {} @Override public void closeInventory(EntityPlayer player) {} /** * Returns true if automation is allowed to insert the given stack (ignoring stack size) into the given slot. */ @Override public boolean isItemValidForSlot(int par1, ItemStack par2ItemStack) { return par1 == 2 ? false : par1 == 1 ? isItemFuel(par2ItemStack) : true; } /** * Returns an array containing the indices of the slots that can be accessed by automation on the given side of this * block. */ @Override public int[] getSlotsForFace(EnumFacing face) { return face == EnumFacing.DOWN ? slotsBottom : face == EnumFacing.UP ? slotsTop : slotsSides; } /** * Returns true if automation can insert the given item in the given slot from the given side. Args: Slot, item, * side */ @Override public boolean canInsertItem(int par1, ItemStack par2ItemStack, EnumFacing face) { return isItemValidForSlot(par1, par2ItemStack); } /** * Returns true if automation can extract the given item in the given slot from the given side. Args: Slot, item, * side */ @Override public boolean canExtractItem(int par1, ItemStack par2ItemStack, EnumFacing face) { if (face == EnumFacing.DOWN && par1 == 1) { Item item = par2ItemStack.getItem(); if (item != Items.WATER_BUCKET && item != Items.BUCKET) return false; } return true; } @Override public int getField(int id) { // TODO Auto-generated method stub return 0; } @Override public void setField(int id, int value) { // TODO Auto-generated method stub } @Override public int getFieldCount() { // TODO Auto-generated method stub return 0; } @Override public void clear() { // TODO Auto-generated method stub } @Override public ITextComponent getDisplayName() { return hasCustomName() ? new TextComponentString(getName()) : new TextComponentTranslation(getName(), new Object[0]); } net.minecraftforge.items.IItemHandler handlerTop = new net.minecraftforge.items.wrapper.SidedInvWrapper(this, net.minecraft.util.EnumFacing.UP); net.minecraftforge.items.IItemHandler handlerBottom = new net.minecraftforge.items.wrapper.SidedInvWrapper(this, net.minecraft.util.EnumFacing.DOWN); net.minecraftforge.items.IItemHandler handlerSide = new net.minecraftforge.items.wrapper.SidedInvWrapper(this, net.minecraft.util.EnumFacing.WEST); @SuppressWarnings("unchecked") @Override public <T> T getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, net.minecraft.util.EnumFacing facing) { if (facing != null && capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) if (facing == EnumFacing.DOWN) return (T) handlerBottom; else if (facing == EnumFacing.UP) return (T) handlerTop; else return (T) handlerSide; return super.getCapability(capability, facing); } @Override public boolean isEmpty() { for (ItemStack itemstack : crystallizerItemStacks) if (!itemstack.isEmpty()) return false; return true; } }