Nerostix Posted January 27, 2014 Posted January 27, 2014 I'm trying to put together a dual-input furnace, based almost entirely on Micro's tutorial. But I can't for the life of me figure out how or why my furnace isn't changing from idle to active. TileEntity package evocraft.clayfurnace; 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 TileEntityClayFurnace extends TileEntity implements IInventory { private ItemStack blastItemStacks[]; public int dualBurnTime; public int currentItemBurnTime; public int dualCookTime; private String customName; public TileEntityClayFurnace() { 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; } public void setInventorySlotContainers(int i, ItemStack itemstack) { blastItemStacks = 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 != null) { NBTTagCompound nbttagcompound1 = new NBTTagCompound(); nbttagcompound1.setByte("Slot", (byte)i); blastItemStacks.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 = ClayFurnaceRecipes.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 = ClayFurnaceRecipes.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.stackSize <= 0) { blastItemStacks = new ItemStack(blastItemStacks.getItem().setFull3D()); } else { blastItemStacks.stackSize--; } if (blastItemStacks.stackSize <= 0) { blastItemStacks = null; } } } private int getItemBurnTime(ItemStack itemstack) { if (itemstack == null) { return 0; } int i = itemstack.getItem().itemID; if (i < 256 && Block.blocksList.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 != null) { if (blastItemStacks.stackSize <= j) { ItemStack itemstack = blastItemStacks; blastItemStacks = null; return itemstack; } ItemStack itemstack1 = blastItemStacks.splitStack(j); if (blastItemStacks.stackSize == 0) { blastItemStacks = 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 = itemstack; if (itemstack != null && itemstack.stackSize > getInventoryStackLimit()) { itemstack.stackSize = getInventoryStackLimit(); } } /** * Returns the name of the inventory. */ public String getInvName() { return "container.clayfurnace"; } 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 != null) { ItemStack itemstack = blastItemStacks; blastItemStacks = 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; } } Block package evocraft.clayfurnace; import java.util.Random; import net.minecraft.block.Block; import net.minecraft.block.BlockContainer; import net.minecraft.block.material.Material; import net.minecraft.client.renderer.texture.IconRegister; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityItem; 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.util.Icon; import net.minecraft.util.MathHelper; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; public class BlockClayFurnace extends BlockContainer { private Random clayFurnaceRand; private final boolean isActive; private static boolean keepClayFurnaceInventory = false; @SideOnly(Side.CLIENT) private Icon furnaceIconTop; @SideOnly(Side.CLIENT) private Icon furnaceIconFront; public BlockClayFurnace(int i, boolean flag) { super(i, Material.ground); clayFurnaceRand = new Random(); isActive = flag; } @SideOnly(Side.CLIENT) public Icon getIcon(int par1, int par2) { if (par1 == 4 && par2 == 0) return furnaceIconFront; if (par1 == 1) return blockIcon; if (par2 == -1 || par1 == par2) return furnaceIconFront; return blockIcon; } @SideOnly(Side.CLIENT) public void registerIcons(IconRegister par1IconRegister) { this.blockIcon = par1IconRegister.registerIcon("clayfurnace:clayFurnaceSide"); this.furnaceIconFront = par1IconRegister.registerIcon(this.isActive ? "clayfurnace:clayFurnaceActive" : "clayfurnace:clayFurnaceIdle"); this.furnaceIconTop = par1IconRegister.registerIcon("clayfurnace:clayFurnaceTop"); } @SideOnly(Side.CLIENT) public Icon getBlockTexture(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) { int meta = par1IBlockAccess.getBlockMetadata(par2, par3, par4); return par5 == 1 ? this.blockIcon : (par5 == 0 ? this.blockIcon : (par5 != meta ? this.blockIcon : this.furnaceIconFront)); } public void onBlockAdded(World par1World, int par2, int par3, int par4) { super.onBlockAdded(par1World, par2, par3, par4); this.setDefaultDirection(par1World, par2, par3, par4); } private void setDefaultDirection(World par1World, int par2, int par3, int par4) { if (!par1World.isRemote) { int l = par1World.getBlockId(par2, par3, par4 - 1); int i1 = par1World.getBlockId(par2, par3, par4 + 1); int j1 = par1World.getBlockId(par2 - 1, par3, par4); int k1 = par1World.getBlockId(par2 + 1, par3, par4); byte b0 = 3; if (Block.opaqueCubeLookup[l] && !Block.opaqueCubeLookup[i1]) { b0 = 3; } if (Block.opaqueCubeLookup[i1] && !Block.opaqueCubeLookup[l]) { b0 = 2; } if (Block.opaqueCubeLookup[j1] && !Block.opaqueCubeLookup[k1]) { b0 = 5; } if (Block.opaqueCubeLookup[k1] && !Block.opaqueCubeLookup[j1]) { b0 = 4; } par1World.setBlockMetadataWithNotify(par2, par3, par4, b0, 2); } } /** * A randomly called display update to be able to add particles or other items for display */ public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random) { if (this.isActive) { int var6 = par1World.getBlockMetadata(par2, par3, par4); float var7 = (float)par2 + 0.5F; float var8 = (float)par3 + 0.0F + par5Random.nextFloat() * 6.0F / 16.0F; float var9 = (float)par4 + 0.5F; float var10 = 0.52F; float var11 = par5Random.nextFloat() * 0.6F - 0.3F; if (var6 == 4) { par1World.spawnParticle("smoke", (double)(var7 - var10), (double)var8, (double)(var9 + var11), 0.0D, 0.0D, 0.0D); par1World.spawnParticle("flame", (double)(var7 - var10), (double)var8, (double)(var9 + var11), 0.0D, 0.0D, 0.0D); } else if (var6 == 5) { par1World.spawnParticle("smoke", (double)(var7 + var10), (double)var8, (double)(var9 + var11), 0.0D, 0.0D, 0.0D); par1World.spawnParticle("flame", (double)(var7 + var10), (double)var8, (double)(var9 + var11), 0.0D, 0.0D, 0.0D); } else if (var6 == 2) { par1World.spawnParticle("smoke", (double)(var7 + var11), (double)var8, (double)(var9 - var10), 0.0D, 0.0D, 0.0D); par1World.spawnParticle("flame", (double)(var7 + var11), (double)var8, (double)(var9 - var10), 0.0D, 0.0D, 0.0D); } else if (var6 == 3) { par1World.spawnParticle("smoke", (double)(var7 + var11), (double)var8, (double)(var9 + var10), 0.0D, 0.0D, 0.0D); par1World.spawnParticle("flame", (double)(var7 + var11), (double)var8, (double)(var9 + var10), 0.0D, 0.0D, 0.0D); } } } /** * Called upon block activation (right click on the block.) */ public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int par6, float par7, float par8, float par9) { if (world.isRemote) { return true; } else if (!player.isSneaking()) { TileEntityClayFurnace var10 = (TileEntityClayFurnace) world.getBlockTileEntity(x, y, z); if (var10 != null) { player.openGui(ClayFurnace.instance, 1, world, x, y, z); } return true; } else { return false; } } /** * Update which block ID the furnace is using depending on whether or not it is burning */ public static void updateFurnaceBlockState(boolean par0, World world, int x, int y, int z) { int var5 = world.getBlockMetadata(x, y, z); TileEntity var6 = world.getBlockTileEntity(x, y, z); keepClayFurnaceInventory = true; if (par0) { world.setBlock(x, y, z, ClayFurnace.clayFurnaceActive.blockID); } else { world.setBlock(x, y, z, ClayFurnace.clayFurnaceIdle.blockID); } keepClayFurnaceInventory = false; world.setBlockMetadataWithNotify(x, y, z, var5, 2); if (var6 != null) { var6.validate(); world.setBlockTileEntity(x, y, z, var6); } } /** * Returns the TileEntity used by this block. */ public TileEntity getBlockEntity() { return new TileEntityClayFurnace(); } public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLivingBase par5EntityLivingBase, ItemStack par6ItemStack) { int l = MathHelper.floor_double((double)(par5EntityLivingBase.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3; if (l == 0) { par1World.setBlockMetadataWithNotify(par2, par3, par4, 2, 2); } if (l == 1) { par1World.setBlockMetadataWithNotify(par2, par3, par4, 5, 2); } if (l == 2) { par1World.setBlockMetadataWithNotify(par2, par3, par4, 3, 2); } if (l == 3) { par1World.setBlockMetadataWithNotify(par2, par3, par4, 4, 2); } if (par6ItemStack.hasDisplayName()) { ((TileEntityClayFurnace)par1World.getBlockTileEntity(par2, par3, par4)).setCustomName(par6ItemStack.getDisplayName()); } } /** * Called whenever the block is removed. */ public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6) { if (!keepClayFurnaceInventory) { TileEntityClayFurnace var7 = (TileEntityClayFurnace)par1World.getBlockTileEntity(par2, par3, par4); if (var7 != null) { for (int var8 = 0; var8 < var7.getSizeInventory(); ++var8) { ItemStack itemstack = var7.getStackInSlot(var8); if (itemstack != null) { float f = this.clayFurnaceRand.nextFloat() * 0.8F + 0.1F; float f1 = this.clayFurnaceRand.nextFloat() * 0.8F + 0.1F; float f2 = this.clayFurnaceRand.nextFloat() * 0.8F + 0.1F; while (itemstack.stackSize > 0) { int k1 = this.clayFurnaceRand.nextInt(21) + 10; if (k1 > itemstack.stackSize) { k1 = itemstack.stackSize; } itemstack.stackSize -= k1; EntityItem entityitem = new EntityItem(par1World, (double)((float)par2 + f), (double)((float)par3 + f1), (double)((float)par4 + f2), new ItemStack(itemstack.itemID, k1, itemstack.getItemDamage())); if (itemstack.hasTagCompound()) { entityitem.getEntityItem().setTagCompound((NBTTagCompound)itemstack.getTagCompound().copy()); } float f3 = 0.05F; entityitem.motionX = (double)((float)this.clayFurnaceRand.nextGaussian() * f3); entityitem.motionY = (double)((float)this.clayFurnaceRand.nextGaussian() * f3 + 0.2F); entityitem.motionZ = (double)((float)this.clayFurnaceRand.nextGaussian() * f3); par1World.spawnEntityInWorld(entityitem); } } } par1World.func_96440_m(par2, par3, par4, par5); } } super.breakBlock(par1World, par2, par3, par4, par5, par6); } public boolean hasComparatorInputOverride() { return true; } public int getComparatorInputOverride(World par1World, int par2, int par3, int par4, int par5) { return Container.calcRedstoneFromInventory((IInventory)par1World.getBlockTileEntity(par2, par3, par4)); } @Override public TileEntity createNewTileEntity(World world) { return new TileEntityClayFurnace(); } } Any help is greatly appreciated Quote
TheGreyGhost Posted January 27, 2014 Posted January 27, 2014 Hi I haven't looked at your code in detail, but a possible clue: The vanilla furnace changes its blockID to make itself active. But depending on how you change the blockID, it's not always visible, i.e. it might still look like the inactive furnace. As a general strategy I would suggest you add breakpoints or System.out.println to the appropriate parts of your code to help gather more symptoms and narrow down what's happening, eg is the code which makes the furnace go active actually being called? is the blockID actually being changed? does my active furnace look any different to the inactive furnace? etc -TGG Quote
Nerostix Posted January 27, 2014 Author Posted January 27, 2014 Hi, My active furnace does look different, when I spawn it in it has particles and all. Since I'm still very new to java, how would I exactly add breakpoints or System.out.println to the approprate parts of the code? Thanks in advance Quote
mardiff Posted January 27, 2014 Posted January 27, 2014 Hi, My active furnace does look different, when I spawn it in it has particles and all. Since I'm still very new to java, how would I exactly add breakpoints or System.out.println to the approprate parts of the code? Thanks in advance He says to use System.out.println to actually see which parts of your code are being called. If you don't know what that is, go learn java first. It may seem like a hassle, but you won't be able to do anything at all by yourself without it. As to pertaining to your problem with the furnace, your updateFurnaceBlockState is never actually being called. With vanilla furnaces, this is called in the updateEntity() method, and your updateEntity() method is both commented out and never actually calls the updateFurnaceBlockState method. Without that part, a block schedule is never actually called, and therefore your furnace will never change it's state. Quote If you really want help, give that modder a thank you. Modders LOVE thank yous.
TheGreyGhost Posted January 27, 2014 Posted January 27, 2014 Hi Integrated debuggers are awesome, once you know how to use them you'll never look back. Track exactly what your code is doing, look at the contents of variables, set a breakpoint to check whether your code is actually being called. Are you using Eclipse? Good introduction here... http://www.vogella.com/tutorials/EclipseDebugging/article.html -TGG Quote
badkraft Posted January 27, 2014 Posted January 27, 2014 He says to use System.out.println to actually see which parts of your code are being called. Is it possible, as an alternative to System.out.println for observing values, to use some of the net.minecraft.logging package? BTW, I'm new to Java but a long time C#/.Net software engineer. So picking up Java is not difficult. Some idioms are just a little different while others are way different. Regardless, it is a challenge; but modding MC results in immediate reward for my learning. I get to bring to the table my knowledge of patterns, inheritance and interfaces. Cheers, ~bk Quote
mardiff Posted January 28, 2014 Posted January 28, 2014 To be honest, I've never even looked through there. Using System.out.println is just a basic java function that doesn't require any knowledge of modding. Quote If you really want help, give that modder a thank you. Modders LOVE thank yous.
TheGreyGhost Posted January 28, 2014 Posted January 28, 2014 Hi Yeah you can also use the inbuilt minecraft logging package (based on the standard Java Logger class), it's more flexible and for logging runtime errors in your permanent code it's great. Vanilla code is sprinkled with it. I just use System.out.println for temporary debugging stuff because it's what I'm used to, no other reason. -TGG Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.