package slimeknights.tconstruct.smeltery.tileentity;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.item.ItemFood;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.FurnaceRecipes;
import net.minecraft.util.ITickable;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.apache.logging.log4j.Logger;
import java.util.List;
import javax.annotation.Nonnull;
import slimeknights.mantle.common.IInventoryGui;
import slimeknights.tconstruct.library.Util;
import slimeknights.tconstruct.smeltery.client.GuiSearedFurnace;
import slimeknights.tconstruct.smeltery.inventory.ContainerSearedFurnace;
import slimeknights.tconstruct.smeltery.multiblock.MultiblockSearedFurnace;
public class TileSearedFurnace extends TileHeatingStructureFuelTank<MultiblockSearedFurnace> implements ITickable, IInventoryGui {
public static final Logger log = Util.getLogger("Furnace");
protected int tick;
public TileSearedFurnace() {
super("gui.searedfurnace.name", 0, 16);
setMultiblock(new MultiblockSearedFurnace(this));
}
@Override
public void update() {
if(isClientWorld()) {
return;
}
// are we fully formed?
if(!isActive()) {
// check for furnace once per second
if(tick == 0) {
checkMultiblockStructure();
}
}
else {
// we have a lot less to do than a smeltery since the inside is unreachable and we have no liquids
// basically just heating and fuel consumption
// we heat items every tick, as otherwise we are quite slow compared to a vanilla furnace
if(tick % 4 == 0) {
heatItems();
}
if(tick == 0) {
interactWithEntitiesInside();
}
if(needsFuel) {
consumeFuel();
}
// we don't check the inside for obstructions since it should not be possible unless the outside was modified
}
tick = (tick + 1) % 20;
}
/* Grabs the heat for a furnace */
@Override
protected void updateHeatRequired(int index) {
ItemStack stack = getStackInSlot(index);
if(stack != null) {
ItemStack result = FurnaceRecipes.instance().getSmeltingResult(stack);
if(result != null) {
int newSize = stack.stackSize * result.stackSize;
if(newSize <= stack.getMaxStackSize() && newSize <= getInventoryStackLimit()) {
// we like our steaks medium rare :)
setHeatRequiredForSlot(index, getHeatForStack(stack, result));
}
else {
// if its too big, set the error state
itemTemperatures[index] = -1;
}
// instantly consume fuel if required
if(!hasFuel()) {
consumeFuel();
}
return;
}
}
setHeatRequiredForSlot(index, 0);
}
/**
* Returns the heat required to smelt the itemstack
*
* @param input Input stack
* @param result Output stack, here just for conveince so we don't have to index it twice
* @return A number representing the time
*/
private int getHeatForStack(@Nonnull ItemStack input, @Nonnull ItemStack result) {
// base stack temp, here in case Forge adds a hook
int base = 200;
float temp = base * input.stackSize / 4f;
// adjust the speed based on if its a food or not
// after adjustment with the base of 200, we get a temp of 160 for foods, though its slightly faster than that due to TileHeatingStructure logic
if(result.getItem() instanceof ItemFood) {
temp *= 0.8;
}
return (int) temp;
}
// melt stuff
@Override
protected boolean onItemFinishedHeating(ItemStack stack, int slot) {
ItemStack result = FurnaceRecipes.instance().getSmeltingResult(stack);
if(result == null) {
// recipe changed mid smelting...
return false;
}
// remember, we can smelt a whole stack at once
result = result.copy();
result.stackSize *= stack.stackSize;
setInventorySlotContents(slot, result);
// we set to 1 so we get positive infinity instead of NaN for progress, since NaN is already defined as no recipe
itemTemperatures[slot] = 1;
itemTempRequired[slot] = 0;
// we return false since the itemstack does not leave the slot, otherwise any data we set here is lost (which really would just be the temp)
return false;
}
@Override
protected int getUpdatedInventorySize(int width, int height, int depth) {
return 9 + (3 * width * height * depth);
}
protected void interactWithEntitiesInside() {
// find all monsters within the furnace and kill them
AxisAlignedBB bb = info.getBoundingBox().contract(1).offset(0, 0.5, 0).expand(0, 0.5, 0);
List<EntityLivingBase> entities = getWorld().getEntitiesWithinAABB(EntityLivingBase.class, bb);
for(EntityLivingBase entity : entities) {
if(entity instanceof EntityMob && entity.isEntityAlive()) {
entity.setDead();
}
}
}
/* GUI */
@Override
public Container createContainer(InventoryPlayer inventoryplayer, World world, BlockPos pos) {
return new ContainerSearedFurnace(inventoryplayer, this);
}
@Override
@SideOnly(Side.CLIENT)
public GuiContainer createGui(InventoryPlayer inventoryplayer, World world, BlockPos pos) {
return new GuiSearedFurnace((ContainerSearedFurnace) createContainer(inventoryplayer, world, pos), this);
}
}