
BlameTaw
Members-
Posts
16 -
Joined
-
Last visited
Everything posted by BlameTaw
-
Tile entity spawn stacks in world from GUI button
BlameTaw replied to BlameTaw's topic in Modder Support
I am registering the TileEntity. No errors in the logs. From some trace messages in the writeToNBT and readFromNBT functions it seems that the client never calls either function, and the server only ever calls the writeToNBT function...That's confusing to me. Okay I feel like I have messed up a lot of things...I'll have to play around with this a bit and get back to you. Whoops. -
Tile entity spawn stacks in world from GUI button
BlameTaw replied to BlameTaw's topic in Modder Support
I have an IGuiHandler that gets the server/client GUI elements. package com.blametaw.gui; import com.blametaw.itembuffers.blocks.TileEntityBasicBuffer; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.fml.common.network.IGuiHandler; public class BasicBufferGuiHandler implements IGuiHandler { private static final int GUIID = 1; public static int getGuiID(){return GUIID;} @Override public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { if (ID != getGuiID()) { System.err.println("Invalid ID: expected " + getGuiID() + ", received " + ID); } BlockPos xyz = new BlockPos(x, y, z); TileEntity tileEntity = world.getTileEntity(xyz); if (tileEntity instanceof TileEntityBasicBuffer) { TileEntityBasicBuffer tebb = (TileEntityBasicBuffer) tileEntity; return new ContainerBasicBuffer(player.inventory, tebb); } return null; } @Override public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { if (ID != getGuiID()) { System.err.println("Invalid ID: expected " + getGuiID() + ", received " + ID); } BlockPos xyz = new BlockPos(x, y, z); TileEntity tileEntity = world.getTileEntity(xyz); if (tileEntity instanceof TileEntityBasicBuffer) { TileEntityBasicBuffer tebb = (TileEntityBasicBuffer) tileEntity; return new GuiContainerBasicBuffer(new ContainerBasicBuffer(player.inventory, tebb)); } return null; } } And I'm calling it with this function in my Block: @Override public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ){ if (worldIn.isRemote) return true; playerIn.openGui(ItemBuffers.instance, BasicBufferGuiHandler.getGuiID(), worldIn, pos.getX(), pos.getY(), pos.getZ()); return true; } From what I understand, this should be opening it on both server and client. Also, I'd be surprised if this was the issue because moving things from the TE slots into the player inventory slots DOES work, and those changes are persistent. It's just that quit/reload resets the TE's NBT data. Also there are GUI buttons that update some other values in the NBT data, so I assume that should be done with IMessages as well, right? I didn't think about that before... When you quit/reload those numbers are also reset which implies they're also only happening client side. I've attached a picture of my GUI to give you more of an idea what I'm referring to. That might help a bit. -
Tile entity spawn stacks in world from GUI button
BlameTaw replied to BlameTaw's topic in Modder Support
In that case, maybe I have no idea how to ensure my entity's packet handling is correct...It's certainly something I didn't fully understand when researching about it. Here is everything I have for the packet handling in my tile entity class. Is there more that I need than just this? I will fully admit that I copy-pasted this from an example class I found, though I did make an effort to understand what it is doing. I assumed these functions are being automatically called by the Container and GuiContainer manipulations. Am I wrong? // // When the world loads from disk, the server needs to send the TileEntity information to the client // // it uses getUpdatePacket(), getUpdateTag(), onDataPacket(), and handleUpdateTag() to do this @Override @Nullable public SPacketUpdateTileEntity getUpdatePacket(){ NBTTagCompound updateTagDescribingTileEntityState = getUpdateTag(); final int METADATA = 0; return new SPacketUpdateTileEntity(this.pos, METADATA, updateTagDescribingTileEntityState); } @Override public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) { NBTTagCompound updateTagDescribingTileEntityState = pkt.getNbtCompound(); handleUpdateTag(updateTagDescribingTileEntityState); } /* Creates a tag containing the TileEntity information, used by vanilla to transmit from server to client Warning - although our getUpdatePacket() uses this method, vanilla also calls it directly, so don't remove it. */ @Override public NBTTagCompound getUpdateTag(){ NBTTagCompound nbtTagCompound = new NBTTagCompound(); writeToNBT(nbtTagCompound); return nbtTagCompound; } /* Populates this TileEntity with information from the tag, used by vanilla to transmit from server to client Warning - although our onDataPacket() uses this method, vanilla also calls it directly, so don't remove it. */ @Override public void handleUpdateTag(NBTTagCompound tag){ this.readFromNBT(tag); } -
Tile entity spawn stacks in world from GUI button
BlameTaw replied to BlameTaw's topic in Modder Support
Oh well maybe I'll try putting it there then... In the mean time, I just found that if you save/quit and reopen the game after modifying the TE's inventory through the GUI, the changes aren't saved so you can duplicate items... Why would changes to the slots not be happening server-side? Isn't that handled by the slot-click method in either Container or GuiContainer? (I forget what it's called and which one) Edit: it DOES make the proper item changes when ejecting items, it's only when manually moving stacks that changes are not made server-side. -
Tile entity spawn stacks in world from GUI button
BlameTaw replied to BlameTaw's topic in Modder Support
Fantastic, works like a charm! Thank you for all the help. I feel like I understand a lot more of the flow of this now. -
Tile entity spawn stacks in world from GUI button
BlameTaw replied to BlameTaw's topic in Modder Support
Ah okay that makes sense! So do I have to have the world ID passed in with the BlockPos in order to know which world to get? I see that both MinecraftServer and DimensionManager require an ID. Thanks for all the quick responses! Sorry for so many questions, I'm still very new to this API. -
Tile entity spawn stacks in world from GUI button
BlameTaw replied to BlameTaw's topic in Modder Support
I actually just figured it out. I didn't have a default constructor on the BufferEjectMessage. It is ejecting items now, however they are still phantom items. Is my message not actually executing server side, even though I'm calling sendToServer: Reference.networkWrapperInstance.sendToServer(new BufferEjectMessage(container.getTileEntity().getPos())); Does Minecraft.getMinecraft() not work for server-side? Is there another way I should be referencing the tile entity itself to call the eject functions? Also, is my assumption correct that I shouldn't be directly referencing the TileEntity from the message? That just seems like a threading nightmare waiting to happen... -
Tile entity spawn stacks in world from GUI button
BlameTaw replied to BlameTaw's topic in Modder Support
Ah that makes sense. I didn't think about character encodings. Either way I'm only sending a BlockPos so it's easy to just send three ints. I'm having an InstantiationException when I close the GUI, however. Seems to be coming from a NoSuchMethodException on my BufferEjectMessage.<init>() implying an issue during construction, maybe? I don't know why that would be. (stacktrace in the spoiler below the code) Here is my IMessage implemention and IMessageHandler implementation: package com.blametaw.itembuffers.blocks; import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.util.math.BlockPos; import net.minecraft.world.WorldServer; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; import net.minecraftforge.items.CapabilityItemHandler; public class BufferEjectMessage implements IMessage { public BlockPos pos; //TileEntity Block Coordinates public BufferEjectMessage(int x, int y, int z){ this.pos = new BlockPos(x,y,z); } public BufferEjectMessage(BlockPos pos){ this.pos = pos; } @Override public void fromBytes(ByteBuf buf) { this.pos = new BlockPos(buf.readInt(), buf.readInt(), buf.readInt()); } @Override public void toBytes(ByteBuf buf) { buf.writeInt(pos.getX()); buf.writeInt(pos.getY()); buf.writeInt(pos.getZ()); } public static class MyMessageHandler implements IMessageHandler<BufferEjectMessage, IMessage> { @Override public IMessage onMessage(BufferEjectMessage message, MessageContext ctx) { //I assume this is wrong because I'd be greatly surprised if I was allowed to access game objects from within messages like this... TileEntityBasicBuffer te = (TileEntityBasicBuffer) Minecraft.getMinecraft().world.getTileEntity(message.pos); BufferStackHandler handler = (BufferStackHandler)te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null); handler.ejectExcessItems(); return null; } } } Error stacktrace: -
Tile entity spawn stacks in world from GUI button
BlameTaw replied to BlameTaw's topic in Modder Support
Oh wow I can't believe I missed that when I was looking at the other classes. Thanks! For the message itself, is there a common way people structure them? Is there a reason not to just convert a string to a byte array, or is it a better practice to just send relevant values and decode them on the other side? -
Tile entity spawn stacks in world from GUI button
BlameTaw replied to BlameTaw's topic in Modder Support
Is there a way to make it only happen when the GUI is closed, rather than when the button is pressed? I'm realizing that might make for a better user experience with this. If not, I'll try making it work on button press. -
Tile entity spawn stacks in world from GUI button
BlameTaw replied to BlameTaw's topic in Modder Support
Thanks, this looks like what I need. Do I need to make the changes on the client side, too, in this case? Like, when they click the button should I be modifying the stack amounts client-side AND server-side, and then spawning the stacks server-side only? (I assume spawning client and server at the same time would cause one phantom stack and one real stack.) -
Hello All, What is necessary to make a Tile Entity spawn stacks in the world from a GUI button press? I can make it work in the client side only, so I get phantom stacks in the world, and the inventory slot for the TileEntity refills to what it was if the GUI is closed and reopened. How do I make it happen server-side, too? Is there a standard way of communicating client-side changes to server-side?
-
Update comparator signal when inventory changes
BlameTaw replied to BlameTaw's topic in Modder Support
How do I get a reference to the world from the ItemStackHandler object? Would I just have to pass a reference to the TileEntity itself in the ItemStackHandler subclass? I was hoping somehow inserting an item could trigger an update on the block itself and from there I could trigger another block update on the surrounding blocks to make the comparator update. It could easily be that I just don't understand the flow of the minecraft code yet though and adding a TileEntity reference would be the best option. -
Update comparator signal when inventory changes
BlameTaw replied to BlameTaw's topic in Modder Support
That seems like it could be useful, but I'm not sure where I would get an update event for the inventory changing. -
Update comparator signal when inventory changes
BlameTaw replied to BlameTaw's topic in Modder Support
Thanks for the response. I have not had any difficulty setting up the inventory at all. I am using the capability system for that and using an ItemStackHandler. Currently it just contains a single stack of items and that's it. I'll be extending the ItemStackHandler to create more specific handling of the items once I can get this basic part working. My issue is with updating the adjacent comparator when the inventory's contents change. Currently you have to cause a block update to the comparator before it will switch to an updated redstone signal. Here are some images of what I'm talking about: Here is the code for my block and tile entity. Currently VERY simplistic. I just want to get redstone controls working before messing everything else up. BlockBasicBuffer.java: package com.blametaw.itembuffers.blocks; import net.minecraft.block.BlockContainer; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.inventory.InventoryHelper; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.BlockRenderLayer; import net.minecraft.util.EnumBlockRenderType; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; import com.blametaw.itembuffers.Reference; public class BlockBasicBuffer extends BlockContainer { public BlockBasicBuffer() { super(Material.IRON); setUnlocalizedName(Reference.ItemBufferBlocks.BASICBUFFER.getUnlocalizedName()); setRegistryName(Reference.ItemBufferBlocks.BASICBUFFER.getRegistryName()); setResistance(6.0f); } @Override public TileEntity createNewTileEntity(World worldIn, int meta) { return new TileEntityBasicBuffer(); } @Override public void breakBlock(World world, BlockPos pos, IBlockState state) { TileEntityBasicBuffer te = (TileEntityBasicBuffer) world.getTileEntity(pos); IItemHandler handler = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null); for(int slot = 0; slot < handler.getSlots(); slot++){ ItemStack stack = handler.getStackInSlot(slot); InventoryHelper.spawnItemStack(world,pos.getX(),pos.getY(),pos.getZ(),stack); } super.breakBlock(world, pos, state); } @Override public boolean hasTileEntity(IBlockState state){ return true; } @SideOnly(Side.CLIENT) public BlockRenderLayer getBlockLayer() { return BlockRenderLayer.SOLID; } @Override public EnumBlockRenderType getRenderType(IBlockState iBlockState) { return EnumBlockRenderType.MODEL; } @Override public boolean hasComparatorInputOverride(IBlockState state) { return true; } @Override public int getComparatorInputOverride(IBlockState state, World world, BlockPos pos){ TileEntityBasicBuffer te = (TileEntityBasicBuffer) world.getTileEntity(pos); IItemHandler handler = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null); if (handler.getStackInSlot(0) != null && handler.getStackInSlot(0).getCount() > 0){ //Return 15 for now. Eventually will modulate based on inventory space. return 15; } return 0; } } TileEntityBasicBuffer.java: package com.blametaw.itembuffers.blocks; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.ItemStackHandler; public class TileEntityBasicBuffer extends TileEntity implements ICapabilityProvider{ private ItemStackHandler handler; public TileEntityBasicBuffer(){ //Currently just a stack of 1 item. this.handler = new ItemStackHandler(1); } @Override public void readFromNBT(NBTTagCompound nbt) { //TODO: Read stuff here this.handler.deserializeNBT(nbt.getCompoundTag("ItemStackHandler")); super.readFromNBT(nbt); } @Override public NBTTagCompound writeToNBT(NBTTagCompound nbt) { //TODO: Write stuff here nbt.setTag("ItemStackHandler", this.handler.serializeNBT()); return super.writeToNBT(nbt); } @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); } @Override public boolean hasCapability(Capability<?> capability, EnumFacing facing) { if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { return true; } return super.hasCapability(capability, facing); } } -
Hi all, I'm new to the modding APIs and working on a very simple mod with some customized inventories. I am able to modify the signal for comparators based on inventory contents, but adding/removing an item from the inventory doesn't send a block update to the connected comparator itself. Placing a block next to the comparator or otherwise causing an update will make it output the proper signal. How can I make my tile entity update the comparator when the inventory updates? I assume I have to use a custom ItemStackHandler or something else to trigger a block update when items are inserted or removed, but I'm not sure if that's correct, nor am I sure how to proceed if it is correct. If it's not correct, my second assumption would be something in the update function? Thanks for the help,