package mhfc.net.common.tile;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import mhfc.net.common.core.registry.MHFCEquipementRecipeRegistry;
import mhfc.net.common.crafting.recipes.equipment.EquipmentRecipe;
import mhfc.net.common.crafting.recipes.equipment.EquipmentRecipe.RecipeType;
import mhfc.net.common.network.PacketPipeline;
import mhfc.net.common.network.message.bench.*;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityFurnace;
public class TileHunterBench extends TileEntity
implements
IInventory,
TileMHFCUpdateStream {
public static final int outputSlot = 2;
public static final int fuelSlot = 0;
public static final int resultSlot = 1;
private ItemStack fuelStack;
private ItemStack resultStack;
private ItemStack[] recipeStacks;
private ItemStack[] inputStacks;
private ItemStack outputStack;
/**
* How hot the furnace currently is
*/
volatile private int heatStrength;
/**
* How hot the fire produced by the currently burning item is
*/
volatile private int heatFromItem;
/**
* How long the furnace stays hot
*/
volatile private int heatLength;
/**
* How long the furnace stayed hot initially with the burning item
*/
private int heatLengthInit;
/**
* How long the current item has been smelting
*/
volatile private int itemSmeltDuration;
/**
* The selected recipe
*/
private EquipmentRecipe recipe;
/**
* If the recipe is currently worked on
*/
volatile private boolean workingMHFCBench;
public TileHunterBench() {
recipeStacks = new ItemStack[7];
inputStacks = new ItemStack[recipeStacks.length];
workingMHFCBench = false;
heatLengthInit = 1;
}
@Override
public int getSizeInventory() {
return recipeStacks.length + inputStacks.length + 3;
}
@Override
public void updateEntity() {
if (heatLength > 0) {
--heatLength;
heatStrength = getNewHeat(heatStrength, heatFromItem);
if (TileHunterBench.this.workingMHFCBench && recipe != null
&& heatStrength >= recipe.getRequiredHeat())
++itemSmeltDuration;
} else {
if (fuelStack != null && TileHunterBench.this.workingMHFCBench) {
heatLength = TileEntityFurnace.getItemBurnTime(fuelStack);
heatLengthInit = heatLength;
heatFromItem = getItemHeat(fuelStack);
decrStackSize(fuelSlot, 1);
if (!worldObj.isRemote)
sendUpdateCraft();
} else {
heatStrength = getNewHeat(heatStrength, 0);
}
}
if (recipe != null && itemSmeltDuration >= recipe.getDuration()) {
finishRecipe();
}
}
private void finishRecipe() {
if (worldObj.isRemote) {
return;
}
inputStacks = new ItemStack[inputStacks.length];
outputStack = resultStack.copy();
workingMHFCBench = false;
itemSmeltDuration = 0;
sendUpdateCraft();
}
/**
* Forces the client to end the crafting and put the stack into the output
* slot. Unused
*
* @param stack
*/
@SideOnly(Side.CLIENT)
public void forceEndCrafting(ItemStack stack) {
outputStack = stack;
inputStacks = new ItemStack[inputStacks.length];
TileHunterBench.this.workingMHFCBench = false;
itemSmeltDuration = 0;
}
public boolean isWorking() {
return TileHunterBench.this.workingMHFCBench;
}
public void changeRecipe(EquipmentRecipe recipe) {
if (worldObj.isRemote) {
sendSetRecipe(recipe);
}
if (recipe != this.recipe) {
cancelRecipe();
setRecipe(recipe);
}
}
protected void setRecipe(EquipmentRecipe recipe) {
if (recipe == null) {
recipeStacks = new ItemStack[7];
this.recipe = null;
resultStack = null;
} else {
resultStack = recipe.getRecipeOutput();
this.recipe = recipe;
setIngredients(recipe);
}
}
public void setIngredients(EquipmentRecipe recipe) {
this.recipeStacks = recipe.getRequirements(7);
}
public static int getItemHeat(ItemStack itemStack) {
if (itemStack == null)
return 0;
if (itemStack.getItem() == Item.getItemById(327))
return 1000;
return 200;
}
private int getNewHeat(int heatOld, int heatAim) {
int diff = heatAim - heatOld;
// Some math to confuse the hell out of everyone reading this
double change = Math.ceil(Math.log(Math.abs(diff) + 1.0));
return heatOld + (int) (Math.ceil(change / 3.0) * Math.signum(diff));
}
@Override
public ItemStack getStackInSlot(int i) {
if (i < 0 || i >= getSizeInventory())
return null;
else if (i >= recipeStacks.length + 3)
return inputStacks[i - 3 - recipeStacks.length];
else if (i >= 3)
return recipeStacks[i - 3];
else if (i == outputSlot)
return outputStack;
else if (i == resultSlot)
return resultStack;
else
return fuelStack;
}
@Override
public ItemStack decrStackSize(int i, int j) {
markDirty();
if (j <= 0)
return null;
if (i > recipeStacks.length + 2) {
ItemStack stack = inputStacks[i - recipeStacks.length - 3];
if (stack == null)
return null;
cancelRecipe();
if (j > stack.stackSize)
j = stack.stackSize;
if (j == stack.stackSize) {
inputStacks[i - recipeStacks.length - 3] = null;
return stack;
}
return stack.splitStack(j);
}
if (i > 2)
return null; // You cant get anything from the recipe slots
else if (i == outputSlot) {
if (outputStack == null)
return null;
if (j > outputStack.stackSize)
j = outputStack.stackSize;
if (j == outputStack.stackSize) {
ItemStack fuel = outputStack;
outputStack = null;
return fuel;
}
return outputStack.splitStack(j);
} else if (i == resultSlot) {
return null;
} else {
if (fuelStack == null)
return null;
if (j > fuelStack.stackSize)
j = fuelStack.stackSize;
if (j == fuelStack.stackSize) {
ItemStack fuel = fuelStack;
fuelStack = null;
return fuel;
}
return fuelStack.splitStack(j);
}
}
/**
* Resets all working progress but leaves the recipe set
*/
public void cancelRecipe() {
if (worldObj.isRemote)
sendCancelRecipe();
TileHunterBench.this.workingMHFCBench = false;
itemSmeltDuration = 0;
}
@Override
public ItemStack getStackInSlotOnClosing(int i) {
return null;
}
@Override
public void setInventorySlotContents(int i, ItemStack itemstack) {
if (i < 0 || i >= getSizeInventory())
return;
if (i >= recipeStacks.length + 3)
inputStacks[i - recipeStacks.length - 3] = itemstack;
else if (i >= 3)
recipeStacks[i - 3] = itemstack;
else if (i == outputSlot) {
outputStack = itemstack;
} else if (i == resultSlot) {
resultStack = itemstack;
} else if (i == fuelSlot)
fuelStack = itemstack;
}
public boolean isInvNameLocalized() {
return false;
}
@Override
public int getInventoryStackLimit() {
return 64;
}
@Override
public boolean isUseableByPlayer(EntityPlayer entityplayer) {
return getDistanceFrom(entityplayer.posX, entityplayer.posY,
entityplayer.posZ) <= 64.0f;
}
@Override
public boolean isItemValidForSlot(int i, ItemStack itemstack) {
return (i == fuelSlot && TileEntityFurnace.isItemFuel(itemstack))
|| (i > recipeStacks.length + 2 && i < recipeStacks.length * 2 + 3);
}
@Override
public String getInventoryName() {
return "container.hunterbench";
}
@Override
public boolean hasCustomInventoryName() {
return false;
}
@Override
public void openInventory() {
}
@Override
public void closeInventory() {
}
public boolean beginCrafting() {
if (worldObj.isRemote) {
sendBeginCraft();
}
if (recipe != null) {
if (canBeginCrafting()) {
TileHunterBench.this.workingMHFCBench = true;
}
}
return TileHunterBench.this.workingMHFCBench;
}
@SideOnly(Side.CLIENT)
private void sendBeginCraft() {
PacketPipeline.networkPipe.sendToServer(new MessageBeginCrafting(this));
}
@SideOnly(Side.CLIENT)
private void sendSetRecipe(EquipmentRecipe recipeToSend) {
PacketPipeline.networkPipe.sendToServer(new MessageSetRecipe(this,
recipeToSend));
}
@SideOnly(Side.CLIENT)
private void sendCancelRecipe() {
PacketPipeline.networkPipe.sendToServer(new MessageCancelRecipe(this));
}
@Override
public void refreshState() {
if (worldObj.isRemote) {
PacketPipeline.networkPipe.sendToServer(
new MessageBenchRefreshRequest(this));
}
}
private void sendUpdateCraft() {
PacketPipeline.networkPipe.sendToAll(new MessageCraftingUpdate(this));
}
public boolean canBeginCrafting() {
return matchesInputOutput() && (outputStack == null);
}
protected boolean matchesInputOutput() {
for (int i = 0; i < inputStacks.length; i++) {
if (!ItemStack.areItemStacksEqual(inputStacks[i], recipeStacks[i]))
return false;
}
return true;
}
public int getHeatStrength() {
return heatStrength;
}
public int getBurningItemHeat() {
return heatFromItem;
}
public int getHeatLength() {
return heatLength;
}
public int getHeatLengthOriginal() {
return heatLengthInit;
}
public int getItemSmeltDuration() {
return itemSmeltDuration;
}
@Override
public void readFromNBT(NBTTagCompound nbtTag) {
super.readFromNBT(nbtTag);
readCustomUpdate(nbtTag);
NBTTagList items = nbtTag.getTagList("Items", 10);
for (int a = 0; a < items.tagCount(); a++) {
NBTTagCompound stack = items.getCompoundTagAt(a);
byte id = stack.getByte("Slot");
if (id >= 0 && id < getSizeInventory())
setInventorySlotContents(id, ItemStack.loadItemStackFromNBT(
stack));
}
}
@Override
public void writeToNBT(NBTTagCompound nbtTag) {
super.writeToNBT(nbtTag);
storeCustomUpdate(nbtTag);
NBTTagList itemsStored = new NBTTagList();
for (int a = 0; a < getSizeInventory(); a++) {
ItemStack s = getStackInSlot(a);
if (s != null) {
NBTTagCompound tag = new NBTTagCompound();
tag.setByte("Slot", (byte) a);
s.writeToNBT(tag);
itemsStored.appendTag(tag);
}
}
nbtTag.setTag("Items", itemsStored);
}
public EquipmentRecipe getRecipe() {
return recipe;
}
private static final String heatStrID = "heatStrength";
private static final String heatFromItemID = "heatFromItem";
private static final String heatLengthID = "heatLength";
private static final String heatLengthInitID = "heatLengthInit";
private static final String itemSmeltDurationID = "itemSmeltDuration";
private static final String workingID = "workingID";
private static final String recipeTypeID = "recipeType";
private static final String recipeIDID = "recipeID";
@Override
public void storeCustomUpdate(NBTTagCompound nbtTag) {
nbtTag.setInteger(heatStrID, heatStrength);
nbtTag.setInteger(heatFromItemID, heatFromItem);
nbtTag.setInteger(heatLengthID, heatLength);
nbtTag.setInteger(heatLengthInitID, heatLengthInit);
nbtTag.setInteger(itemSmeltDurationID, itemSmeltDuration);
nbtTag.setBoolean(workingID, TileHunterBench.this.workingMHFCBench);
RecipeType type = recipe != null
? recipe.getRecipeType()
: RecipeType.MHFC;
int recipeID = MHFCEquipementRecipeRegistry.getIDFor(recipe);
nbtTag.setInteger(recipeTypeID, type.ordinal());
nbtTag.setInteger(recipeIDID, recipeID);
}
@Override
public void readCustomUpdate(NBTTagCompound nbtTag) {
heatStrength = nbtTag.getInteger(heatStrID);
heatFromItem = nbtTag.getInteger(heatFromItemID);
heatLength = nbtTag.getInteger(heatLengthID);
heatLengthInit = nbtTag.getInteger(heatLengthInitID);
itemSmeltDuration = nbtTag.getInteger(itemSmeltDurationID);
TileHunterBench.this.workingMHFCBench = nbtTag.getBoolean(workingID);
int irecType = nbtTag.getInteger(recipeTypeID);
int recId = nbtTag.getInteger(recipeIDID);
RecipeType recType = RecipeType.values()[irecType];
setRecipe(MHFCEquipementRecipeRegistry.getRecipeFor(recId, recType));
}
}