Posted October 28, 20186 yr Hello, It's my first time working with Gui's and containers within forge. I created a basic mod that includes two containers: a chest and a sort of furnace, but I can't seem to acces them no matter what I try. onBlockActivated gets called but the GUI jus't doesn't want to open. I hope someone can help me BlockLogStripper: package com.almightyelement.thirteen.objects.machines.stripper; import java.util.Random; import com.almightyelement.thirteen.Main; import com.almightyelement.thirteen.init.ModBlocks; import com.almightyelement.thirteen.items.BlockBase; import com.almightyelement.thirteen.objects.tileentity.TileEntityLogStripper; import com.almightyelement.thirteen.util.Reference; import com.almightyelement.thirteen.Main; import com.almightyelement.thirteen.objects.tileentity.TileEntityLogStripper; import com.almightyelement.thirteen.util.Reference; 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.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; 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 BlockLogStripper extends BlockBase { public static final PropertyDirection FACING = BlockHorizontal.FACING; public static final PropertyBool BURNING = PropertyBool.create("burning"); public BlockLogStripper(String name) { super(name, Material.IRON); setSoundType(SoundType.METAL); this.setDefaultState(this.blockState.getBaseState().withProperty(FACING, EnumFacing.NORTH).withProperty(BURNING, false)); } @Override public Item getItemDropped(IBlockState state, Random rand, int fortune) { return Item.getItemFromBlock(ModBlocks.LOG_STRIPPER); } @Override public ItemStack getItem(World worldIn, BlockPos pos, IBlockState state) { return new ItemStack(ModBlocks.LOG_STRIPPER); } @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(Main.instance, Reference.GUI_LOG_STRIPPER, 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, ModBlocks.LOG_STRIPPER.getDefaultState().withProperty(FACING, state.getValue(FACING)).withProperty(BURNING, true), 3); else worldIn.setBlockState(pos, ModBlocks.LOG_STRIPPER.getDefaultState().withProperty(FACING, state.getValue(FACING)).withProperty(BURNING, 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 TileEntityLogStripper(); } @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[] {BURNING,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(); } } GuiLogStripper: package com.almightyelement.thirteen.objects.machines.stripper; import com.almightyelement.thirteen.objects.tileentity.TileEntityLogStripper; import com.almightyelement.thirteen.util.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 GuiLogStripper extends GuiContainer { private static final ResourceLocation TEXTURES = new ResourceLocation(Reference.MOD_ID + ":textures/gui/log_stripper.png"); private final InventoryPlayer player; private final TileEntityLogStripper tileentity; public GuiLogStripper(InventoryPlayer player, TileEntityLogStripper tileentity) { super(new ContainerLogStripper(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(TileEntityLogStripper.isBurning(tileentity)) { int k = this.getBurnLeftScaled(13); this.drawTexturedModalRect(this.guiLeft + 8, this.guiTop + 54 + 12 - k, 176, 12 - k, 14, k + 1); } int l = this.getCookProgressScaled(24); this.drawTexturedModalRect(this.guiLeft + 44, this.guiTop + 36, 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 getCookProgressScaled(int pixels) { int i = this.tileentity.getField(2); int j = this.tileentity.getField(3); return j != 0 && i != 0 ? i * pixels / j : 0; } } GuiHandler: package com.almightyelement.thirteen.util.handlers; import com.almightyelement.thirteen.objects.container.ContainerCopperChest; import com.almightyelement.thirteen.objects.container.ContainerLogStripper; import com.almightyelement.thirteen.objects.gui.GuiCopperChest; import com.almightyelement.thirteen.objects.gui.GuiLogStripper; import com.almightyelement.thirteen.objects.tileentity.TileEntityCopperChest; import com.almightyelement.thirteen.objects.tileentity.TileEntityLogStripper; import com.almightyelement.thirteen.util.Reference; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.fml.common.network.IGuiHandler; public class GuiHandler implements IGuiHandler { @Override public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { if(ID == Reference.GUI_LOG_STRIPPER) return new ContainerLogStripper(player.inventory, (TileEntityLogStripper)world.getTileEntity(new BlockPos(x,y,z))); if(ID == Reference.GUI_COPPER_CHEST) return new ContainerCopperChest(player.inventory, (TileEntityCopperChest)world.getTileEntity(new BlockPos(x,y,z)), player); return null; } @Override public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z){ if(ID == Reference.GUI_LOG_STRIPPER) return new GuiLogStripper(player.inventory, (TileEntityLogStripper)world.getTileEntity(new BlockPos(x,y,z))); if(ID == Reference.GUI_COPPER_CHEST) return new GuiCopperChest(player.inventory, (TileEntityCopperChest)world.getTileEntity(new BlockPos(x,y,z)), player); return null; } } Thanks in advance, AlmightyElement Edited October 28, 20186 yr by AlmightyElement Additional info
October 28, 20186 yr 1 hour ago, AlmightyElement said: extends BlockBase BlockBase is an antipattern. You don't need it. @Override public Item getItemDropped(IBlockState state, Random rand, int fortune) { return Item.getItemFromBlock(ModBlocks.LOG_STRIPPER); } @Override public ItemStack getItem(World worldIn, BlockPos pos, IBlockState state) { return new ItemStack(ModBlocks.LOG_STRIPPER); } @Override public EnumBlockRenderType getRenderType(IBlockState state) { return EnumBlockRenderType.MODEL; } These are not needed at all. This is the default implementation of these methods. There is no reason to override them since you are not providing a different implementation. Don't set the blockstate in Block#onBlockPlaced and Block#onBlockPlacedBy. Return the blockstate you need in Block#getStateForPlacement. if(tileentity != null) { tileentity.validate(); worldIn.setTileEntity(pos, tileentity); } You do not need these TE manipulations. Just override TileEntity#shouldRefresh and return false if it is a simple blockstate property change. You have not provided enough code. Have you registered your IGuiHandler implementation at all? Does your container override Container#canInteractWith and if it does what does it return there? And if it references your TEs what do they return in their methods? What did the debugger told you? Are your IGuiHandler methods being invoked? Are your Container/GUI constructors getting invoked?
October 28, 20186 yr Author Hey, This is a guiHandler that I'm using package com.almightyelement.thirteen.util.handlers; import com.almightyelement.thirteen.objects.container.ContainerCopperChest; import com.almightyelement.thirteen.objects.container.ContainerLogStripper; import com.almightyelement.thirteen.objects.gui.GuiCopperChest; import com.almightyelement.thirteen.objects.gui.GuiLogStripper; import com.almightyelement.thirteen.objects.tileentity.TileEntityCopperChest; import com.almightyelement.thirteen.objects.tileentity.TileEntityLogStripper; import com.almightyelement.thirteen.util.Reference; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.fml.common.network.IGuiHandler; public class GuiHandler implements IGuiHandler { @Override public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { if(ID == Reference.GUI_LOG_STRIPPER) return new ContainerLogStripper(player.inventory, (TileEntityLogStripper)world.getTileEntity(new BlockPos(x,y,z))); if(ID == Reference.GUI_COPPER_CHEST) return new ContainerCopperChest(player.inventory, (TileEntityCopperChest)world.getTileEntity(new BlockPos(x,y,z)), player); return null; } @Override public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z){ if(ID == Reference.GUI_LOG_STRIPPER) return new GuiLogStripper(player.inventory, (TileEntityLogStripper)world.getTileEntity(new BlockPos(x,y,z))); if(ID == Reference.GUI_COPPER_CHEST) return new GuiCopperChest(player.inventory, (TileEntityCopperChest)world.getTileEntity(new BlockPos(x,y,z)), player); return null; } } This is the container: package com.almightyelement.thirteen.objects.machines.stripper; import com.almightyelement.thirteen.objects.recipes.LogStripperRecipes; import com.almightyelement.thirteen.objects.tileentity.TileEntityCopperChest; import com.almightyelement.thirteen.objects.tileentity.TileEntityLogStripper; 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 ContainerLogStripper extends Container { //{InventoryPlayer playerInv; TileEntityCopperChest tileEntityCopperChest;} private final TileEntityLogStripper tileentity; private int cookTime, totalCookTime, burnTime, currentBurnTime; public ContainerLogStripper(InventoryPlayer player, TileEntityLogStripper tileentity) { this.tileentity = tileentity; IItemHandler handler = tileentity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null); this.addSlotToContainer(new SlotItemHandler(handler, 0, 26, 11)); this.addSlotToContainer(new SlotItemHandler(handler, 1, 26, 59)); this.addSlotToContainer(new SlotItemHandler(handler, 2, 7, 35)); this.addSlotToContainer(new SlotItemHandler(handler, 3, 81, 36)); 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(!LogStripperRecipes.getInstance().getLogStripperResult(stack1, slot1.getStack()).isEmpty()) { if(!this.mergeItemStack(stack1, 0, 2, false)) { return ItemStack.EMPTY; } else if(TileEntityLogStripper.isItemFuel(stack1)) { if(!this.mergeItemStack(stack1, 2, 3, false)) return ItemStack.EMPTY; } else if(TileEntityLogStripper.isItemFuel(stack1)) { if(!this.mergeItemStack(stack1, 2, 3, false)) return ItemStack.EMPTY; } else if(TileEntityLogStripper.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; } }
October 28, 20186 yr Author And the debugger doesn't give any errors it just prints: Trying to open GUI.
October 28, 20186 yr You still haven't answered most of my questions. 16 minutes ago, V0idWa1k3r said: Have you registered your IGuiHandler implementation at all? Does your container override Container#canInteractWith and if it does what does it return there? And if it references your TEs what do they return in their methods? What did the debugger told you? Are your IGuiHandler methods being invoked? Are your Container/GUI constructors getting invoked? 8 minutes ago, AlmightyElement said: the debugger doesn't give any errors It is not supposed to. Place a breakpoint in your IGuiHandler implementation when returning the GUI or the Container object to see if it is getting called. Place a breakpoint in your GUI/Container constructor to see if they are getting invoked.
October 28, 20186 yr Author Excuse me if I'm giving you wrong answers but I'm pretty new to all of this. And I don't really understand the rest too well. @Override public boolean canInteractWith(EntityPlayer playerIn) { return this.tileentity.isUsableByPlayer(playerIn); } I set some breakpoints and they returned : GuiHandler [line: 32] - getClientGuiElement(int, EntityPlayer, World, int, int, int)
October 28, 20186 yr First of all your actual issue - you've never actually registered your gui handler. You have the method that registered it correctly... in an another method that is never called from anywhere. BlockBase/ItemBase is an antipattern. Composition over inheritance. Quote IHasModel IHasModel is stupid. All items need models, no exceptions. And nothing about item model registration requires access to private/protected stuff. Register your models in the ModelRegistryEvent directly. @SubscribeEvent public static void registerBlock(RegistryEvent.Register<Block> event) { event.getRegistry().registerAll(ModBlocks.BLOCKS.toArray(new Block[0])); TileEntityHandler.registerTileEntities(); ClientRegistry.bindTileEntitySpecialRenderer(TileEntityCopperChest.class, new RenderCopperChest()); } You can't do this. Registering a renderer for a TE is a client-side only operation, while RegistryEvents are common code. This will crash the server. public static final Block COPPER_BLOCK = new BlockBase("copper_block", Material.IRON); public static final Block COPPER_CHEST = new BlockCopperChest("copper_chest"); public static final Block LOG_STRIPPER = new BlockLogStripper("log_stripper"); Never ever use static initializers. Instantinate your stuff in the registry event directly, not in static final fields. compound.setInteger("BurnTime", (short)this.burnTime); compound.setInteger("CookTime", (short)this.cookTime); compound.setInteger("CookTimeTotal", (short)this.totalCookTime); Any particular reason you are replicating a vanilla bug of casting things to a short but saving them as ints? public static int getItemBurnTime(ItemStack fuel) *Sigh*. This is like the tenth time I see this method in custom TEs that have a fuel unedited and blindly copied from TileEntityFurnace. You are not changing the implementation of this method. It is static. And public. Just invoke it from TileEntityFurnace, there is absolutely zero need to mindlessly copy-paste it from TileEntityFurnace, this is not how programming works. Quote public int getField(int id) You are not using IInventory, why are you copying this abomination of a method from it? Just reference your fields directly, you do not need this. @Override public void tick() public void update() So, you've blindly copied TileEntityFurnace and yet it never occured to you that it is a little bit strange that the TileEntityFurnace has no tick method at all yet you are for some reason required to override it, and when you put @Override over the update method you get an error? No, no concern at all? Again - you need to understand what is actually going on, not blindly copy classes and then hope everything works out. If you ever want to learn you need to start understanding. Also, auto-fix in eclipe isn't a magical "fix all my issues" button. Instead of using it here you need to try and understand why do you need to implement tick here. I am kinda going on a tangent here, and I am sorry if I sound rude or something, but I am trying to help you. The issue in this case is simple - you've implemented the wrong ITickable but if you actually stopped and thought about the issue for a minute instead of blindly applying auto-fix of eclipse then you woundn't have this issue in the first place. This applies to your other TileEntity too, the copper chest one. public Table<ItemStack, ItemStack, ItemStack> getDualSmeltingList() Again, this is not the first time I am seeing this. Why are you using a Table exactly? There is no reason to use Table here, this is not it's use case. Use a Triple<ItemStack, ItemStack, ItemStack> instead. Why do you have 2 of the same class LogStripperRecipes in 2 different packages? They are identical after all. Your TileEntityCopperChest implements IInventory. Not directly, through inheritance but still. Never do that. IInventory is a horrible artifact of the past and nobody should be ever using it. Use capabilities instead, like you are doing in your furnace TE. CommonProxy makes no sense. Proxies are to separate sided only code. If the code is common it goes into your main class. Do not use a CommonProxy, use an interface instead. Your NBTHandler methods are kinda broken. First of all when saving an ItemStack you also need to save it's NBT and capability data, not just it's registry name and count. And second of all ItemStack already implements the methods for (de)serializing it into NBT, there is no need for duplicate functionality. public interface IStructure { public static final WorldServer worldServer = FMLCommonHandler.instance().getMinecraftServerInstance().getWorld(0); public static final PlacementSettings settings = (new PlacementSettings()).setChunk(null).setIgnoreEntities(false).setIgnoreStructureBlock(false).setMirror(Mirror.NONE).setRotation(Rotation.NONE); } You really can't do this. This is not how anything works at all. These are static final fields meaning they get instantinated when the class is loaded. A lot of the things you are referencing here will be null by then. Quote public static final String SERVER = "com.almightyelement.thirteen.proxy.CommonProxy"; This makes even less sense than a CommonProxy. A server proxy is NOT your CommonProxy, it's a collection of methods that either provide a noop implementation for client-only stuff or reference server-only things. A server proxy can't and musn't be a CommonProxy. This is not how proxies work and they are not meant to be used like this.
October 28, 20186 yr Author Hey, Thank you for checking this out. The only explanation I can give to why I used some of these is because a lot of stuff that I didn't know, I searched up. And then implemented the things that most other people did in this mod. Once again thanks for helping a bit
October 28, 20186 yr 11 minutes ago, AlmightyElement said: And then implemented the things that most other people did in this mod. Popular != good. A lot of popular mods are actually quite badly written with a lot of bad practices in place and a ton of cargo-cult programming in place. I can recommend some trustworthy repositories for learning:
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.