I'm starting to assume that almost everyone on this forum is getting the same set of coding from the same tutorial (admittedly, it is the only tutorial I can find). Problem is, we're all using the same tutorial, but none of us seem to be getting straight answers on how to fix the issues (at least, in the 4 topics I found, no one mentioned a fix to the problems). Now, I'm a pretty big noob when it comes to modding in 1.12 (as in, this is my first time). Last time I did modding, it was back in 1.6.4. On that note... I'm noticing that 90% of how to code stuff seems to have changed. Because I've not had the advantage of updating my code through the years, I've had to fall back on tutorials just to relearn the basics again. In turn, I've fallen into the same trap everyone else seems to have had with the one existing tutorial on custom furnaces/machines that exists out there for 1.12.2. So, I'd like to see if I can help by asking for help, and in turn, maybe I can also determine what it is all of us are doing wrong and how we can all fix it. In truth, if someone could make a current and up-to-date tutorial on this matter, it'd help the most, but with 1.13 out now, it's unlikely.
So, the first thing is: I have no idea what this ItemHandler thing that Forge utilizes is... I've done my best to follow what others are posting for fixes, but simply put, the tutorial utilized IInventory, which I've also noticed people practically cussing about when it's used... While, yes, I agree this is apparently an issue... I feel that's taking it to an extreme... especially since all of us are following the same tutorial, and likely don't know of the alternatives.
So, what is wrong with my furnace, you ask? What needs fixing? Well, my guess is the update function in the Tile Entity, but I can't for the life of me figure out how to do it. The tutorial I followed had a large mess of code for the update function, and as best as I can guess, the function is running and taking the items from the itemstacks before it's even updating anything as when I add items into the furnace when it is off, it turns on and then removes all of the items. However, once it's on, it no longer does that. I honestly can't figure out why it is doing this, though. I assume it has to do with the really crummy tutorial I followed, but alas, as I said... it's the only one I can find, and I spent 2 hours looking for another one cause it's honestly that bad.
The other thing that is wrong is that I cannot shift+click any of the items into the slots. I have to click them into the furnace slots. That said, though, those are the only two issues I'm having. I believe I have been able to solve every other issue...
Oh yeah... I guess there is one other issue? To register my alloyer, I am using this code:
GameRegistry.registerTileEntity(TileEntityAlloyer.class, "alloyer");
Forge, however, says this is deprecated, but refuses to tell me how to do this otherwise? Could anyone help with that?
Here's the Block code:
package com.sureenink.metallics.basemetals.machines.alloyer;
import java.util.Random;
import com.sureenink.metallics.Metallics;
import com.sureenink.metallics.Reference;
import com.sureenink.metallics.basemetals.BaseMetalsBlocks;
import com.sureenink.metallics.blocks.BlockBase;
import net.minecraft.block.BlockHorizontal;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.properties.PropertyDirection;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.Mirror;
import net.minecraft.util.Rotation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class BlockAlloyer extends BlockBase {
public static final PropertyDirection FACING = BlockHorizontal.FACING;
public static final PropertyBool ACTIVE = PropertyBool.create("active");
public BlockAlloyer(String name)
{
super(Material.ROCK, name, "blockAlloyer", 3.0f, 3.0f, "pickaxe", 1);
setSoundType(SoundType.STONE);
this.setDefaultState(this.blockState.getBaseState().withProperty(FACING, EnumFacing.NORTH).withProperty(ACTIVE, false));
}
@Override
public Item getItemDropped(IBlockState state, Random rand, int fortune)
{
return Item.getItemFromBlock(BaseMetalsBlocks.alloyer);
}
@Override
public ItemStack getItem(World worldIn, BlockPos pos, IBlockState state)
{
return new ItemStack(BaseMetalsBlocks.alloyer);
}
@Override
public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ)
{
if(!worldIn.isRemote)
{
playerIn.openGui(Metallics.instance, Reference.GUI_ALLOYER, worldIn, pos.getX(), pos.getY(), pos.getZ());
}
return true;
}
@Override
public void onBlockAdded(World worldIn, BlockPos pos, IBlockState state)
{
if (!worldIn.isRemote)
{
IBlockState north = worldIn.getBlockState(pos.north());
IBlockState south = worldIn.getBlockState(pos.south());
IBlockState west = worldIn.getBlockState(pos.west());
IBlockState east = worldIn.getBlockState(pos.east());
EnumFacing face = (EnumFacing)state.getValue(FACING);
if (face == EnumFacing.NORTH && north.isFullBlock() && !south.isFullBlock()) face = EnumFacing.SOUTH;
else if (face == EnumFacing.SOUTH && south.isFullBlock() && !north.isFullBlock()) face = EnumFacing.NORTH;
else if (face == EnumFacing.WEST && west.isFullBlock() && !east.isFullBlock()) face = EnumFacing.EAST;
else if (face == EnumFacing.EAST && east.isFullBlock() && !west.isFullBlock()) face = EnumFacing.WEST;
worldIn.setBlockState(pos, state.withProperty(FACING, face), 2);
}
}
public static void setState(boolean active, World worldIn, BlockPos pos)
{
IBlockState state = worldIn.getBlockState(pos);
TileEntity tileentity = worldIn.getTileEntity(pos);
if(active) worldIn.setBlockState(pos, BaseMetalsBlocks.alloyer.getDefaultState().withProperty(FACING, state.getValue(FACING)).withProperty(ACTIVE, true), 3);
else worldIn.setBlockState(pos, BaseMetalsBlocks.alloyer.getDefaultState().withProperty(FACING, state.getValue(FACING)).withProperty(ACTIVE, false), 3);
if(tileentity != null)
{
tileentity.validate();
worldIn.setTileEntity(pos, tileentity);
}
}
@Override
public boolean hasTileEntity(IBlockState state)
{
return true;
}
@Override
public TileEntity createTileEntity(World world, IBlockState state)
{
return new TileEntityAlloyer();
}
@Override
public IBlockState getStateForPlacement(World world, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer, EnumHand hand)
{
return this.getDefaultState().withProperty(FACING, placer.getHorizontalFacing().getOpposite());
}
@Override
public void onBlockPlacedBy(World worldIn, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack)
{
worldIn.setBlockState(pos, this.getDefaultState().withProperty(FACING, placer.getHorizontalFacing().getOpposite()), 2);
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state)
{
return EnumBlockRenderType.MODEL;
}
@Override
public IBlockState withRotation(IBlockState state, Rotation rot)
{
return state.withProperty(FACING, rot.rotate((EnumFacing)state.getValue(FACING)));
}
@Override
public IBlockState withMirror(IBlockState state, Mirror mirrorIn)
{
return state.withRotation(mirrorIn.toRotation((EnumFacing)state.getValue(FACING)));
}
@Override
protected BlockStateContainer createBlockState()
{
return new BlockStateContainer(this, new IProperty[] {ACTIVE,FACING});
}
@Override
public IBlockState getStateFromMeta(int meta)
{
EnumFacing facing = EnumFacing.getFront(meta);
if(facing.getAxis() == EnumFacing.Axis.Y) facing = EnumFacing.NORTH;
return this.getDefaultState().withProperty(FACING, facing);
}
@Override
public int getMetaFromState(IBlockState state)
{
return ((EnumFacing)state.getValue(FACING)).getIndex();
}
public void registerItemModel(Item itemBlock) {
Metallics.proxy.registerItemRenderer(itemBlock, 0, name);
}
public Item createItemBlock() {
return new ItemBlock(this).setRegistryName(getRegistryName());
}
@Override
public BlockAlloyer setCreativeTab(CreativeTabs tab) {
super.setCreativeTab(tab);
return this;
}
}
Now for the TileEntity code:
package com.sureenink.metallics.basemetals.machines.alloyer;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemHoe;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemSword;
import net.minecraft.item.ItemTool;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ITickable;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.ItemStackHandler;
public class TileEntityAlloyer extends TileEntity implements ITickable {
private ItemStackHandler handler = new ItemStackHandler(4);
private String customName;
private ItemStack smelting = ItemStack.EMPTY;
private int burnTime;
private int currentBurnTime;
private int cookTime;
private int totalCookTime = 200;
@Override
public boolean hasCapability(Capability<?> capability, EnumFacing facing)
{
if(capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return true;
else return false;
}
@Override
public <T> T getCapability(Capability<T> capability, EnumFacing facing)
{
if(capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return (T) this.handler;
return super.getCapability(capability, facing);
}
public boolean hasCustomName()
{
return this.customName != null && !this.customName.isEmpty();
}
public void setCustomName(String customName)
{
this.customName = customName;
}
@Override
public ITextComponent getDisplayName()
{
return this.hasCustomName() ? new TextComponentString(this.customName) : new TextComponentTranslation("container.basic_metallic_infuser");
}
@Override
public void readFromNBT(NBTTagCompound compound)
{
super.readFromNBT(compound);
this.handler.deserializeNBT(compound.getCompoundTag("Inventory"));
this.burnTime = compound.getInteger("BurnTime");
this.cookTime = compound.getInteger("CookTime");
this.totalCookTime = compound.getInteger("CookTimeTotal");
this.currentBurnTime = getItemBurnTime((ItemStack)this.handler.getStackInSlot(2));
if(compound.hasKey("CustomName", 8)) this.setCustomName(compound.getString("CustomName"));
}
@Override
public NBTTagCompound writeToNBT(NBTTagCompound compound)
{
super.writeToNBT(compound);
compound.setInteger("BurnTime", (short)this.burnTime);
compound.setInteger("CookTime", (short)this.cookTime);
compound.setInteger("CookTimeTotal", (short)this.totalCookTime);
compound.setTag("Inventory", this.handler.serializeNBT());
if(this.hasCustomName()) compound.setString("CustomName", this.customName);
return compound;
}
public boolean isBurning()
{
return this.burnTime > 0;
}
@SideOnly(Side.CLIENT)
public static boolean isBurning(TileEntityAlloyer te)
{
return te.getField(0) > 0;
}
public void update()
{
if(this.isBurning())
{
--this.burnTime;
BlockAlloyer.setState(true, world, pos);
}
ItemStack[] inputs = new ItemStack[] {handler.getStackInSlot(0), handler.getStackInSlot(1)};
ItemStack fuel = this.handler.getStackInSlot(2);
if(this.isBurning() || !fuel.isEmpty() && !this.handler.getStackInSlot(0).isEmpty() || this.handler.getStackInSlot(1).isEmpty())
{
if(!this.isBurning() && this.canSmelt())
{
this.burnTime = getItemBurnTime(fuel);
this.currentBurnTime = burnTime;
if(this.isBurning() && !fuel.isEmpty())
{
Item item = fuel.getItem();
fuel.shrink(1);
if(fuel.isEmpty())
{
ItemStack item1 = item.getContainerItem(fuel);
this.handler.setStackInSlot(2, item1);
}
}
}
}
if(this.isBurning() && this.canSmelt() && cookTime > 0)
{
cookTime++;
if(cookTime == totalCookTime)
{
if(handler.getStackInSlot(3).getCount() > 0)
{
handler.getStackInSlot(3).grow(1);
}
else
{
handler.insertItem(3, smelting, false);
}
smelting = ItemStack.EMPTY;
cookTime = 0;
return;
}
}
else
{
if(this.canSmelt() && this.isBurning())
{
ItemStack output = AlloyerRecipes.getInstance().getAlloyerResult(inputs[0], inputs[1]);
if(!output.isEmpty())
{
smelting = output;
cookTime++;
inputs[0].shrink(1);
inputs[1].shrink(1);
handler.setStackInSlot(0, inputs[0]);
handler.setStackInSlot(1, inputs[1]);
}
}
}
}
private boolean canSmelt()
{
if(((ItemStack)this.handler.getStackInSlot(0)).isEmpty() || ((ItemStack)this.handler.getStackInSlot(1)).isEmpty()) return false;
else
{
ItemStack result = AlloyerRecipes.getInstance().getAlloyerResult((ItemStack)this.handler.getStackInSlot(0), (ItemStack)this.handler.getStackInSlot(1));
if(result.isEmpty()) return false;
else
{
ItemStack output = (ItemStack)this.handler.getStackInSlot(3);
if(output.isEmpty()) return true;
if(!output.isItemEqual(result)) return false;
int res = output.getCount() + result.getCount();
return res <= 64 && res <= output.getMaxStackSize();
}
}
}
public static int getItemBurnTime(ItemStack fuel)
{
if(fuel.isEmpty()) return 0;
else
{
Item item = fuel.getItem();
if (item instanceof ItemBlock && Block.getBlockFromItem(item) != Blocks.AIR)
{
Block block = Block.getBlockFromItem(item);
if (block == Blocks.WOODEN_SLAB) return 150;
if (block.getDefaultState().getMaterial() == Material.WOOD) return 300;
if (block == Blocks.COAL_BLOCK) return 16000;
}
if (item instanceof ItemTool && "WOOD".equals(((ItemTool)item).getToolMaterialName())) return 200;
if (item instanceof ItemSword && "WOOD".equals(((ItemSword)item).getToolMaterialName())) return 200;
if (item instanceof ItemHoe && "WOOD".equals(((ItemHoe)item).getMaterialName())) return 200;
if (item == Items.STICK) return 100;
if (item == Items.COAL) return 1600;
if (item == Items.LAVA_BUCKET) return 20000;
if (item == Item.getItemFromBlock(Blocks.SAPLING)) return 100;
if (item == Items.BLAZE_ROD) return 2400;
return GameRegistry.getFuelValue(fuel);
}
}
public static boolean isItemFuel(ItemStack fuel)
{
return getItemBurnTime(fuel) > 0;
}
public boolean isUsableByPlayer(EntityPlayer player)
{
return this.world.getTileEntity(this.pos) != this ? false : player.getDistanceSq((double)this.pos.getX() + 0.5D, (double)this.pos.getY() + 0.5D, (double)this.pos.getZ() + 0.5D) <= 64.0D;
}
public int getField(int id)
{
switch(id)
{
case 0:
return this.burnTime;
case 1:
return this.currentBurnTime;
case 2:
return this.cookTime;
case 3:
return this.totalCookTime;
default:
return 0;
}
}
public void setField(int id, int value)
{
switch(id)
{
case 0:
this.burnTime = value;
break;
case 1:
this.currentBurnTime = value;
break;
case 2:
this.cookTime = value;
break;
case 3:
this.totalCookTime = value;
}
}
}
And the Container code:
package com.sureenink.metallics.basemetals.machines.alloyer;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IContainerListener;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.SlotItemHandler;
public class ContainerAlloyer extends Container {
private final TileEntityAlloyer tileentity;
private int cookTime, totalCookTime, burnTime, currentBurnTime;
public ContainerAlloyer(InventoryPlayer player, TileEntityAlloyer tileentity)
{
this.tileentity = tileentity;
IItemHandler handler = tileentity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);
this.addSlotToContainer(new SlotItemHandler(handler, 0, 30, 22));
this.addSlotToContainer(new SlotItemHandler(handler, 1, 58, 22));
this.addSlotToContainer(new SlotItemHandler(handler, 2, 45, 46));
this.addSlotToContainer(new SlotItemHandler(handler, 3, 124, 22));
for(int y = 0; y < 3; y++)
{
for(int x = 0; x < 9; x++)
{
this.addSlotToContainer(new Slot(player, x + y*9 + 9, 8 + x*18, 84 + y*18));
}
}
for(int x = 0; x < 9; x++)
{
this.addSlotToContainer(new Slot(player, x, 8 + x * 18, 142));
}
}
@Override
public void detectAndSendChanges()
{
super.detectAndSendChanges();
for(int i = 0; i < this.listeners.size(); ++i)
{
IContainerListener listener = (IContainerListener)this.listeners.get(i);
if(this.cookTime != this.tileentity.getField(2)) listener.sendWindowProperty(this, 2, this.tileentity.getField(2));
if(this.burnTime != this.tileentity.getField(0)) listener.sendWindowProperty(this, 0, this.tileentity.getField(0));
if(this.currentBurnTime != this.tileentity.getField(1)) listener.sendWindowProperty(this, 1, this.tileentity.getField(1));
if(this.totalCookTime != this.tileentity.getField(3)) listener.sendWindowProperty(this, 3, this.tileentity.getField(3));
}
this.cookTime = this.tileentity.getField(2);
this.burnTime = this.tileentity.getField(0);
this.currentBurnTime = this.tileentity.getField(1);
this.totalCookTime = this.tileentity.getField(3);
}
@Override
@SideOnly(Side.CLIENT)
public void updateProgressBar(int id, int data)
{
this.tileentity.setField(id, data);
}
@Override
public boolean canInteractWith(EntityPlayer playerIn)
{
return this.tileentity.isUsableByPlayer(playerIn);
}
@Override
public ItemStack transferStackInSlot(EntityPlayer playerIn, int index)
{
ItemStack stack = ItemStack.EMPTY;
Slot slot = (Slot)this.inventorySlots.get(index);
if(slot != null && slot.getHasStack())
{
ItemStack stack1 = slot.getStack();
stack = stack1.copy();
if(index == 3)
{
if(!this.mergeItemStack(stack1, 4, 40, true)) return ItemStack.EMPTY;
slot.onSlotChange(stack1, stack);
}
else if(index != 2 && index != 1 && index != 0)
{
Slot slot1 = (Slot)this.inventorySlots.get(index + 1);
if(!AlloyerRecipes.getInstance().getAlloyerResult(stack1, slot1.getStack()).isEmpty())
{
if(!this.mergeItemStack(stack1, 0, 2, false))
{
return ItemStack.EMPTY;
}
else if(TileEntityAlloyer.isItemFuel(stack1))
{
if(!this.mergeItemStack(stack1, 2, 3, false)) return ItemStack.EMPTY;
}
else if(TileEntityAlloyer.isItemFuel(stack1))
{
if(!this.mergeItemStack(stack1, 2, 3, false)) return ItemStack.EMPTY;
}
else if(TileEntityAlloyer.isItemFuel(stack1))
{
if(!this.mergeItemStack(stack1, 2, 3, false)) return ItemStack.EMPTY;
}
else if(index >= 4 && index < 31)
{
if(!this.mergeItemStack(stack1, 31, 40, false)) return ItemStack.EMPTY;
}
else if(index >= 31 && index < 40 && !this.mergeItemStack(stack1, 4, 31, false))
{
return ItemStack.EMPTY;
}
}
}
else if(!this.mergeItemStack(stack1, 4, 40, false))
{
return ItemStack.EMPTY;
}
if(stack1.isEmpty())
{
slot.putStack(ItemStack.EMPTY);
}
else
{
slot.onSlotChanged();
}
if(stack1.getCount() == stack.getCount()) return ItemStack.EMPTY;
slot.onTake(playerIn, stack1);
}
return stack;
}
}
And finally the GUI code:
package com.sureenink.metallics.basemetals.machines.alloyer;
import com.sureenink.metallics.Metallics;
import com.sureenink.metallics.Reference;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.util.ResourceLocation;
public class GuiAlloyer extends GuiContainer {
private static final ResourceLocation TEXTURES = new ResourceLocation(Reference.MODID + ":textures/gui/container/alloyer.png");
private final InventoryPlayer player;
private final TileEntityAlloyer tileEntity;
public GuiAlloyer(InventoryPlayer player, TileEntityAlloyer tileEntity) {
super(new ContainerAlloyer(player, tileEntity));
this.player = player;
this.tileEntity = tileEntity;
}
@Override
protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) {
String tileName = this.tileEntity.getDisplayName().getUnformattedText();
this.fontRenderer.drawString(tileName, (this.xSize / 2 - this.fontRenderer.getStringWidth(tileName) / 2) + 3, 8, 4210752);
this.fontRenderer.drawString(this.player.getDisplayName().getUnformattedText(), 122, this.ySize - 96 + 2, 4210752);
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) {
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
this.mc.getTextureManager().bindTexture(TEXTURES);
this.drawTexturedModalRect(this.guiLeft, this.guiTop, 0, 0, this.xSize, this.ySize);
if(TileEntityAlloyer.isBurning(tileEntity)) {
int k = this.getBurnLeftScaled(13);
this.drawTexturedModalRect(this.guiLeft + 39, this.guiTop + 37 + 12 - k, 176, 12 - k, 14, k + 1);
}
int l = this.getCookingProgressScaled(24);
this.drawTexturedModalRect(this.guiLeft + 80, this.guiTop + 35, 176, 14, l + 1, 16);
}
private int getBurnLeftScaled(int pixels) {
int i = this.tileEntity.getField(1);
if(i == 0) i = 200;
return this.tileEntity.getField(0) * pixels / i;
}
private int getCookingProgressScaled(int pixels) {
int i = this.tileEntity.getField(2);
int j = this.tileEntity.getField(3);
return j != 0 && i != 0 ? i * pixels / j : 0;
}
}