Below are tutorials for different furnace type blocks. First will be a basic furnace, and then in no particular order, a double furnace, a two input furnace and a lava fueled furnace. I know that I had a tutorial for this once before and tomtomg99 had one for 1.5.x which was just fine and worked well. He hasn't updated his tutorial for this yet so I decided with as many help requests as I have seen on this forum alone I would post one again. Please DO NOT flood my PM box with requests for help, that is what this thread is for, if I dont reply, someone else may. You could also use the forum dev section for help, #irc chat boards and other forums for help if you get stuck.
The furnace requires only a few files like the crafting table, some are not even necessary. Depending on the type of furnace you are trying to code, your files may vary and even require more or less files. However they will all need a mod class and a block class and a GUI Handler.
This is now a video tutorial so please pay close attention and excuse my arrogance in my tone of voice. After viewing this tutorial it should help you understand where many of the mistakes have been made and why some things just done work for you....
This is a five part series for the basic furnace and I feel I have covered every thing necessary to make this work, every class is explained....
Part 1
Part 2
Part 3
Part 4
Part 5
GUI Handler
This is a very important class here, this is absolutely necessary to have if you actually intend to open your blocks GUI
public class GuiHandlerFurnace implements IGuiHandler
{
@Override
public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z)
{
TileEntity tile_entity = world.getBlockTileEntity(x, y, z);
switch(id)
{
case 0: return new ContainerSmoker(player.inventory, (TileEntitySmoker) tile_entity);
}
return null;
}
@Override
public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z)
{
TileEntity tile_entity = world.getBlockTileEntity(x, y, z);
switch(id)
{
case 0: return new GuiSmoker(player.inventory, (TileEntitySmoker) tile_entity);
}
return null;
}
}
Render Class
public class RenderSmoker implements ISimpleBlockRenderingHandler
{
public static final RenderSmoker INSTANCE = new RenderSmoker();
@Override
public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer)
{
int meta=3;
if(block.blockID == FurnaceTutorial.smokerActive.blockID)meta=1;
Tessellator tessellator = Tessellator.instance;
block.setBlockBoundsForItemRender();
renderer.setRenderBoundsFromBlock(block);
GL11.glRotatef(90.0F, 0.0F, 1.0F, 0.0F);
GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
tessellator.startDrawingQuads();
tessellator.setNormal(0.0F, -1.0F, 0.0F);
renderer.renderFaceYNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 0, meta));
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.setNormal(0.0F, 1.0F, 0.0F);
renderer.renderFaceYPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 1, meta));
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.setNormal(0.0F, 0.0F, -1.0F);
renderer.renderFaceZNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 2, meta));
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.setNormal(0.0F, 0.0F, 1.0F);
renderer.renderFaceZPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 3, meta));
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.setNormal(-1.0F, 0.0F, 0.0F);
renderer.renderFaceXNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 4, meta));
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.setNormal(1.0F, 0.0F, 0.0F);
renderer.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 5, meta));
tessellator.draw();
GL11.glTranslatef(0.5F, 0.5F, 0.5F);
}
@Override
public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer)
{
int direction = renderer.blockAccess.getBlockMetadata(x, y, z) & 3;
if(direction>0)
renderer.uvRotateTop = direction-1;
else
renderer.uvRotateTop = 3;
boolean flag = renderer.renderStandardBlock(block, x, y, z);
renderer.uvRotateTop = 0;
return flag;
}
@Override
public boolean shouldRender3DInInventory()
{
return true;
}
@Override
public int getRenderId()
{
return 2105;
}
}
This is basically two furnaces in one. Its efficient and hey, it lets you smelt more than one object at a time so why not. I honestly feel mojang is missing the point on some things. They seem to keep adding in more and more mods that people have made as opposed to improving the stuff they already have in the game. Furnace upgrades and crafting table upgrades are something that needs to be looked at, even if they are only upgradeable based on XP levels. At any rate, enough rambling.....
I will try to come back later and post some highlights and comments on the code here, for now I will only post the necessary classes needed for this to happen....
Container
import java.util.List;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.ICrafting;
import net.minecraft.inventory.Slot;
import net.minecraft.inventory.SlotFurnace;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.FurnaceRecipes;
public class ContainerLargeFurnace extends Container
{
private TileEntityLargeFurnace telf;
public int furnaceBurnTime = 0;
public int currentItemBurnTime = 0;
public int furnaceCookTime1 = 0;
public int furnaceCookTime2 = 0;
public ContainerLargeFurnace(InventoryPlayer par1InventoryPlayer, TileEntityLargeFurnace par2TileEntityLargeFurnace)
{
this.telf = par2TileEntityLargeFurnace;
this.addSlotToContainer(new Slot(par2TileEntityLargeFurnace, 0, 52, 15));
this.addSlotToContainer(new Slot(par2TileEntityLargeFurnace, 1, 52, 57));
this.addSlotToContainer(new SlotFurnace(par1InventoryPlayer.player, par2TileEntityLargeFurnace, 2, 108, 15));
this.addSlotToContainer(new Slot(par2TileEntityLargeFurnace, 3, 52, 33));
this.addSlotToContainer(new SlotFurnace(par1InventoryPlayer.player, par2TileEntityLargeFurnace, 4, 108, 33));
for(int i = 0; i < 3; i++)
{
for(int k = 0; k < 9; k++)
{
this.addSlotToContainer(new Slot(par1InventoryPlayer, k + i * 9 + 9, 8 + k * 18, 84 + i * 18));
}
}
for(int j = 0; j < 9; j++)
{
this.addSlotToContainer(new Slot(par1InventoryPlayer, j, 8 + j * 18, 142));
}
}
public void addCraftingToCrafters(ICrafting par1ICrafting)
{
super.addCraftingToCrafters(par1ICrafting);
par1ICrafting.sendProgressBarUpdate(this, 0, this.telf.furnaceCookTime1);
par1ICrafting.sendProgressBarUpdate(this, 1, this.telf.furnaceBurnTime);
par1ICrafting.sendProgressBarUpdate(this, 2, this.telf.currentItemBurnTime);
par1ICrafting.sendProgressBarUpdate(this, 3, this.telf.furnaceCookTime2);
}
/**
* Looks for changes made in the container, sends them to every listener.
*/
public void detectAndSendChanges()
{
super.detectAndSendChanges();
for (int var1 = 0; var1 < this.crafters.size(); ++var1)
{
ICrafting var2 = (ICrafting)this.crafters.get(var1);
if(furnaceBurnTime != telf.furnaceBurnTime)
{
var2.sendProgressBarUpdate(this, 1, telf.furnaceBurnTime);
}
if(currentItemBurnTime != telf.currentItemBurnTime)
{
var2.sendProgressBarUpdate(this, 2, telf.currentItemBurnTime);
}
if(furnaceCookTime1 != telf.furnaceCookTime1)
{
var2.sendProgressBarUpdate(this, 0, telf.furnaceCookTime1);
}
if(furnaceCookTime2 != telf.furnaceCookTime2)
{
var2.sendProgressBarUpdate(this, 3, telf.furnaceCookTime2);
}
}
this.furnaceCookTime1 = this.telf.furnaceCookTime1;
this.furnaceCookTime2 = this.telf.furnaceCookTime2;
this.furnaceBurnTime = this.telf.furnaceBurnTime;
this.currentItemBurnTime = this.telf.currentItemBurnTime;
}
@SideOnly(Side.CLIENT)
public void updateProgressBar(int par1, int par2)
{
if(par1 == 0)
{
telf.furnaceCookTime1 = par2;
}
if(par1 == 1)
{
telf.furnaceBurnTime = par2;
}
if(par1 == 2)
{
telf.currentItemBurnTime = par2;
}
if(par1 == 3)
{
telf.furnaceCookTime2 = par2;
}
}
public boolean canInteractWith(EntityPlayer par1EntityPlayer)
{
return this.telf.isUseableByPlayer(par1EntityPlayer);
}
/**
* Called when a player shift-clicks on a slot. You must override this or you will crash when someone does that.
*/
public ItemStack transferStackInSlot(EntityPlayer par1EntityPlayer, int par2)
{
ItemStack var3 = null;
Slot var4 = (Slot)this.inventorySlots.get(par2);
if (var4 != null && var4.getHasStack())
{
ItemStack var5 = var4.getStack();
var3 = var5.copy();
if (par2 == 2)
{
if (!this.mergeItemStack(var5, 3, 39, true))
{
return null;
}
var4.onSlotChange(var5, var3);
}
else if (par2 != 1 && par2 != 0)
{
if (FurnaceRecipes.smelting().getSmeltingResult(var5) != null)
{
if (!this.mergeItemStack(var5, 0, 1, false))
{
return null;
}
}
else if (TileEntityLargeFurnace.isItemFuel(var5))
{
if (!this.mergeItemStack(var5, 1, 2, false))
{
return null;
}
}
else if (par2 >= 3 && par2 < 30)
{
if (!this.mergeItemStack(var5, 30, 39, false))
{
return null;
}
}
else if (par2 >= 30 && par2 < 39 && !this.mergeItemStack(var5, 3, 30, false))
{
return null;
}
}
else if (!this.mergeItemStack(var5, 3, 39, false))
{
return null;
}
if (var5.stackSize == 0)
{
var4.putStack((ItemStack)null);
}
else
{
var4.onSlotChanged();
}
if (var5.stackSize == var3.stackSize)
{
return null;
}
var4.onPickupFromSlot(par1EntityPlayer, var5);
}
return var3;
}
}
Gui
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
import org.lwjgl.opengl.GL11;
public class GuiLargeFurnace extends GuiContainer
{
private ResourceLocation largeFurnace = new ResourceLocation("textures/largefurnace/textures/gui/largeFurnaceGui.png");
private TileEntityLargeFurnace furnaceInventory;
private ArrayList telfs;
public GuiLargeFurnace(InventoryPlayer inventoryplayer, TileEntityLargeFurnace tileentitylargefurnace, ArrayList arraylist)
{
super(new ContainerLargeFurnace(inventoryplayer, tileentitylargefurnace));
telfs = arraylist;
furnaceInventory = tileentitylargefurnace;
}
protected void drawGuiContainerForegroundLayer(int par1, int par2)
{
fontRenderer.drawString(StatCollector.translateToLocal("Large Furnace"), 50, 4, 0x404040);
fontRenderer.drawString(StatCollector.translateToLocal("Inventory"), 7, (ySize - 94) + 2, 0x404040);
}
protected void drawGuiContainerBackgroundLayer(float f, int var1, int var2)
{
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
mc.renderEngine.func_110577_a(largeFurnace);
int j = (width - xSize) / 2;
int k = (height - ySize) / 2;
drawTexturedModalRect(j, k, 0, 0, xSize, ySize);
if(furnaceInventory.isBurning())
{
int l = furnaceInventory.getBurnTimeRemainingScaled(12);
drawTexturedModalRect(j + 82, (k + 71) - l, 176, 12 - l, 14, l + 2);
}
int i1 = furnaceInventory.getCookProgressScaled(24, 0);
int j1 = furnaceInventory.getCookProgressScaled(24, 1);
drawTexturedModalRect(j + 77, k + 34, 176, 14, j1 + 1, 16);
drawTexturedModalRect(j + 77, k + 15, 176, 14, i1 + 1, 16);
}
}
With these added classes and the block, handler and mod classes above you will now have a double furnace. Review the code here within and you can make anything like this or bigger, 3, 4, or even 6 furnaces in one.
So, for the furnace changes when making the furnace do different things and not unlike the crafting table tutorial I have posted as well, you make changes only in a few places and usually not in the block class. So for the Lava Furnace, as in the Double Furnace and in the Dual Input Furnace, I will only be posting relevant code changes for you to follow.
Container
package bcblocks.lavafurnace.lava;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.ICrafting;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.FurnaceRecipes;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class ContainerLavaFurnace extends Container
{
private TileEntityLavaFurnace lava;
private int lastCookTime = 0;
private int lastBurnTime = 0;
private int lastItemBurnTime = 0;
public ContainerLavaFurnace(InventoryPlayer inventoryplayer, TileEntityLavaFurnace tileentityLavaFurnace)
{
lava = tileentityLavaFurnace;
this.addSlotToContainer(new Slot(tileentityLavaFurnace, 0, 56, 27));
this.addSlotToContainer(new SlotLavaFurnace(inventoryplayer.player, tileentityLavaFurnace, 2, 116, 35));
for (int i = 0; i < 3; i++)
{
for (int k = 0; k < 9; k++)
{
this.addSlotToContainer(new Slot(inventoryplayer, k + i * 9 + 9, 8 + k * 18, 84 + i * 18));
}
}
for (int j = 0; j < 9; j++)
{
this.addSlotToContainer(new Slot(inventoryplayer, j, 8 + j * 18, 142));
}
}
public void addCraftingToCrafters(ICrafting par1ICrafting)
{
super.addCraftingToCrafters(par1ICrafting);
par1ICrafting.sendProgressBarUpdate(this, 0, this.lava.furnaceCookTime);
par1ICrafting.sendProgressBarUpdate(this, 1, this.lava.furnaceBurnTime);
par1ICrafting.sendProgressBarUpdate(this, 2, this.lava.currentItemBurnTime);
}
public void detectAndSendChanges()
{
super.detectAndSendChanges();
for (int var1 = 0; var1 < this.crafters.size(); ++var1)
{
ICrafting var2 = (ICrafting)this.crafters.get(var1);
if (this.lastCookTime != this.lava.furnaceCookTime)
{
var2.sendProgressBarUpdate(this, 0, this.lava.furnaceCookTime);
}
if (this.lastBurnTime != this.lava.furnaceBurnTime)
{
var2.sendProgressBarUpdate(this, 1, this.lava.furnaceBurnTime);
}
if (this.lastItemBurnTime != this.lava.currentItemBurnTime)
{
var2.sendProgressBarUpdate(this, 2, this.lava.currentItemBurnTime);
}
}
lastCookTime = lava.furnaceCookTime;
lastBurnTime = lava.furnaceBurnTime;
lastItemBurnTime = lava.currentItemBurnTime;
}
@SideOnly(Side.CLIENT)
public void updateProgressBar(int par1, int par2)
{
if (par1 == 0)
{
this.lava.furnaceCookTime = par2;
}
if (par1 == 1)
{
this.lava.furnaceBurnTime = par2;
}
if (par1 == 2)
{
this.lava.currentItemBurnTime = par2;
}
}
public boolean canInteractWith(EntityPlayer entityplayer)
{
return lava.isUseableByPlayer(entityplayer);
}
public ItemStack transferStackInSlot(EntityPlayer par1EntityPlayer, int par2)
{
ItemStack itemstack = null;
Slot slot = (Slot)this.inventorySlots.get(par2);
if (slot != null && slot.getHasStack())
{
ItemStack itemstack1 = slot.getStack();
itemstack = itemstack1.copy();
if (par2 == 2)
{
if (!mergeItemStack(itemstack1, 3, 39, true))
{
return null;
}
}
else if (par2 >= 3 && par2 < 30)
{
if (!mergeItemStack(itemstack1, 30, 39, false))
{
return null;
}
}
else if (par2 >= 30 && par2 < 39)
{
if (!mergeItemStack(itemstack1, 3, 30, false))
{
return null;
}
}
else if (!mergeItemStack(itemstack1, 3, 39, false))
{
return null;
}
if (itemstack1.stackSize == 0)
{
slot.putStack(null);
}
else
{
slot.onSlotChanged();
}
if (itemstack1.stackSize != itemstack.stackSize)
{
slot.onPickupFromSlot(par1EntityPlayer, itemstack1);
}
else
{
return null;
}
}
return itemstack;
}
}
Tile Entity
package bcblocks.lavafurnace.lava;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
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.inventory.ISidedInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.FurnaceRecipes;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeDirection;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class TileEntityLavaFurnace extends TileEntity implements IInventory, ISidedInventory
{
private ItemStack[] furnaceItemStacks = new ItemStack[3];
public int furnaceBurnTime = 1000;
public int currentItemBurnTime = 0;
public int furnaceCookTime = 0;
public int maxCookTime = 250;
private Minecraft minecraft;
private String customName;
public int getSizeInventory()
{
return this.furnaceItemStacks.length;
}
public ItemStack getStackInSlot(int par1)
{
return this.furnaceItemStacks[par1];
}
public boolean isRedPowered()
{
World world = minecraft.getMinecraft().theWorld;
return world.getBlockId(xCoord, yCoord - 1, zCoord) == Block.lavaStill.blockID || world.getBlockId(xCoord, yCoord - 1, zCoord) == Block.lavaMoving.blockID;
}
public ItemStack decrStackSize(int par1, int par2)
{
if (this.furnaceItemStacks[par1] != null)
{
ItemStack var3;
if (this.furnaceItemStacks[par1].stackSize <= par2)
{
var3 = this.furnaceItemStacks[par1];
this.furnaceItemStacks[par1] = null;
return var3;
}
else
{
var3 = this.furnaceItemStacks[par1].splitStack(par2);
if (this.furnaceItemStacks[par1].stackSize == 0)
{
this.furnaceItemStacks[par1] = null;
}
return var3;
}
}
else
{
return null;
}
}
/**
* 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.
*/
public ItemStack getStackInSlotOnClosing(int par1)
{
if (this.furnaceItemStacks[par1] != null)
{
ItemStack var2 = this.furnaceItemStacks[par1];
this.furnaceItemStacks[par1] = null;
return var2;
}
else
{
return null;
}
}
/**
* Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections).
*/
public void setInventorySlotContents(int par1, ItemStack par2ItemStack)
{
this.furnaceItemStacks[par1] = par2ItemStack;
if (par2ItemStack != null && par2ItemStack.stackSize > this.getInventoryStackLimit())
{
par2ItemStack.stackSize = this.getInventoryStackLimit();
}
}
/**
* Returns the name of the inventory.
*/
public String getInvName()
{
return "lava_furnace";
}
/**
* Reads a tile entity from NBT.
*/
public void readFromNBT(NBTTagCompound par1NBTTagCompound)
{
super.readFromNBT(par1NBTTagCompound);
NBTTagList var2 = par1NBTTagCompound.getTagList("Items");
this.furnaceItemStacks = new ItemStack[this.getSizeInventory()];
for (int var3 = 0; var3 < var2.tagCount(); ++var3)
{
NBTTagCompound var4 = (NBTTagCompound)var2.tagAt(var3);
byte var5 = var4.getByte("Slot");
if (var5 >= 0 && var5 < this.furnaceItemStacks.length)
{
this.furnaceItemStacks[var5] = ItemStack.loadItemStackFromNBT(var4);
}
}
this.furnaceBurnTime = par1NBTTagCompound.getShort("BurnTime");
this.furnaceCookTime = par1NBTTagCompound.getShort("CookTime");
this.currentItemBurnTime = getItemBurnTime(this.furnaceItemStacks[1]);
}
/**
* Writes a tile entity to NBT.
*/
public void writeToNBT(NBTTagCompound par1NBTTagCompound)
{
super.writeToNBT(par1NBTTagCompound);
par1NBTTagCompound.setShort("BurnTime", (short)this.furnaceBurnTime);
par1NBTTagCompound.setShort("CookTime", (short)this.furnaceCookTime);
NBTTagList var2 = new NBTTagList();
for (int var3 = 0; var3 < this.furnaceItemStacks.length; ++var3)
{
if (this.furnaceItemStacks[var3] != null)
{
NBTTagCompound var4 = new NBTTagCompound();
var4.setByte("Slot", (byte)var3);
this.furnaceItemStacks[var3].writeToNBT(var4);
var2.appendTag(var4);
}
}
par1NBTTagCompound.setTag("Items", var2);
}
/**
* Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't
* this more of a set than a get?*
*/
public int getInventoryStackLimit()
{
return 64;
}
@SideOnly(Side.CLIENT)
/**
* Returns an integer between 0 and the passed value representing how close the current item is to being completely
* cooked
*/
public int getCookProgressScaled(int par1)
{
return (furnaceCookTime * par1) / maxCookTime;
}
@SideOnly(Side.CLIENT)
/**
* 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
*/
public int getBurnTimeRemainingScaled(int par1)
{
if (currentItemBurnTime == 0)
{
currentItemBurnTime = maxCookTime;
}
return (furnaceBurnTime * par1) / currentItemBurnTime;
}
/**
* Returns true if the furnace is currently burning
*/
public boolean isBurning()
{
return this.furnaceBurnTime > 0;
}
/**
* Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count
* ticks and creates a new spawn inside its implementation.
*/
public void updateEntity()
{
boolean flag = furnaceBurnTime > 0;
boolean flag1 = false;
if (!isRedPowered())
{
furnaceBurnTime = 0;
BlockLavaFurnace.updateFurnaceBlockState(false, worldObj, xCoord, yCoord, zCoord);
}
else if (isRedPowered())
{
furnaceBurnTime = 1000;
}
if (canSmelt())
{
currentItemBurnTime = furnaceBurnTime = getItemBurnTime(furnaceItemStacks[1]);
if (furnaceBurnTime > 0)
{
flag1 = true;
if (furnaceItemStacks[1] != null)
{
if (furnaceItemStacks[1].getItem().hasContainerItem())
{
furnaceItemStacks[1] = new ItemStack(furnaceItemStacks[1].getItem().getContainerItem());
}
else
{
furnaceItemStacks[1].stackSize--;
}
if (furnaceItemStacks[1].stackSize == 0)
{
furnaceItemStacks[1] = null;
}
}
}
}
if (isBurning() && canSmelt())
{
furnaceCookTime++;
BlockLavaFurnace.updateFurnaceBlockState(true, worldObj, xCoord, yCoord, zCoord);
if (furnaceCookTime == maxCookTime)
{
furnaceCookTime = 0;
BlockLavaFurnace.updateFurnaceBlockState(false, worldObj, xCoord, yCoord, zCoord);
smeltItem();
flag1 = true;
}
}
else
{
furnaceCookTime = 0;
}
if (flag1)
{
onInventoryChanged();
}
}
/**
* Returns true if the furnace can smelt an item, i.e. has a source item, destination stack isn't full, etc.
*/
private boolean canSmelt()
{
if (furnaceItemStacks[0] == null)
{
return false;
}
ItemStack itemstack = FurnaceRecipes.smelting().getSmeltingResult(furnaceItemStacks[0].getItem().itemID);
if (itemstack == null)
{
return false;
}
if (furnaceItemStacks[2] == null)
{
return true;
}
if (!furnaceItemStacks[2].isItemEqual(itemstack))
{
return false;
}
if (furnaceItemStacks[2].stackSize < getInventoryStackLimit() && furnaceItemStacks[2].stackSize < furnaceItemStacks[2].getMaxStackSize())
{
return true;
}
else
{
return furnaceItemStacks[2].stackSize < itemstack.getMaxStackSize();
}
}
/**
* Turn one item from the furnace source stack into the appropriate smelted item in the furnace result stack
*/
public void smeltItem()
{
if (!canSmelt())
{
return;
}
ItemStack itemstack = FurnaceRecipes.smelting().getSmeltingResult(furnaceItemStacks[0].getItem().itemID);
if (furnaceItemStacks[2] == null)
{
furnaceItemStacks[2] = itemstack.copy();
}
else if (furnaceItemStacks[2].itemID == itemstack.itemID)
{
furnaceItemStacks[2].stackSize += itemstack.stackSize;
}
if (furnaceItemStacks[0].getItem().hasContainerItem())
{
furnaceItemStacks[0] = new ItemStack(furnaceItemStacks[0].getItem().getContainerItem());
}
else
{
furnaceItemStacks[0].stackSize--;
}
if (furnaceItemStacks[0].stackSize <= 0)
{
furnaceItemStacks[0] = null;
}
}
/**
* Returns the number of ticks that the supplied fuel item will keep the furnace burning, or 0 if the item isn't
* fuel
*/
public int getItemBurnTime(ItemStack par0ItemStack)
{
return !isRedPowered() ? 0 : 1000;
}
/**
* Return true if item is a fuel source (getItemBurnTime() > 0).
*/
public boolean isItemFuel(ItemStack par0ItemStack)
{
return getItemBurnTime(par0ItemStack) > 0;
}
/**
* Do not make give this method the name canInteractWith because it clashes with Container
*/
public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer)
{
return this.worldObj.getBlockTileEntity(this.xCoord, this.yCoord, this.zCoord) != this ? false : par1EntityPlayer.getDistanceSq((double)this.xCoord + 0.5D, (double)this.yCoord + 0.5D, (double)this.zCoord + 0.5D) <= 64.0D;
}
public void openChest() {}
public void closeChest() {}
@Override
public boolean isInvNameLocalized()
{
return (this.customName != null) && (this.customName.length() > 0);
}
public void setCustomName(String name)
{
this.customName = name;
}
@Override
public int[] getAccessibleSlotsFromSide(int var1) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean canInsertItem(int i, ItemStack itemstack, int j) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean canExtractItem(int i, ItemStack itemstack, int j) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isItemValidForSlot(int i, ItemStack itemstack) {
return false;
}
}
Gui
package bcblocks.lavafurnace.lava;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
import org.lwjgl.opengl.GL11;
public class GuiLavaFurnace extends GuiContainer
{
private ResourceLocation spf = new ResourceLocation("textures/lavafurnace/textures/gui/lavafurnace.png");
private TileEntityLavaFurnace furnaceInventory;
public GuiLavaFurnace(InventoryPlayer inventoryplayer, TileEntityLavaFurnace tileentityLavaFurnace)
{
super(new ContainerLavaFurnace(inventoryplayer, tileentityLavaFurnace));
furnaceInventory = tileentityLavaFurnace;
}
/**
* Draw the foreground layer for the GuiContainer (everythin in front of the items)
*/
protected void drawGuiContainerForegroundLayer()
{
fontRenderer.drawString("Lava Furnace", 60, 6, 0x404040);
fontRenderer.drawString("Inventory", 8, (ySize - 96) + 2, 0x404040);
}
/**
* Draw the background layer for the GuiContainer (everything behind the items)
*/
protected void drawGuiContainerBackgroundLayer(float f, int i, int j)
{
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
mc.renderEngine.func_110577_a(spf);
int l = (width - xSize) / 2;
int i1 = (height - ySize) / 2;
drawTexturedModalRect(l, i1, 0, 0, xSize, ySize);
if (furnaceInventory.isBurning())
{
int j1 = furnaceInventory.getBurnTimeRemainingScaled(12);
drawTexturedModalRect(l + 57, (i1 + 36 + 22) - j1, 176, 12 - j1, 14, j1 + 2);
}
int k1 = furnaceInventory.getCookProgressScaled(24);
drawTexturedModalRect(l + 79, i1 + 34, 176, 14, k1 + 1, 16);
}
}
Slot
package bcblocks.lavafurnace.lavacare;
import net.minecraft.entity.item.EntityXPOrb;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.FurnaceRecipes;
import net.minecraft.stats.AchievementList;
import net.minecraft.util.MathHelper;
import cpw.mods.fml.common.registry.GameRegistry;
public class SlotLavaFurnace extends Slot
{
public SlotLavaFurnace(EntityPlayer entityplayer, IInventory iinventory, int i, int j, int k)
{
super(iinventory, i, j, k);
}
/**
* Check if the stack is a valid item for this slot. Always true beside for the armor slots.
*/
public boolean isItemValid(ItemStack itemstack)
{
return false;
}
/**
* Called when the player picks up an item from an inventory slot
*/
public void onPickupFromSlot(EntityPlayer par1EntityPlayer, ItemStack par2ItemStack)
{
this.onCrafting(par2ItemStack);
super.onPickupFromSlot(par1EntityPlayer, par2ItemStack);
}
}
This is one way to make the all important 2 input furnace that everyone seems to seek out. This code works just fine, may not be the best way to do this but it works for me. I have gathered as much info as I can find and sifted through a ton of non working code for this. Basically the credit for this goes to the community because that is the source I used for the code, though most of it didnt work. Another thought, I am not actually using this in any mod, mostly because I dont want to code an entire mod around this. This is mostly for those who have a mod with an intended two input furnace. Therefore feel free to use this code for any needs you may have, however I will not be able to help you solve too many issues with this code.
Container
import java.util.List;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.ICrafting;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
public class ContainerInputFurnace extends Container
{
private TileEntityInputFurnace blast;
private int dualCookTime;
private int dualBurnTime;
private int lastItemBurnTime;
public ContainerInputFurnace(InventoryPlayer inventoryplayer, TileEntityInputFurnace tileentityInputFurnace)
{
dualCookTime = 0;
dualBurnTime = 0;
lastItemBurnTime = 0;
blast = tileentityInputFurnace;
this.addSlotToContainer(new Slot(tileentityInputFurnace, 0, 38, 17));
this.addSlotToContainer(new Slot(tileentityInputFurnace, 1, 74, 17));
this.addSlotToContainer(new Slot(tileentityInputFurnace, 2, 56, 53));
this.addSlotToContainer(new SlotInputFurnace(inventoryplayer.player, tileentityInputFurnace, 3, 116, 35));
for (int i = 0; i < 3; i++)
{
for (int k = 0; k < 9; k++)
{
this.addSlotToContainer(new Slot(inventoryplayer, k + i * 9 + 9, 8 + k * 18, 84 + i * 18));
}
}
for (int j = 0; j < 9; j++)
{
this.addSlotToContainer(new Slot(inventoryplayer, j, 8 + j * 18, 142));
}
}
public void addCraftingToCrafters(ICrafting par1ICrafting)
{
super.addCraftingToCrafters(par1ICrafting);
par1ICrafting.sendProgressBarUpdate(this, 0, this.blast.dualCookTime);
par1ICrafting.sendProgressBarUpdate(this, 1, this.blast.dualBurnTime);
par1ICrafting.sendProgressBarUpdate(this, 2, this.blast.currentItemBurnTime);
}
/**
* Looks for changes made in the container, sends them to every listener.
*/
public void detectAndSendChanges()
{
super.detectAndSendChanges();
for (int var1 = 0; var1 < this.crafters.size(); ++var1)
{
ICrafting var2 = (ICrafting)this.crafters.get(var1);
if (this.dualCookTime != this.blast.dualCookTime)
{
var2.sendProgressBarUpdate(this, 0, this.blast.dualCookTime);
}
if (this.dualBurnTime != this.blast.dualBurnTime)
{
var2.sendProgressBarUpdate(this, 1, this.blast.dualBurnTime);
}
if (this.lastItemBurnTime != this.blast.currentItemBurnTime)
{
var2.sendProgressBarUpdate(this, 2, this.blast.currentItemBurnTime);
}
}
this.dualCookTime = this.blast.dualCookTime;
this.dualBurnTime = this.blast.dualBurnTime;
this.lastItemBurnTime = this.blast.currentItemBurnTime;
}
public void updateProgressBar(int i, int j)
{
if (i == 0)
{
blast.dualCookTime = j;
}
if (i == 1)
{
blast.dualBurnTime = j;
}
if (i == 2)
{
blast.currentItemBurnTime = j;
}
}
/**
* Called to transfer a stack from one inventory to the other eg. when shift clicking.
*/
public ItemStack transferStackInSlot(EntityPlayer par1EntityPlayer, int par2)
{
ItemStack itemstack = null;
Slot slot = (Slot)inventorySlots.get(par2);
if (slot != null && slot.getHasStack())
{
ItemStack itemstack1 = slot.getStack();
itemstack = itemstack1.copy();
if (par2 == 2)
{
if (!mergeItemStack(itemstack1, 3, 39, true))
{
return null;
}
}
else if (par2 >= 3 && par2 < 30)
{
if (!mergeItemStack(itemstack1, 30, 39, false))
{
return null;
}
}
else if (par2 >= 30 && par2 < 39)
{
if (!mergeItemStack(itemstack1, 3, 30, false))
{
return null;
}
}
else if (!mergeItemStack(itemstack1, 3, 39, false))
{
return null;
}
if (itemstack1.stackSize == 0)
{
slot.putStack(null);
}
else
{
slot.onSlotChanged();
}
if (itemstack1.stackSize != itemstack.stackSize)
{
slot.onPickupFromSlot(par1EntityPlayer, itemstack1);
}
else
{
return null;
}
}
return itemstack;
}
public boolean canInteractWith(EntityPlayer entityplayer)
{
return blast.isUseableByPlayer(entityplayer);
}
}
GUI
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
import org.lwjgl.opengl.GL11;
public class GuiInputFurnace extends GuiContainer
{
private ResourceLocation tif = new ResourceLocation("textures/inputfurnace/textures/gui/tifGUI.png");
private TileEntityInputFurnace inputFurnaceInventory;
public GuiInputFurnace(InventoryPlayer inventoryplayer, TileEntityInputFurnace tileentityInputFurnace)
{
super(new ContainerInputFurnace(inventoryplayer, tileentityInputFurnace));
inputFurnaceInventory = tileentityInputFurnace;
}
/**
* Draw the foreground layer for the GuiContainer (everythin in front of the items)
*/
protected void drawGuiContainerForegroundLayer(int par1, int par2)
{
fontRenderer.drawString(StatCollector.translateToLocal("Dual Input Furnace"), 40, 6, 0x404040);
fontRenderer.drawString(StatCollector.translateToLocal("Inventory"), 8, (ySize - 96) + 2, 0x404040);
}
/**
* Draw the background layer for the GuiContainer (everything behind the items)
*/
protected void drawGuiContainerBackgroundLayer(float f, int i, int j)
{
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
mc.renderEngine.func_110577_a(tif);
int l = (width - xSize) / 2;
int i1 = (height - ySize) / 2;
drawTexturedModalRect(l, i1, 0, 0, xSize, ySize);
if (inputFurnaceInventory.isBurning())
{
int j1 = inputFurnaceInventory.getBurnTimeRemainingScaled(12);
drawTexturedModalRect(l + 56, (i1 + 36 + 12) - j1, 176, 12 - j1, 14, j1 + 2);
}
int k1 = inputFurnaceInventory.getCookProgressScaled(24);
drawTexturedModalRect(l + 79, i1 + 34, 176, 14, k1 + 1, 16);
}
}
Tile Entity
import cpw.mods.fml.common.registry.GameRegistry;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
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;
public class TileEntityInputFurnace extends TileEntity implements IInventory
{
private ItemStack blastItemStacks[];
public int dualBurnTime;
public int currentItemBurnTime;
public int dualCookTime;
private String customName;
public TileEntityInputFurnace()
{
blastItemStacks = new ItemStack[4];
dualBurnTime = 0;
currentItemBurnTime = 0;
dualCookTime = 0;
}
/**
* Returns the number of slots in the inventory.
*/
public int getSizeInventory()
{
return blastItemStacks.length;
}
/**
* Returns the stack in slot i
*/
public ItemStack getStackInSlot(int i)
{
return blastItemStacks[i];
}
public void setInventorySlotConatainers(int i, ItemStack itemstack)
{
blastItemStacks[i] = itemstack;
if (itemstack != null && itemstack.stackSize > getInventoryStackLimit())
{
itemstack.stackSize = getInventoryStackLimit();
}
}
/**
* Reads a tile entity from NBT.
*/
public void readFromNBT(NBTTagCompound nbttagcompound)
{
super.readFromNBT(nbttagcompound);
NBTTagList nbttaglist = nbttagcompound.getTagList("Items");
blastItemStacks = new ItemStack[getSizeInventory()];
for (int i = 0; i < nbttaglist.tagCount(); i++)
{
NBTTagCompound nbttagcompound1 = (NBTTagCompound)nbttaglist.tagAt(i);
byte byte0 = nbttagcompound1.getByte("Slot");
if (byte0 >= 0 && byte0 < blastItemStacks.length)
{
blastItemStacks[byte0] = ItemStack.loadItemStackFromNBT(nbttagcompound1);
}
}
dualBurnTime = nbttagcompound.getShort("BurnTime");
dualCookTime = nbttagcompound.getShort("CookTime");
currentItemBurnTime = getItemBurnTime(blastItemStacks[1]);
}
/**
* Writes a tile entity to NBT.
*/
public void writeToNBT(NBTTagCompound nbttagcompound)
{
super.writeToNBT(nbttagcompound);
nbttagcompound.setShort("BurnTime", (short)dualBurnTime);
nbttagcompound.setShort("CookTime", (short)dualCookTime);
NBTTagList nbttaglist = new NBTTagList();
for (int i = 0; i < blastItemStacks.length; i++)
{
if (blastItemStacks[i] != null)
{
NBTTagCompound nbttagcompound1 = new NBTTagCompound();
nbttagcompound1.setByte("Slot", (byte)i);
blastItemStacks[i].writeToNBT(nbttagcompound1);
nbttaglist.appendTag(nbttagcompound1);
}
}
nbttagcompound.setTag("Items", nbttaglist);
}
/**
* Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't
* this more of a set than a get?*
*/
public int getInventoryStackLimit()
{
return 64;
}
public int getCookProgressScaled(int i)
{
return (dualCookTime * i) / 200;
}
public int getBurnTimeRemainingScaled(int i)
{
if (currentItemBurnTime == 0)
{
currentItemBurnTime = 200;
}
return (dualBurnTime * i) / currentItemBurnTime;
}
public boolean isBurning()
{
return dualBurnTime > 0;
}
/**
* Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count
* ticks and creates a new spawn inside its implementation.
*/
public void updateEntity()
{
boolean flag = dualBurnTime > 0;
boolean flag1 = false;
if (dualBurnTime > 0)
{
dualBurnTime--;
}
if (!worldObj.isRemote)
{
if (dualBurnTime == 0 && canSmelt())
{
currentItemBurnTime = dualBurnTime = getItemBurnTime(blastItemStacks[2]);
if (dualBurnTime > 0)
{
flag1 = true;
if (blastItemStacks[2] != null)
{
if (blastItemStacks[2].stackSize == 0)
{
blastItemStacks[2] = new ItemStack(blastItemStacks[2].getItem().setFull3D());
}
else
{
blastItemStacks[2].stackSize--;
}
if (blastItemStacks[2].stackSize == 0)
{
blastItemStacks[2] = null;
}
}
}
}
if (isBurning() && canSmelt())
{
dualCookTime++;
if (dualCookTime == 200)
{
dualCookTime = 0;
smeltItem();
flag1 = true;
}
}
else
{
dualCookTime = 0;
}
if (flag != (dualBurnTime > 0))
{
flag1 = true;
}
}
if (flag1)
{
onInventoryChanged();
}
}
private boolean canSmelt()
{
if (blastItemStacks[0] == null || blastItemStacks[1] == null)
{
return false;
}
ItemStack itemstack = InputFurnaceRecipes.getSmeltingResult(blastItemStacks[0].getItem().itemID, blastItemStacks[1].getItem().itemID);
if (itemstack == null)
{
return false;
}
if (blastItemStacks[3] == null)
{
return true;
}
if (!blastItemStacks[3].isItemEqual(itemstack))
{
return false;
}
if (blastItemStacks[3].stackSize < getInventoryStackLimit() && blastItemStacks[3].stackSize < blastItemStacks[3].getMaxStackSize())
{
return true;
}
else
{
return blastItemStacks[3].stackSize < itemstack.getMaxStackSize();
}
}
public void smeltItem()
{
if (!canSmelt())
{
return;
}
ItemStack itemstack = InputFurnaceRecipes.getSmeltingResult(blastItemStacks[0].getItem().itemID, blastItemStacks[1].getItem().itemID);
if (blastItemStacks[3] == null)
{
blastItemStacks[3] = itemstack.copy();
}
else if (blastItemStacks[3].itemID == itemstack.itemID)
{
blastItemStacks[3].stackSize++;
}
for (int i = 0; i < 2; i++)
{
if (blastItemStacks[i].stackSize <= 0)
{
blastItemStacks[i] = new ItemStack(blastItemStacks[i].getItem().setFull3D());
}
else
{
blastItemStacks[i].stackSize--;
}
if (blastItemStacks[i].stackSize <= 0)
{
blastItemStacks[i] = null;
}
}
}
private int getItemBurnTime(ItemStack itemstack)
{
if (itemstack == null)
{
return 0;
}
int i = itemstack.getItem().itemID;
if (i < 256 && Block.blocksList[i].blockMaterial == Material.wood)
{
return 300;
}
if (i == Item.stick.itemID)
{
return 100;
}
if (i == Item.coal.itemID)
{
return 1600;
}
if (i == Item.bucketLava.itemID)
{
return 20000;
}
if (i == Item.blazeRod.itemID)
{
return 2400;
}
if (i == Block.sapling.blockID)
{
return 100;
}
else
{
return GameRegistry.getFuelValue(itemstack);
}
}
/**
* Do not make give this method the name canInteractWith because it clashes with Container
*/
public boolean isUseableByPlayer(EntityPlayer entityplayer)
{
if (worldObj.getBlockTileEntity(xCoord, yCoord, zCoord) != this)
{
return false;
}
else
{
return entityplayer.getDistanceSq((double)xCoord + 0.5D, (double)yCoord + 0.5D, (double)zCoord + 0.5D) <= 64D;
}
}
/**
* Decrease the size of the stack in slot (first int arg) by the amount of the second int arg. Returns the new
* stack.
*/
public ItemStack decrStackSize(int i, int j)
{
if (blastItemStacks[i] != null)
{
if (blastItemStacks[i].stackSize <= j)
{
ItemStack itemstack = blastItemStacks[i];
blastItemStacks[i] = null;
return itemstack;
}
ItemStack itemstack1 = blastItemStacks[i].splitStack(j);
if (blastItemStacks[i].stackSize == 0)
{
blastItemStacks[i] = null;
}
return itemstack1;
}
else
{
return null;
}
}
/**
* Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections).
*/
public void setInventorySlotContents(int i, ItemStack itemstack)
{
blastItemStacks[i] = itemstack;
if (itemstack != null && itemstack.stackSize > getInventoryStackLimit())
{
itemstack.stackSize = getInventoryStackLimit();
}
}
/**
* Returns the name of the inventory.
*/
public String getInvName()
{
return "container.goldfurnace";
}
public void openChest()
{
}
public void closeChest()
{
}
/**
* 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.
*/
public ItemStack getStackInSlotOnClosing(int i)
{
if (blastItemStacks[i] != null)
{
ItemStack itemstack = blastItemStacks[i];
blastItemStacks[i] = null;
return itemstack;
}
else
{
return null;
}
}
@Override
public boolean isInvNameLocalized()
{
return (this.customName != null) && (this.customName.length() > 0);
}
public void setCustomName(String name)
{
this.customName = name;
}
@Override
public boolean isItemValidForSlot(int i, ItemStack itemstack) {
return false;
}
}
Slot
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
public class SlotInputFurnace extends Slot
{
public SlotInputFurnace(EntityPlayer entityplayer, IInventory iinventory, int i, int j, int k)
{
super(iinventory, i, j, k);
}
/**
* Check if the stack is a valid item for this slot. Always true beside for the armor slots.
*/
public boolean isItemValid(ItemStack itemstack)
{
return false;
}
/**
* Called when the player picks up an item from an inventory slot
*/
public void onPickupFromSlot(EntityPlayer par1EntityPlayer, ItemStack par2ItemStack)
{
this.onCrafting(par2ItemStack);
super.onPickupFromSlot(par1EntityPlayer, par2ItemStack);
}
}
Recipes
import bcblocks.twoinputfurnace.InputFurnace;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
public class InputFurnaceRecipes
{
public InputFurnaceRecipes()
{
}
public static ItemStack getSmeltingResult(int i, int j)
{
return getOutput(i, j);
}
private static ItemStack getOutput(int i, int j)
{
if (i == Item.coal.itemID && j == Item.ingotIron.itemID || i == Item.ingotIron.itemID && j == Item.coal.itemID)
{
return new ItemStack(Item.ingotGold, 1);
}
if (i == InputFurnace.item1 && j == InputFurnace.item2 || i == InputFurnace.item2 && j == InputFurnace.item1)
{
return new ItemStack(Item.ingotGold, 1);
}
return null;
}
}
Source Code....this is a fully functioning and running mod containing only this furnace, if it does not work for you by dropping in to your mcp folder, its something you did wrong, this works 100%....
Damnit you beat me to it.I was thinking of posting my solution for it however mine would be for 1.5.2
Anyway,glad you posted for 1.6.2 I just updated and this will save me from the despair I had in 1.5.2
Thanks a lot for this! ^^
Don't see the dual input though,but coming from you I know it will be here soon.
Damnit you beat me to it.I was thinking of posting my solution for it however mine would be for 1.5.2
Anyway,glad you posted for 1.6.2 I just updated and this will save me from the despair I had in 1.5.2
Thanks a lot for this! ^^
Don't see the dual input though,but coming from you I know it will be here soon.
Its really nice of you to do all this, but this is not really a tutorial, we never learn anything, we just c/p :/
But the idea is still really nice
Thanks and while I agree with you to a point, the first post will have basic reference to them explaining the changes and why. I also did this with my crafting table explanations. Gave the first post some explanation and for the rest just showed most of the code. I havent had much time to go back and add the notes to this one yet....also I know I dont say for moderately advanced modders, but for these it should be implied...
This is all basic stuff tbh, if you know java not much needs explanation except for quirks of the minecraft code
Now with this I agree 100%.....As I dont know much about java outside of minecraft I am finding that much of the tile entity and container classes still get me crazy....I am just beginning to understand how they work and that is through a lot of trial and error and help from the community here. There was a guy here for a while, though I havent seen him around lately, jcm2606 I think was his user name. He helped me get the ball rolling on these types of blocks, as I had no idea why just a copy and paste job wasnt getting the GUI's to work or function as supposed too....I got much better, but still dont know half what I should for some stuff, and as these are blocks for the bit more advanced coder, beginners really should be making blocks, items, and other basic stuff first while learning a bit of java too. This will make these block more understandable. And that just copy and pasting the code you will not be able to solve any issues right off. No matter what the tutorial is, or how well or disorganized they are written, you should always read through the code first to understand what and why....Anyone can copy and paste, I find reading the material 2 or 3 times or so will help a lot as well as having done the basics first, I certainly didnt start out with these, my first mod was a block, then I made the block spawn particles, and then made it make sounds and moved on to items and so on....Oh and not understanding a bit of the code, made it take 2 and a half weeks to get a basic block to work the first time, so yeah java does help but patience and determination will work too, just takes longer.....
Mate, please use some spacing between parts of your text.
Without separating them into smaller chunks it gets quite tedious to read and feels like a wall of text more than a few lines
Im sorry, I have a bad habit of just typing out what is on the brain rather than realizing how hard it may be to read...There have been lots of folk here that have been kind and helpful to me, you included and I try not to offend. Sometimes though I get carried away...
by duel input is that like saying that the vanilla furnace is duel input? if not how would you classify the vanilla furnace
By duel input I mean exactly that, one fuel source and two smeltable objects. This will produce one out put. I dont understand what you dont understand about this. And no, the vanilla furnace is one input, one fuel source, and one out put.
Because I have not got to it yet, I have the code and will be posting it tonight actually so be patient...
By duel input I mean exactly that, one fuel source and two smeltable objects. This will produce one out put. I dont understand what you dont understand about this. And no, the vanilla furnace is one input, one fuel source, and one out put.
thanks I understand now, I thought the fuel source counted as input :3
I'm not sure how to get the CommonProxy thing working. It's a stubborn error that just doesn't seem to go away for me. Any way to deal with it?
Mod file:
package dishWasherMod;
import net.minecraft.block.Block;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.Configuration;
import net.minecraftforge.common.MinecraftForge;
import cpw.mods.fml.client.registry.RenderingRegistry;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.Mod.Init;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.SidedProxy;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.network.NetworkMod;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;
@Mod(modid = "DishWasherMod", name = "DishWasherMod", version = "1.0")
@NetworkMod(clientSideRequired = true, serverSideRequired = false)
public class DishWasherMod
{
@Instance("DishWasher")
public static DishWasherMod instance;
private GuiHandlerDishWasher guiHandlerDishWasher = new GuiHandlerDishWasher();
public static Block dishWasher;
public static Block dishWasherActive;
public static int dishWasherID;
public static int dishWasherActiveID;
@SidedProxy(clientSide = "dishWasherMod.ClientProxy", serverSide = "dishWasherMod.CommonProxy")
@EventHandler
public void PreInit(FMLPreInitializationEvent event)
{
Configuration config = new Configuration(event.getSuggestedConfigurationFile());
config.load();
dishWasherID = config.getBlock("dishWasher ID", 3007, (String)null).getInt();
dishWasherActiveID = config.getBlock("dishWasher Active ID", 3008, (String)null).getInt();
config.save();
}
@EventHandler
public void load(FMLInitializationEvent event)
{
dishWasher = new BlockDishWasher(dishWasherID, false).setHardness(3.5F).setResistance(2000.0F).setStepSound(Block.soundStoneFootstep).setUnlocalizedName("highSpeedFurnace").setCreativeTab(CreativeTabs.tabBlock);
dishWasherActive = new BlockDishWasher(dishWasherActiveID, true).setHardness(3.5F).setResistance(2000.0F).setStepSound(Block.soundStoneFootstep).setUnlocalizedName("highSpeedFurnace");
GameRegistry.registerBlock(dishWasher, "dishWasher");
GameRegistry.registerBlock(dishWasherActive, "dishWasherActive");
LanguageRegistry.addName(dishWasher, "Dishwasher");
GameRegistry.registerTileEntity(TileEntityDishWasher.class,"tileEntityDishWasher");
GameRegistry.addRecipe(new ItemStack(dishWasher, 1), new Object[] {"III", "IBI", "ITI", Character.valueOf('I'), Item.ingotIron, Character.valueOf('B'), Item.bucketEmpty, Character.valueOf('T'), Block.trapdoor});
RenderingRegistry.registerBlockHandler(2105, RenderDish.INSTANCE);
NetworkRegistry.instance().registerGuiHandler(this, guiHandlerDishWasher);
proxy.registerRenderThings();
}
@EventHandler
public void PostInit(FMLPostInitializationEvent event)
{
}
}
OT: Btw, love your profile pic. Sgt. Schultz was hilarious. Just happened to see a few clips on YouTube. "Ohh, I see nothing, I was not here, I did not even get UP this morning!"
Below are tutorials for different furnace type blocks. First will be a basic furnace, and then in no particular order, a double furnace, a two input furnace and a lava fueled furnace. I know that I had a tutorial for this once before and tomtomg99 had one for 1.5.x which was just fine and worked well. He hasn't updated his tutorial for this yet so I decided with as many help requests as I have seen on this forum alone I would post one again. Please DO NOT flood my PM box with requests for help, that is what this thread is for, if I dont reply, someone else may. You could also use the forum dev section for help, #irc chat boards and other forums for help if you get stuck.
The furnace requires only a few files like the crafting table, some are not even necessary. Depending on the type of furnace you are trying to code, your files may vary and even require more or less files. However they will all need a mod class and a block class and a GUI Handler.
This is now a video tutorial so please pay close attention and excuse my arrogance in my tone of voice. After viewing this tutorial it should help you understand where many of the mistakes have been made and why some things just done work for you....
This is a five part series for the basic furnace and I feel I have covered every thing necessary to make this work, every class is explained....
Part 1
Part 2
Part 3
Part 4
Part 5
GUI Handler
This is a very important class here, this is absolutely necessary to have if you actually intend to open your blocks GUI
Render Class
Find out how I generate....coolAlias...world structure generation and rotation tool...
This is basically two furnaces in one. Its efficient and hey, it lets you smelt more than one object at a time so why not. I honestly feel mojang is missing the point on some things. They seem to keep adding in more and more mods that people have made as opposed to improving the stuff they already have in the game. Furnace upgrades and crafting table upgrades are something that needs to be looked at, even if they are only upgradeable based on XP levels. At any rate, enough rambling.....
I will try to come back later and post some highlights and comments on the code here, for now I will only post the necessary classes needed for this to happen....
Container
Gui
Tile
With these added classes and the block, handler and mod classes above you will now have a double furnace. Review the code here within and you can make anything like this or bigger, 3, 4, or even 6 furnaces in one.
Find out how I generate....coolAlias...world structure generation and rotation tool...
So, for the furnace changes when making the furnace do different things and not unlike the crafting table tutorial I have posted as well, you make changes only in a few places and usually not in the block class. So for the Lava Furnace, as in the Double Furnace and in the Dual Input Furnace, I will only be posting relevant code changes for you to follow.
Container
Tile Entity
Gui
Slot
Find out how I generate....coolAlias...world structure generation and rotation tool...
This is one way to make the all important 2 input furnace that everyone seems to seek out. This code works just fine, may not be the best way to do this but it works for me. I have gathered as much info as I can find and sifted through a ton of non working code for this. Basically the credit for this goes to the community because that is the source I used for the code, though most of it didnt work. Another thought, I am not actually using this in any mod, mostly because I dont want to code an entire mod around this. This is mostly for those who have a mod with an intended two input furnace. Therefore feel free to use this code for any needs you may have, however I will not be able to help you solve too many issues with this code.
Container
GUI
Tile Entity
Slot
Recipes
Source Code....this is a fully functioning and running mod containing only this furnace, if it does not work for you by dropping in to your mcp folder, its something you did wrong, this works 100%....
Find out how I generate....coolAlias...world structure generation and rotation tool...
Anyway,glad you posted for 1.6.2 I just updated and this will save me from the despair I had in 1.5.2
Thanks a lot for this! ^^
Don't see the dual input though,but coming from you I know it will be here soon.
Yes, only me and tomtomg99 and one or two others are doing stuff like this that I know of...
Thanks, its nice to know I can help. I only wish more people would do some stuff that others are not. Too many block and other basic tutorials...
Yes it should be up tonight...
Find out how I generate....coolAlias...world structure generation and rotation tool...
Find out how I generate....coolAlias...world structure generation and rotation tool...
But the idea is still really nice
Thanks and while I agree with you to a point, the first post will have basic reference to them explaining the changes and why. I also did this with my crafting table explanations. Gave the first post some explanation and for the rest just showed most of the code. I havent had much time to go back and add the notes to this one yet....also I know I dont say for moderately advanced modders, but for these it should be implied...
Find out how I generate....coolAlias...world structure generation and rotation tool...
Now with this I agree 100%.....As I dont know much about java outside of minecraft I am finding that much of the tile entity and container classes still get me crazy....I am just beginning to understand how they work and that is through a lot of trial and error and help from the community here. There was a guy here for a while, though I havent seen him around lately, jcm2606 I think was his user name. He helped me get the ball rolling on these types of blocks, as I had no idea why just a copy and paste job wasnt getting the GUI's to work or function as supposed too....I got much better, but still dont know half what I should for some stuff, and as these are blocks for the bit more advanced coder, beginners really should be making blocks, items, and other basic stuff first while learning a bit of java too. This will make these block more understandable. And that just copy and pasting the code you will not be able to solve any issues right off. No matter what the tutorial is, or how well or disorganized they are written, you should always read through the code first to understand what and why....Anyone can copy and paste, I find reading the material 2 or 3 times or so will help a lot as well as having done the basics first, I certainly didnt start out with these, my first mod was a block, then I made the block spawn particles, and then made it make sounds and moved on to items and so on....Oh and not understanding a bit of the code, made it take 2 and a half weeks to get a basic block to work the first time, so yeah java does help but patience and determination will work too, just takes longer.....
Find out how I generate....coolAlias...world structure generation and rotation tool...
Without separating them into smaller chunks it gets quite tedious to read and feels like a wall of text more than a few lines
Find out how I generate....coolAlias...world structure generation and rotation tool...
why is this empty?
Because I have not got to it yet, I have the code and will be posting it tonight actually so be patient...
By duel input I mean exactly that, one fuel source and two smeltable objects. This will produce one out put. I dont understand what you dont understand about this. And no, the vanilla furnace is one input, one fuel source, and one out put.
Find out how I generate....coolAlias...world structure generation and rotation tool...
Mod file:
OT: Btw, love your profile pic. Sgt. Schultz was hilarious. Just happened to see a few clips on YouTube. "Ohh, I see nothing, I was not here, I did not even get UP this morning!"
I just took the Minecraft Noob test! Check out what I scored. Think you can beat me?!
To take the test, check out
https://minecraftnoobtest.com/test.php
Don't click this link, HE is haunting it...