Jump to content

[SOLVED] Change NBT tag of ItemStack in container from GUI


Recommended Posts

Posted

hello

 

I'm trying to change a tag in the NBT data of an itemstack that is in a container from a gui (on the press of a button).

 

when the button is pressed, the packet seems to be successfully sent and processed, but nothing happens.

 

Packet/handler

 

 

package com.zpig333.runesofwizardry.gui;

import cpw.mods.fml.common.network.ByteBufUtils;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
import io.netty.buffer.ByteBuf;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
/**@see http://www.minecraftforge.net/forum/index.php/topic,20135.0.html
* 
*/
public class DustDyeButtonPacket implements IMessage {

    private String text;
    private int color;
    //private TileEntityDustDye source;
    private ItemStack stack;
    private int type;
    private int x,y,z; //position of the tileentity
    public final static int TYPE_TEXT=0,
                            TYPE_DYE=1;

    public DustDyeButtonPacket(){
        this.type=-1;
    }

    public DustDyeButtonPacket(int color, ItemStack stack){
        this.type=TYPE_DYE;
        this.color=color;
        this.stack=stack;
        //DEBUG
        System.out.println("packet created");
    }
    public DustDyeButtonPacket(int x, int y, int z, int color){
        this.type=TYPE_DYE;
        this.x=x;
        this.y=y;
        this.z=z;
        this.color=color;
    }
    @Override
    public void fromBytes(ByteBuf buf) {
        type=ByteBufUtils.readVarShort(buf);
       /* try {
            ObjectInputStream stream =new ObjectInputStream(new ByteBufInputStream(buf));
            Object in=stream.readObject();
            if(in instanceof TileEntityDustDye){
                source=(TileEntityDustDye)in;
            }
        } catch (IOException ex) {
            Logger.getLogger(DustDyeButtonPacket.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(DustDyeButtonPacket.class.getName()).log(Level.SEVERE, null, ex);
        }*/
        if(type==TYPE_TEXT){
            text = ByteBufUtils.readUTF8String(buf); // this class is very useful in general for writing more complex objects
        }else if(type==TYPE_DYE){
            color=ByteBufUtils.readVarInt(buf, 5);
            //stack=ByteBufUtils.readItemStack(buf);
            x=ByteBufUtils.readVarInt(buf, 5);
            y=ByteBufUtils.readVarInt(buf, 5);
            z=ByteBufUtils.readVarInt(buf, 5);
        }
        
        //DEBUG
        System.out.println("packet decoded");
    }

    @Override
    public void toBytes(ByteBuf buf) {
        ByteBufUtils.writeVarShort(buf, type);
       /* ObjectOutputStream stream;
        try {
            stream = new ObjectOutputStream(new ByteBufOutputStream(buf));
            stream.writeObject(source);
        } catch (IOException ex) {
            Logger.getLogger(DustDyeButtonPacket.class.getName()).log(Level.SEVERE, null, ex);
        }*/
        if(type==TYPE_TEXT){
            ByteBufUtils.writeUTF8String(buf, text);
        }else if(type==TYPE_DYE){
            ByteBufUtils.writeVarInt(buf, color, 5);
            //ByteBufUtils.writeItemStack(buf, stack);
            ByteBufUtils.writeVarInt(buf, x, 5);
            ByteBufUtils.writeVarInt(buf, y, 5);
            ByteBufUtils.writeVarInt(buf, z, 5);
        }
        //DEBUG
        System.out.println("packet encoded");
    }

    public static class Handler implements IMessageHandler<DustDyeButtonPacket, IMessage> {

        @Override
        public IMessage onMessage(DustDyeButtonPacket message, MessageContext ctx) {
            //TODO what to do when the button is clicked
            System.out.println(String.format("Received %s from %s", message, ctx.getServerHandler().playerEntity.getDisplayName()));
           // System.out.println("type: "+message.type+" stack: "+message.stack);
            //System.out.println("stack color: "+message.stack.getTagCompound().getInteger("color"));
            if(message.type==TYPE_DYE){
                System.out.println("color: "+message.color);
                //FIXME tis not do stuffz
                //message.stack.getTagCompound().setInteger("color", message.color);
                 //System.out.println("stack color: "+message.stack.getTagCompound().getInteger("color"));
                 //message.stack.writeToNBT(message.stack.getTagCompound());
                TileEntity te = ctx.getServerHandler().playerEntity.worldObj.getTileEntity(message.x, message.y, message.z);
                //FIXME fsr this does not recognize the import?
                if(te instanceof com.zpig333.runesofwizardry.tileentity.TileEntityDustDye){
                    com.zpig333.runesofwizardry.tileentity.TileEntityDustDye ted;
                    ted = (com.zpig333.runesofwizardry.tileentity.TileEntityDustDye)te;
                    ted.dye(message.color);
                }
            }else if(message.type==TYPE_TEXT){
                //message.source.setColor(message.text);
            }
            return null; // no response in this case
        }
    }
}

 

 

 

TileEntity

 

package com.zpig333.runesofwizardry.tileentity;

import com.zpig333.runesofwizardry.item.ItemDyedDust;
import java.io.Serializable;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;


public class TileEntityDustDye extends TileEntity implements IInventory{
    //only 1 slot for now, might change if dyes are required as input
    private ItemStack[] contents = new ItemStack[1];
    //the currently selected color
    private String colorString;
    
    public TileEntityDustDye(){
        super();
        //colorString="Color";
    }
    public void dye(int color){
        contents[0].getTagCompound().setInteger("color", color);
        setColor(Integer.toHexString(color));
    }
    /**
     * 
     * @return the currently selected Color of this block as a String
     */
    public String getColor(){
        return colorString;
    }
    /**
     * 
     * @param color the selected color
     */
    public void setColor(String color){
        colorString=color;
    }
    @Override
    public int getSizeInventory() {
        return contents.length;
    }

    @Override
    public ItemStack getStackInSlot(int i1) {
        return contents[i1];
    }
    
    /**
     * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a
     * new stack.
     */
    @Override
    public ItemStack decrStackSize(int slot, int number)
    {
        if (this.contents[slot] != null)
        {
            ItemStack itemstack;

            if (this.contents[slot].stackSize <= number)
            {
                itemstack = this.contents[slot];
                this.contents[slot] = null;
                return itemstack;
            }
            else
            {
                itemstack = this.contents[slot].splitStack(number);

                if (this.contents[slot].stackSize == 0)
                {
                    this.contents[slot] = null;
                }

                return itemstack;
            }
        }
        else
        {
            return null;
        }
    }
    /**
     * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections).
     */
    @Override
     public void setInventorySlotContents(int slot, ItemStack stack) {
        contents[slot]=stack;
        contents[slot] = stack;
        /*        if (stack != null && stack.stackSize > getInventoryStackLimit()) {
                        stack.stackSize = getInventoryStackLimit();
                }              
        */
    }

    @Override
    /**
     * 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 slot) {
                ItemStack stack = getStackInSlot(slot);
                if (stack != null) {
                        setInventorySlotContents(slot, null);
                }
                return stack;
        }

    @Override
    /**
     * Returns the name of the inventory
     */
    public String getInventoryName()
    {
        return "RunesWiz.DustDye";
    }


    @Override
    public boolean isUseableByPlayer(EntityPlayer player) {
        return worldObj.getTileEntity(xCoord, yCoord, zCoord) == this &&
                player.getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5) < 64;
    }

    @Override
    public void openInventory() {
    }

    @Override
    public void closeInventory() {
    }

    @Override
    public boolean isItemValidForSlot(int slot, ItemStack stack) {
        
        //only allow dyed dust in the dyer
        return slot==0 ? stack.getItem() instanceof ItemDyedDust : false;
        //from tileentityBrewingStand
        //return p_94041_1_ == 3 ? p_94041_2_.getItem().isPotionIngredient(p_94041_2_) : p_94041_2_.getItem() instanceof ItemPotion || p_94041_2_.getItem() == Items.glass_bottle;
        //TODO auto-generated method: isItemValidForSlot
        //throw new UnsupportedOperationException("Not supported yet: isItemValidForSlot");
    }
    @Override
    public int getInventoryStackLimit() {
        return 64;
    }

    @Override
    public boolean hasCustomInventoryName() {
        return true;
    }
    
    @Override
    public void readFromNBT(NBTTagCompound tagCompound) {
                super.readFromNBT(tagCompound);
               
                NBTTagList tagList = tagCompound.getTagList("Inventory",10);
                for (int i = 0; i < tagList.tagCount(); i++) {
                        NBTTagCompound tag = tagList.getCompoundTagAt(i);
                        byte slot = tag.getByte("Slot");
                        if (slot >= 0 && slot < contents.length) {
                                contents[slot] = ItemStack.loadItemStackFromNBT(tag);
                        }
                }
                this.colorString=tagCompound.getString("Color");
        }
        //FIXME fsr, the color string does not save between game sessions
        @Override
        public void writeToNBT(NBTTagCompound tagCompound) {
                super.writeToNBT(tagCompound);
                               
                NBTTagList itemList = new NBTTagList();
                for (int i = 0; i < contents.length; i++) {
                        ItemStack stack = contents[i];
                        if (stack != null) {
                                NBTTagCompound tag = new NBTTagCompound();
                                tag.setByte("Slot", (byte) i);
                                stack.writeToNBT(tag);
                                itemList.appendTag(tag);
                        }
                }
                tagCompound.setTag("Inventory", itemList);
                tagCompound.setString("Color", colorString);
                
        }

}

 

 

Container

 

package com.zpig333.runesofwizardry.client.container;

import com.zpig333.runesofwizardry.item.ItemDyedDust;
import com.zpig333.runesofwizardry.tileentity.TileEntityDustDye;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;

public class ContainerDustDye extends Container {

    protected TileEntityDustDye tileEntity;

    public ContainerDustDye(InventoryPlayer inventoryPlayer, TileEntityDustDye te) {
        tileEntity = te;

        //the Slot constructor takes the IInventory and the slot number in that it binds to
        //and the x-y coordinates it resides on-screen
        addSlotToContainer(new ContainerDustDye.Dye(tileEntity, 0, 116,30));
        /*for (int i = 0; i < 1; i++) {
            for (int j = 0; j < 1; j++) {
                addSlotToContainer(new Slot(tileEntity, j + i * 3, 62 + j * 18, 17 + i * 18));
            }
        }*/

        //commonly used vanilla code that adds the player's inventory
        bindPlayerInventory(inventoryPlayer);
    }

    @Override
    public boolean canInteractWith(EntityPlayer player) {
        return tileEntity.isUseableByPlayer(player);
    }

    protected void bindPlayerInventory(InventoryPlayer inventoryPlayer) {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 9; j++) {
                addSlotToContainer(new Slot(inventoryPlayer, j + i * 9 + 9,
                        8 + j * 18, 84 + i * 18));
            }
        }

        for (int i = 0; i < 9; i++) {
            addSlotToContainer(new Slot(inventoryPlayer, i, 8 + i * 18, 142));
        }
    }

    @Override
    public ItemStack transferStackInSlot(EntityPlayer player, int slot) {
        ItemStack stack = null;
        Slot slotObject = (Slot) inventorySlots.get(slot);

        //null checks and checks if the item can be stacked (maxStackSize > 1)
        if (slotObject != null && slotObject.getHasStack()) {
            ItemStack stackInSlot = slotObject.getStack();
            stack = stackInSlot.copy();

            //merges the item into player inventory since its in the tileEntity
            if (slot < 9) {
                if (!this.mergeItemStack(stackInSlot, 0, 35, true)) {
                    return null;
                }
            } //places it into the tileEntity is possible since its in the player inventory
            else if (!this.mergeItemStack(stackInSlot, 0, 9, false)) {
                return null;
            }

            if (stackInSlot.stackSize == 0) {
                slotObject.putStack(null);
            } else {
                slotObject.onSlotChanged();
            }

            if (stackInSlot.stackSize == stack.stackSize) {
                return null;
            }
            slotObject.onPickupFromSlot(player, stackInSlot);
        }
        return stack;
    }
    
    static class Dye extends Slot{
        public Dye(IInventory inv, int a, int b, int c){
            super(inv, a, b, c);
        }
        @Override
        public boolean isItemValid(ItemStack stack){
            //only allow dyed dusts in the slot
            return stack.getItem() instanceof ItemDyedDust;
        }
    }
}

 

 

GUI

 

package com.zpig333.runesofwizardry.gui;

//TODO maybe the lwjgl color should be used?
import java.awt.Color;
import com.zpig333.runesofwizardry.RunesOfWizardry;
import com.zpig333.runesofwizardry.client.container.ContainerDustDye;
import com.zpig333.runesofwizardry.core.References;
import com.zpig333.runesofwizardry.core.ModLogger;
import com.zpig333.runesofwizardry.tileentity.TileEntityDustDye;
import net.minecraft.client.gui.FontRenderer;

import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.InventoryPlayer;

import org.lwjgl.opengl.GL11;

import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;

import org.lwjgl.input.Keyboard;
/*TODO major cleanup required, 
* this is a mashup from many different examples/tutorials
* there is probably a lot of useless code
*/
public class GuiDustDye extends GuiContainer {

    public static final int GUI_ID = 1;
    public static final int GUI_DYE_BUTTON=0;
    
    private static final int textureX = 175,
                             textureY = 166;

    private String colorString;
    private Color color;
    private int colorInt=0;
    private boolean validColor=false;
    
    private GuiTextField textColor;
    //the tile entity source for this GUI
    private final TileEntityDustDye PARENT;
    public GuiDustDye(InventoryPlayer inventoryPlayer,
            TileEntityDustDye tileEntity) {
        //the container is instanciated and passed to the superclass for handling
        super(new ContainerDustDye(inventoryPlayer, tileEntity));
        //sets the parent entity
        PARENT=tileEntity;
        colorString=PARENT.getColor();
        if(colorString==null)colorString="Color";
    }
    /** runs once every time the GUI is opened
     * 
     */
    @Override
    public void initGui(){
      super.initGui();
      Keyboard.enableRepeatEvents(true);
      //posX, posY defines the top left pixel of the gui display
      int posX = (this.width - textureX) /2;
      int posY = (this.height - textureY) /2;
     
      //GuiTextField(fontrenderer, x, y, sizeX, sizeY)
      //here, 0,0 is the top left of the texture...
      textColor = new GuiTextField(this.fontRendererObj, 105, 14, 45, 12);
      textColor.setMaxStringLength(6);
      textColor.setEnableBackgroundDrawing(false);
      textColor.setVisible(true);
      textColor.setTextColor(16777215);
      textColor.setText(colorString);
      updateColor();
      textColor.setFocused(true);
      textColor.setCanLoseFocus(true);
      //textColor.setDisabledTextColour(16777215);
      //textColor.setCursorPositionEnd();
      
     //id, x, y, width, height, text
      //note: height seems to need to be 20 to display full button texture
      buttonList.add(new GuiButton(GUI_DYE_BUTTON,posX+99,posY+55,50,20,"Dye"));
      
      
    }
    
    @Override
    public void updateScreen(){
        textColor.updateCursorCounter();
    }
    @Override
    public void onGuiClosed(){
      super.onGuiClosed();
      Keyboard.enableRepeatEvents(false);
    }
    /**when a key is typed. equivalent of keyListener
     * 
     * @param par1
     * @param par2 
     */
    @Override
    protected void keyTyped(char par1, int par2){
       /* if(textColor.isFocused()){
            textColor.textboxKeyTyped(par1, par2);
            colorString = textColor.getText();
            PARENT.setColor(colorString);
            try{
                //parsing in hexadecimal allows for a more natural, html-style color input
                colorInt=Integer.parseInt(colorString,16);
            	color = new Color(colorInt);
                validColor=true;
            }catch(NumberFormatException e){
                //this might spam a bit...
                ModLogger.logDebug("GuiDustDye could not parse colorString to Integer");
                validColor=false;
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        if(!textColor.isFocused()||par2 == '27'){
        super.keyTyped(par1, par2);
    }*/
        
        if(textColor.textboxKeyTyped(par1, par2)){
            colorString = textColor.getText();
           // RunesOfWizardry.networkWrapper.sendToServer(new DustDyeButtonPacket(colorString, PARENT));
            updateColor();
        }else{
            super.keyTyped(par1, par2);
        }
    }
    /** updates the color to the text
     * 
     */
    private void updateColor(){
        try{
                //parsing in hexadecimal allows for a more natural, html-style color input
                //that is, 2 (hex) digits per color (RGB)
                colorInt=Integer.parseInt(colorString,16);
            	color = new Color(colorInt);
                validColor=true;
            }catch(NumberFormatException e){
                //this might spam a bit...
                ModLogger.logDebug("GuiDustDye could not parse colorString to Integer");
                validColor=false;
            }catch(Exception e){
                e.printStackTrace();
            }
    }
    @Override
    protected void mouseClicked(int par1, int par2, int par3){
    	//posX, posY defines the top left pixel of the gui display
        int posX = (this.width - textureX) /2;
        int posY = (this.height - textureY) /2;
    	//DEBUG flag used by textColor.mouseClicked
        /*
    	boolean flag = par1 >= textColor.xPosition && par1 < textColor.xPosition + textColor.width && par2 >= textColor.yPosition && par2 < textColor.yPosition + textColor.height;
    	System.out.println(flag+": par1="+par1+" par2="+par2+
    			"\nx="+textColor.xPosition+" y="+textColor.yPosition+
    			"\nwidth="+textColor.width+" height="+textColor.height+
    			"\npassed: "+(par1-posX)+", "+(par2-posY));
                        */
    	/*Well, it seems the click is located relative to the window, 
    	 * while the text field position depends on the texture
    	 * WTF Minecraft?
    	 * anyways, compensating...
    	 */
    	textColor.mouseClicked(par1-posX, par2-posY, par3);
    	super.mouseClicked(par1, par2, par3);
    }

    /** runs while the GUI is open
     * 
     * @param param1
     * @param param2 
     */
    @Override
    protected void drawGuiContainerForegroundLayer(int param1, int param2) {
        //draw text and stuff here
        //the parameters for drawString are: string, x, y, color
        fontRendererObj.drawString("Dust Dye", 8, 6, 4210752);
        //draws "Inventory" or your regional equivalent
        fontRendererObj.drawString(StatCollector.translateToLocal("container.inventory"), 8, ySize - 96 + 2, 4210752);
        textColor.drawTextBox();
        if(!validColor){
        	//TODO this is slightly small
        	fontRendererObj.drawString("!", 98, 15, 0xFF0000);
        }
        // x1, y1, x2, y2, color (NOTE: first byte (2 char) of color is alpha)
        drawRect(77, 59, 92, 71, 0xff000000+colorInt);
        //fontRendererObj.drawString("##", 0, 0, colorInt);
        //super.drawGuiContainerForegroundLayer(param1, param2);
    }

    @Override
    protected void drawGuiContainerBackgroundLayer(float par1, int par2,
            int par3) {
        //draw your Gui here, only thing you need to change is the path
        GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
        this.mc.renderEngine.bindTexture(new ResourceLocation(References.texture_path+"textures/gui/GuiDustDye.png"));
        int x = (width - xSize) / 2;
        int y = (height - ySize) / 2;
        this.drawTexturedModalRect(x, y, 0, 0, xSize, ySize);
    }
    /** called when a button is clicked
     * 
     * @param button the button that was clicked (?)
     */
    protected void actionPerformed(GuiButton button){
    	switch(button.id){
    	case GUI_DYE_BUTTON: 
    		//send the selected colour to the server
    		RunesOfWizardry.networkWrapper.sendToServer(new DustDyeButtonPacket(colorInt,PARENT.getStackInSlot(0)));
                //Hopefully this will work
                //FIXME nope, reset when it leaves GUI
                //PARENT.getStackInSlot(0).getTagCompound().setInteger("color", colorInt);
    		//break;
    	default: System.out.println("Button clicked "+button.displayString+" "+button.id);
    		break;
    	}
    		
    	
    }
}

 

 

I can't figure what is not working, please help.

 

EDIT: forge 1.7.10 (1.7.10-10.13.0.1188)

Posted

When you say nothing happens, are you logging the expected changes on the server or client?

 

In my example, I send the updated info back to the client as the return to the Imessage (another packet)

 

@Override
        public IMessage onMessage(ChangeCostUp message, MessageContext ctx) {
        	
        	EntityPlayer player = ctx.getServerHandler().playerEntity;
        	ContainerShop container = (ContainerShop)player.openContainer;     
            
        	container.tileEntity.Cost++;
        	if(container.tileEntity.Cost > 144) container.tileEntity.Cost = 144;
        	player.worldObj.markBlockForUpdate(container.tileEntity.xCoord, container.tileEntity.yCoord, container.tileEntity.zCoord);
        	container.tileEntity.markDirty();        	
        	
        	return new SendCost((short) container.tileEntity.Cost); 
        }

 

whether you are updating a field (in my case) or NBT (yours) the situation should be the same.

I'll need help, and I'll give help. Just ask, you know I will!

Posted

..to clarify my example, the client has a gui open, presses a button, and then this packet is sent to the server for processing, where the value is changed. I returned a packet to update the client from this, where you are only returning null. Guis sit on the client alone, and so will not be updating automatically. Again, my first question would be where are you watching the value to which nothing is happening?

I'll need help, and I'll give help. Just ask, you know I will!

Posted
where are you watching the value to which nothing is happening

 

I'm not sure... I would guess on the client (the item in question changes its rendering depending on the NBT, and it does not change when the button is pressed). that said, it is not updated on world reload either.

 

I see I don't mark the tileentity as dirty, I'll try that...

 

also, out of curiosity, how do you handle your SendCost packet (reply) on the client?

Posted

return new SendCost((short) container.tileEntity.Cost);

 

In this scenario, SendCost is just another packet, registered on the client side, not the server. So just like any other packet.

 

network.registerMessage(PacketToServer.Handler.class, PacketToServer.class, 0, Side.SERVER);
    	network.registerMessage(ResponseToClient.Handler.class, ResponseToClient.class, 1, Side.CLIENT);

 

@Override
        public IMessage onMessage(PacketToServer message, MessageContext ctx) {
        	
        	
        	return new ResponseToClient(); 
        }

 

@Override
        public IMessage onMessage(ResponseToClient message, MessageContext ctx) {
        	
        	
        	return null;
        }

 

 

I'll need help, and I'll give help. Just ask, you know I will!

Posted

I meant to update the client...

 

I tried setting up a reply, but the item still does not change. I mus be doing something wrong, but I can't find what

 

packet

 

package com.zpig333.runesofwizardry.gui;

import cpw.mods.fml.common.network.ByteBufUtils;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
/**@see http://www.minecraftforge.net/forum/index.php/topic,20135.0.html
* 
*/
public class DustDyeButtonPacket implements IMessage {

    private String text;
    private int color;
    //private TileEntityDustDye source;
    private ItemStack stack;
    private int type;
    private int x,y,z; //position of the tileentity
    public final static int TYPE_TEXT=0,
                            TYPE_DYE=1,
                            TYPE_REPLY=2;

    public DustDyeButtonPacket(){
        this.type=-1;
    }

    public DustDyeButtonPacket(int color, ItemStack stack){
        this.type=TYPE_REPLY;
        this.color=color;
        this.stack=stack;
        //DEBUG
        System.out.println("packet created");
    }
    public DustDyeButtonPacket(int x, int y, int z, int color){
        this.type=TYPE_DYE;
        this.x=x;
        this.y=y;
        this.z=z;
        this.color=color;
    }
    @Override
    public void fromBytes(ByteBuf buf) {
        type=ByteBufUtils.readVarShort(buf);
       /* try {
            ObjectInputStream stream =new ObjectInputStream(new ByteBufInputStream(buf));
            Object in=stream.readObject();
            if(in instanceof TileEntityDustDye){
                source=(TileEntityDustDye)in;
            }
        } catch (IOException ex) {
            Logger.getLogger(DustDyeButtonPacket.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(DustDyeButtonPacket.class.getName()).log(Level.SEVERE, null, ex);
        }*/
        if(type==TYPE_TEXT){
            text = ByteBufUtils.readUTF8String(buf); // this class is very useful in general for writing more complex objects
        }else if(type==TYPE_DYE){
            color=ByteBufUtils.readVarInt(buf, 5);
            //stack=ByteBufUtils.readItemStack(buf);
            x=ByteBufUtils.readVarInt(buf, 5);
            y=ByteBufUtils.readVarInt(buf, 5);
            z=ByteBufUtils.readVarInt(buf, 5);
        }else if(type==TYPE_REPLY){
            color=ByteBufUtils.readVarInt(buf, 5);
            stack=ByteBufUtils.readItemStack(buf);
        }
        
        //DEBUG
        System.out.println("packet decoded");
    }

    @Override
    public void toBytes(ByteBuf buf) {
        ByteBufUtils.writeVarShort(buf, type);
       /* ObjectOutputStream stream;
        try {
            stream = new ObjectOutputStream(new ByteBufOutputStream(buf));
            stream.writeObject(source);
        } catch (IOException ex) {
            Logger.getLogger(DustDyeButtonPacket.class.getName()).log(Level.SEVERE, null, ex);
        }*/
        if(type==TYPE_TEXT){
            ByteBufUtils.writeUTF8String(buf, text);
        }else if(type==TYPE_DYE){
            ByteBufUtils.writeVarInt(buf, color, 5);
            //ByteBufUtils.writeItemStack(buf, stack);
            ByteBufUtils.writeVarInt(buf, x, 5);
            ByteBufUtils.writeVarInt(buf, y, 5);
            ByteBufUtils.writeVarInt(buf, z, 5);
        }else if(type==TYPE_REPLY){
            ByteBufUtils.writeVarInt(buf, color, 5);
            ByteBufUtils.writeItemStack(buf, stack);
        }
        //DEBUG
        System.out.println("packet encoded");
    }

    public static class Handler implements IMessageHandler<DustDyeButtonPacket, IMessage> {

        @Override
        public IMessage onMessage(DustDyeButtonPacket message, MessageContext ctx) {
            //TODO what to do when the button is clicked
            System.out.println(String.format("Received %s from %s", message, ctx.getServerHandler().playerEntity.getDisplayName()));
           // System.out.println("type: "+message.type+" stack: "+message.stack);
            //System.out.println("stack color: "+message.stack.getTagCompound().getInteger("color"));
            if(message.type==TYPE_DYE){
                System.out.println("color: "+message.color);
                //FIXME tis not do stuffz
                //message.stack.getTagCompound().setInteger("color", message.color);
                 //System.out.println("stack color: "+message.stack.getTagCompound().getInteger("color"));
                 //message.stack.writeToNBT(message.stack.getTagCompound());
                EntityPlayer player = ctx.getServerHandler().playerEntity;
                TileEntity te = player.worldObj.getTileEntity(message.x, message.y, message.z);
                //FIXME fsr this does not recognize the import?
                if(te instanceof com.zpig333.runesofwizardry.tileentity.TileEntityDustDye){
                    com.zpig333.runesofwizardry.tileentity.TileEntityDustDye ted;
                    ted = (com.zpig333.runesofwizardry.tileentity.TileEntityDustDye)te;
                    ted.dye(message.color);
                    player.worldObj.markBlockForUpdate(ted.xCoord, ted.yCoord, ted.zCoord);
                    ted.markDirty();
                    return new DustDyeButtonPacket(message.color, ted.getStackInSlot(0));
                }
                
            }else if(message.type==TYPE_TEXT){
                return null;
                //message.source.setColor(message.text);
            }else if(message.type==TYPE_REPLY){
                message.stack.getTagCompound().setInteger("color", message.color);
                return null;
            }
            throw new IllegalArgumentException("Could not process message, "+message.type);
        }
    }
}

 

Posted

You can't send the same packet back to the client. What you want to do is simplify your packets as much as possible. For example, make a button that increases a value. This will send an empty pack to the server (and is registered to be handled by the server) called, lets say, InrcreaseValuePacket(). The server sees this packet, and increases the value. You can make as many buttons and packets as you like! Then each of those will have a relative packet, say RespondWithIncreasePacket(), that is registered on the client. If you send packet A to the server - where its registered to be handled - you cant send packet A back to the client, it won't ever hit the handler. You would make packet B and register is to be handled on the client. You can make unlimited packets, just make sure you register the handlers on the right side, and also you can minimize the information stored within. It looks like you are sending an UpdateEveryValueEver() packet to the server, and trying to send the UpdateEveryValueEver() packet right back to client (sometimes.)

 

One possible example of flow could/should be like this:

 

  • Player activates block which opens gui on the client only
  • Gui sends update request to server(packet A)
  • server responds with data the gui needs to display(packet B)
  • player clicks button to adjust a value
  • gui sends packet to adjust specific value to server(packet C)
  • server receives packet and changes value, responds with either total update (packet B) or value specific update (packet D)

 

Packets A and C would be registered to be handled on the server and would most likely hold 0 specific data whatsoever. the server would know what to do just based on the packet type.

 

Packets B and D would be registered to be handled on the client, and packet D would have the advantage of not carrying much data.

 

...I sure hope that makes sense/helps!

I'll need help, and I'll give help. Just ask, you know I will!

Posted

yes, this makes sense.

 

I tried doing that, but I have trouble understanding how to arrange the communication between the GUI and the packethandler.

 

if it helps, the full code is on GitHub.

 

  • 2 weeks later...
Posted

ok, i've set up a few new packets in an attempt to properly update things, but I get a crash when opening the GUI.

 

log:

[15:56:55] [server thread/ERROR] [FML]: FMLIndexedMessageCodec exception caught
io.netty.handler.codec.DecoderException: java.lang.IndexOutOfBoundsException: readerIndex(11) + length(1) exceeds writerIndex(11): SlicedByteBuf(ridx: 11, widx: 11, cap: 11/11, unwrapped: UnpooledHeapByteBuf(ridx: 1, widx: 12, cap: 12/12))
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:99) ~[MessageToMessageDecoder.class:?]
at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111) ~[MessageToMessageCodec.class:?]
at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:337) [DefaultChannelHandlerContext.class:?]
at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:323) [DefaultChannelHandlerContext.class:?]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:785) [DefaultChannelPipeline.class:?]
at io.netty.channel.embedded.EmbeddedChannel.writeInbound(EmbeddedChannel.java:169) [EmbeddedChannel.class:?]
at cpw.mods.fml.common.network.internal.FMLProxyPacket.processPacket(FMLProxyPacket.java:86) [FMLProxyPacket.class:?]
at net.minecraft.network.NetworkManager.processReceivedPackets(NetworkManager.java:247) [NetworkManager.class:?]
at net.minecraft.network.NetworkSystem.networkTick(NetworkSystem.java:182) [NetworkSystem.class:?]
at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:736) [MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:624) [MinecraftServer.class:?]
at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:118) [integratedServer.class:?]
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:495) [MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer$2.run(MinecraftServer.java:762) [MinecraftServer$2.class:?]
Caused by: java.lang.IndexOutOfBoundsException: readerIndex(11) + length(1) exceeds writerIndex(11): SlicedByteBuf(ridx: 11, widx: 11, cap: 11/11, unwrapped: UnpooledHeapByteBuf(ridx: 1, widx: 12, cap: 12/12))
at io.netty.buffer.AbstractByteBuf.checkReadableBytes(AbstractByteBuf.java:1160) ~[AbstractByteBuf.class:?]
at io.netty.buffer.AbstractByteBuf.readByte(AbstractByteBuf.java:562) ~[AbstractByteBuf.class:?]
at cpw.mods.fml.common.network.ByteBufUtils.readVarInt(ByteBufUtils.java:46) ~[byteBufUtils.class:?]
at cpw.mods.fml.common.network.ByteBufUtils.readUTF8String(ByteBufUtils.java:118) ~[byteBufUtils.class:?]
at com.zpig333.runesofwizardry.gui.DustDyeUpdatePacket.fromBytes(DustDyeUpdatePacket.java:27) ~[DustDyeUpdatePacket.class:?]
at cpw.mods.fml.common.network.simpleimpl.SimpleIndexedCodec.decodeInto(SimpleIndexedCodec.java:17) ~[simpleIndexedCodec.class:?]
at cpw.mods.fml.common.network.simpleimpl.SimpleIndexedCodec.decodeInto(SimpleIndexedCodec.java:7) ~[simpleIndexedCodec.class:?]
at cpw.mods.fml.common.network.FMLIndexedMessageToMessageCodec.decode(FMLIndexedMessageToMessageCodec.java:77) ~[FMLIndexedMessageToMessageCodec.class:?]
at cpw.mods.fml.common.network.FMLIndexedMessageToMessageCodec.decode(FMLIndexedMessageToMessageCodec.java:17) ~[FMLIndexedMessageToMessageCodec.class:?]
at io.netty.handler.codec.MessageToMessageCodec$2.decode(MessageToMessageCodec.java:81) ~[MessageToMessageCodec$2.class:?]
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:89) ~[MessageToMessageDecoder.class:?]
... 13 more
[15:56:55] [server thread/ERROR] [FML]: SimpleChannelHandlerWrapper exception
io.netty.handler.codec.DecoderException: java.lang.IndexOutOfBoundsException: readerIndex(11) + length(1) exceeds writerIndex(11): SlicedByteBuf(ridx: 11, widx: 11, cap: 11/11, unwrapped: UnpooledHeapByteBuf(ridx: 1, widx: 12, cap: 12/12))
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:99) ~[MessageToMessageDecoder.class:?]
at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111) ~[MessageToMessageCodec.class:?]
at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:337) [DefaultChannelHandlerContext.class:?]
at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:323) [DefaultChannelHandlerContext.class:?]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:785) [DefaultChannelPipeline.class:?]
at io.netty.channel.embedded.EmbeddedChannel.writeInbound(EmbeddedChannel.java:169) [EmbeddedChannel.class:?]
at cpw.mods.fml.common.network.internal.FMLProxyPacket.processPacket(FMLProxyPacket.java:86) [FMLProxyPacket.class:?]
at net.minecraft.network.NetworkManager.processReceivedPackets(NetworkManager.java:247) [NetworkManager.class:?]
at net.minecraft.network.NetworkSystem.networkTick(NetworkSystem.java:182) [NetworkSystem.class:?]
at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:736) [MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:624) [MinecraftServer.class:?]
at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:118) [integratedServer.class:?]
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:495) [MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer$2.run(MinecraftServer.java:762) [MinecraftServer$2.class:?]
Caused by: java.lang.IndexOutOfBoundsException: readerIndex(11) + length(1) exceeds writerIndex(11): SlicedByteBuf(ridx: 11, widx: 11, cap: 11/11, unwrapped: UnpooledHeapByteBuf(ridx: 1, widx: 12, cap: 12/12))
at io.netty.buffer.AbstractByteBuf.checkReadableBytes(AbstractByteBuf.java:1160) ~[AbstractByteBuf.class:?]
at io.netty.buffer.AbstractByteBuf.readByte(AbstractByteBuf.java:562) ~[AbstractByteBuf.class:?]
at cpw.mods.fml.common.network.ByteBufUtils.readVarInt(ByteBufUtils.java:46) ~[byteBufUtils.class:?]
at cpw.mods.fml.common.network.ByteBufUtils.readUTF8String(ByteBufUtils.java:118) ~[byteBufUtils.class:?]
at com.zpig333.runesofwizardry.gui.DustDyeUpdatePacket.fromBytes(DustDyeUpdatePacket.java:27) ~[DustDyeUpdatePacket.class:?]
at cpw.mods.fml.common.network.simpleimpl.SimpleIndexedCodec.decodeInto(SimpleIndexedCodec.java:17) ~[simpleIndexedCodec.class:?]
at cpw.mods.fml.common.network.simpleimpl.SimpleIndexedCodec.decodeInto(SimpleIndexedCodec.java:7) ~[simpleIndexedCodec.class:?]
at cpw.mods.fml.common.network.FMLIndexedMessageToMessageCodec.decode(FMLIndexedMessageToMessageCodec.java:77) ~[FMLIndexedMessageToMessageCodec.class:?]
at cpw.mods.fml.common.network.FMLIndexedMessageToMessageCodec.decode(FMLIndexedMessageToMessageCodec.java:17) ~[FMLIndexedMessageToMessageCodec.class:?]
at io.netty.handler.codec.MessageToMessageCodec$2.decode(MessageToMessageCodec.java:81) ~[MessageToMessageCodec$2.class:?]
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:89) ~[MessageToMessageDecoder.class:?]
... 13 more
[15:56:55] [server thread/ERROR] [FML]: SimpleChannelHandlerWrapper exception
io.netty.handler.codec.DecoderException: java.lang.IndexOutOfBoundsException: readerIndex(11) + length(1) exceeds writerIndex(11): SlicedByteBuf(ridx: 11, widx: 11, cap: 11/11, unwrapped: UnpooledHeapByteBuf(ridx: 1, widx: 12, cap: 12/12))
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:99) ~[MessageToMessageDecoder.class:?]
at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111) ~[MessageToMessageCodec.class:?]
at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:337) [DefaultChannelHandlerContext.class:?]
at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:323) [DefaultChannelHandlerContext.class:?]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:785) [DefaultChannelPipeline.class:?]
at io.netty.channel.embedded.EmbeddedChannel.writeInbound(EmbeddedChannel.java:169) [EmbeddedChannel.class:?]
at cpw.mods.fml.common.network.internal.FMLProxyPacket.processPacket(FMLProxyPacket.java:86) [FMLProxyPacket.class:?]
at net.minecraft.network.NetworkManager.processReceivedPackets(NetworkManager.java:247) [NetworkManager.class:?]
at net.minecraft.network.NetworkSystem.networkTick(NetworkSystem.java:182) [NetworkSystem.class:?]
at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:736) [MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:624) [MinecraftServer.class:?]
at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:118) [integratedServer.class:?]
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:495) [MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer$2.run(MinecraftServer.java:762) [MinecraftServer$2.class:?]
Caused by: java.lang.IndexOutOfBoundsException: readerIndex(11) + length(1) exceeds writerIndex(11): SlicedByteBuf(ridx: 11, widx: 11, cap: 11/11, unwrapped: UnpooledHeapByteBuf(ridx: 1, widx: 12, cap: 12/12))
at io.netty.buffer.AbstractByteBuf.checkReadableBytes(AbstractByteBuf.java:1160) ~[AbstractByteBuf.class:?]
at io.netty.buffer.AbstractByteBuf.readByte(AbstractByteBuf.java:562) ~[AbstractByteBuf.class:?]
at cpw.mods.fml.common.network.ByteBufUtils.readVarInt(ByteBufUtils.java:46) ~[byteBufUtils.class:?]
at cpw.mods.fml.common.network.ByteBufUtils.readUTF8String(ByteBufUtils.java:118) ~[byteBufUtils.class:?]
at com.zpig333.runesofwizardry.gui.DustDyeUpdatePacket.fromBytes(DustDyeUpdatePacket.java:27) ~[DustDyeUpdatePacket.class:?]
at cpw.mods.fml.common.network.simpleimpl.SimpleIndexedCodec.decodeInto(SimpleIndexedCodec.java:17) ~[simpleIndexedCodec.class:?]
at cpw.mods.fml.common.network.simpleimpl.SimpleIndexedCodec.decodeInto(SimpleIndexedCodec.java:7) ~[simpleIndexedCodec.class:?]
at cpw.mods.fml.common.network.FMLIndexedMessageToMessageCodec.decode(FMLIndexedMessageToMessageCodec.java:77) ~[FMLIndexedMessageToMessageCodec.class:?]
at cpw.mods.fml.common.network.FMLIndexedMessageToMessageCodec.decode(FMLIndexedMessageToMessageCodec.java:17) ~[FMLIndexedMessageToMessageCodec.class:?]
at io.netty.handler.codec.MessageToMessageCodec$2.decode(MessageToMessageCodec.java:81) ~[MessageToMessageCodec$2.class:?]
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:89) ~[MessageToMessageDecoder.class:?]
... 13 more
[15:56:55] [server thread/ERROR] [FML]: SimpleChannelHandlerWrapper exception
io.netty.handler.codec.DecoderException: java.lang.IndexOutOfBoundsException: readerIndex(11) + length(1) exceeds writerIndex(11): SlicedByteBuf(ridx: 11, widx: 11, cap: 11/11, unwrapped: UnpooledHeapByteBuf(ridx: 1, widx: 12, cap: 12/12))
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:99) ~[MessageToMessageDecoder.class:?]
at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111) ~[MessageToMessageCodec.class:?]
at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:337) [DefaultChannelHandlerContext.class:?]
at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:323) [DefaultChannelHandlerContext.class:?]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:785) [DefaultChannelPipeline.class:?]
at io.netty.channel.embedded.EmbeddedChannel.writeInbound(EmbeddedChannel.java:169) [EmbeddedChannel.class:?]
at cpw.mods.fml.common.network.internal.FMLProxyPacket.processPacket(FMLProxyPacket.java:86) [FMLProxyPacket.class:?]
at net.minecraft.network.NetworkManager.processReceivedPackets(NetworkManager.java:247) [NetworkManager.class:?]
at net.minecraft.network.NetworkSystem.networkTick(NetworkSystem.java:182) [NetworkSystem.class:?]
at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:736) [MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:624) [MinecraftServer.class:?]
at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:118) [integratedServer.class:?]
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:495) [MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer$2.run(MinecraftServer.java:762) [MinecraftServer$2.class:?]
Caused by: java.lang.IndexOutOfBoundsException: readerIndex(11) + length(1) exceeds writerIndex(11): SlicedByteBuf(ridx: 11, widx: 11, cap: 11/11, unwrapped: UnpooledHeapByteBuf(ridx: 1, widx: 12, cap: 12/12))
at io.netty.buffer.AbstractByteBuf.checkReadableBytes(AbstractByteBuf.java:1160) ~[AbstractByteBuf.class:?]
at io.netty.buffer.AbstractByteBuf.readByte(AbstractByteBuf.java:562) ~[AbstractByteBuf.class:?]
at cpw.mods.fml.common.network.ByteBufUtils.readVarInt(ByteBufUtils.java:46) ~[byteBufUtils.class:?]
at cpw.mods.fml.common.network.ByteBufUtils.readUTF8String(ByteBufUtils.java:118) ~[byteBufUtils.class:?]
at com.zpig333.runesofwizardry.gui.DustDyeUpdatePacket.fromBytes(DustDyeUpdatePacket.java:27) ~[DustDyeUpdatePacket.class:?]
at cpw.mods.fml.common.network.simpleimpl.SimpleIndexedCodec.decodeInto(SimpleIndexedCodec.java:17) ~[simpleIndexedCodec.class:?]
at cpw.mods.fml.common.network.simpleimpl.SimpleIndexedCodec.decodeInto(SimpleIndexedCodec.java:7) ~[simpleIndexedCodec.class:?]
at cpw.mods.fml.common.network.FMLIndexedMessageToMessageCodec.decode(FMLIndexedMessageToMessageCodec.java:77) ~[FMLIndexedMessageToMessageCodec.class:?]
at cpw.mods.fml.common.network.FMLIndexedMessageToMessageCodec.decode(FMLIndexedMessageToMessageCodec.java:17) ~[FMLIndexedMessageToMessageCodec.class:?]
at io.netty.handler.codec.MessageToMessageCodec$2.decode(MessageToMessageCodec.java:81) ~[MessageToMessageCodec$2.class:?]
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:89) ~[MessageToMessageDecoder.class:?]
... 13 more
[15:56:55] [server thread/ERROR] [FML]: There was a critical exception handling a packet on channel RunesWiz
io.netty.handler.codec.DecoderException: java.lang.IndexOutOfBoundsException: readerIndex(11) + length(1) exceeds writerIndex(11): SlicedByteBuf(ridx: 11, widx: 11, cap: 11/11, unwrapped: UnpooledHeapByteBuf(ridx: 1, widx: 12, cap: 12/12))
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:99) ~[MessageToMessageDecoder.class:?]
at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111) ~[MessageToMessageCodec.class:?]
at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:337) ~[DefaultChannelHandlerContext.class:?]
at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:323) ~[DefaultChannelHandlerContext.class:?]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:785) ~[DefaultChannelPipeline.class:?]
at io.netty.channel.embedded.EmbeddedChannel.writeInbound(EmbeddedChannel.java:169) ~[EmbeddedChannel.class:?]
at cpw.mods.fml.common.network.internal.FMLProxyPacket.processPacket(FMLProxyPacket.java:86) [FMLProxyPacket.class:?]
at net.minecraft.network.NetworkManager.processReceivedPackets(NetworkManager.java:247) [NetworkManager.class:?]
at net.minecraft.network.NetworkSystem.networkTick(NetworkSystem.java:182) [NetworkSystem.class:?]
at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:736) [MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:624) [MinecraftServer.class:?]
at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:118) [integratedServer.class:?]
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:495) [MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer$2.run(MinecraftServer.java:762) [MinecraftServer$2.class:?]
Caused by: java.lang.IndexOutOfBoundsException: readerIndex(11) + length(1) exceeds writerIndex(11): SlicedByteBuf(ridx: 11, widx: 11, cap: 11/11, unwrapped: UnpooledHeapByteBuf(ridx: 1, widx: 12, cap: 12/12))
at io.netty.buffer.AbstractByteBuf.checkReadableBytes(AbstractByteBuf.java:1160) ~[AbstractByteBuf.class:?]
at io.netty.buffer.AbstractByteBuf.readByte(AbstractByteBuf.java:562) ~[AbstractByteBuf.class:?]
at cpw.mods.fml.common.network.ByteBufUtils.readVarInt(ByteBufUtils.java:46) ~[byteBufUtils.class:?]
at cpw.mods.fml.common.network.ByteBufUtils.readUTF8String(ByteBufUtils.java:118) ~[byteBufUtils.class:?]
at com.zpig333.runesofwizardry.gui.DustDyeUpdatePacket.fromBytes(DustDyeUpdatePacket.java:27) ~[DustDyeUpdatePacket.class:?]
at cpw.mods.fml.common.network.simpleimpl.SimpleIndexedCodec.decodeInto(SimpleIndexedCodec.java:17) ~[simpleIndexedCodec.class:?]
at cpw.mods.fml.common.network.simpleimpl.SimpleIndexedCodec.decodeInto(SimpleIndexedCodec.java:7) ~[simpleIndexedCodec.class:?]
at cpw.mods.fml.common.network.FMLIndexedMessageToMessageCodec.decode(FMLIndexedMessageToMessageCodec.java:77) ~[FMLIndexedMessageToMessageCodec.class:?]
at cpw.mods.fml.common.network.FMLIndexedMessageToMessageCodec.decode(FMLIndexedMessageToMessageCodec.java:17) ~[FMLIndexedMessageToMessageCodec.class:?]
at io.netty.handler.codec.MessageToMessageCodec$2.decode(MessageToMessageCodec.java:81) ~[MessageToMessageCodec$2.class:?]
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:89) ~[MessageToMessageDecoder.class:?]
... 13 more
[15:56:55] [server thread/INFO]: Player180 lost connection: TextComponent{text='A fatal error has occured, this connection is terminated', siblings=[], style=Style{hasParent=false, color=null, bold=null, italic=null, underlined=null, obfuscated=null, clickEvent=null, hoverEvent=null}}
[15:56:55] [server thread/INFO]: Player180 left the game

 

I can't find where this comes from :(

 

code (GitHub because IMO it's easier than copy-pasting 5 files and miss those you need to see)

Posted

I can tell you from that error that you haven't numbered your packets correctly - they each need an individual number - or you haven't referenced that number correctly.

I'll need help, and I'll give help. Just ask, you know I will!

Posted

yep, that was it. However, for the packet that updates the GUI/TileEntity, should I register it on Side.SERVER or Side.CLIENT? if it is on Client, how do I access the TileEntity? the client handler (MessageContext.getClientHandler()) does not have access to the player/world to obtain the TE (and, of course, getServerHandler crashes since it's client-side)

Posted

Yes, that can be tricky! I added a field to store my TE in my container, which I assigned in construction. Then, I was able to access the TE through the container in the client packet handler like such:

 

GuiScreen screen = Minecraft.getMinecraft().currentScreen;
        	
        	if (screen instanceof GuiShopper) {
			ContainerShopper container = ((GuiShopper) screen).container;

			container.tileEntity.Cost = message.cost;
			container.tileEntity.markDirty();
		}

 

Your usage will look different, but you get the idea. You are right, you cant access the player simply!

I'll need help, and I'll give help. Just ask, you know I will!

Posted

You should be able to get it now. Maybe the flow would be like:

 

  • Client presses button(handled in the gui)
  • Gui sends a packet "pressedUpButton" to server
  • Server makes changes to item nbt according to "up button" packet
  • Server responds with a "ichangedthenbt" packet
  • Client changes the local nbt or refreshes from server, etc. to you can see the changes in the gui
  • Eat a cookie

I'll need help, and I'll give help. Just ask, you know I will!

Posted

that is indeed what I did, and it works (also, the reply from the server does not seem necessary either).

 

however, I noticed that if I break the tileEntity and place a new one in the same spot, the new one takes the properties of the old one, and if there was an ItemStack in it (dropped when the TE is broken), it is still there, although with only 1 item. Reloading the world between the breaking and placing of the TE fixes it.

 

do I need to do something specific to reset the TileEntity when it is broken?

Posted

here you go.

 

also, I didn't notice before, but the block seems to be instantly broken (and does not drop) with the empty hand in survival mode, even though the harvest level has been set.

 

package com.zpig333.runesofwizardry.block;

import com.zpig333.runesofwizardry.RunesOfWizardry;
import com.zpig333.runesofwizardry.core.ModLogger;
import com.zpig333.runesofwizardry.gui.GuiDustDye;
import com.zpig333.runesofwizardry.tileentity.TileEntityDustDye;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;

public class BlockDustDye extends BlockContainer {

    private Random random = new Random();

    public BlockDustDye(Material mat) {
        super(mat);
        setCreativeTab(RunesOfWizardry.wizardry_tab);
        setHarvestLevel("pickaxe", 0);
    }

    @Override
    public TileEntity createNewTileEntity(World p_149915_1_, int p_149915_2_) {
        return new TileEntityDustDye();
    }

    //drops the items when the block is broken (?)
    @Override
    public void breakBlock(World p_149749_1_, int p_149749_2_, int p_149749_3_, int p_149749_4_, Block p_149749_5_, int p_149749_6_) {
        TileEntityDustDye tileentityDustDye = (TileEntityDustDye) p_149749_1_.getTileEntity(p_149749_2_, p_149749_3_, p_149749_4_);

        if (tileentityDustDye != null) {
            for (int i1 = 0; i1 < tileentityDustDye.getSizeInventory(); ++i1) {
                ItemStack itemstack = tileentityDustDye.getStackInSlot(i1);

                if (itemstack != null) {
                    float f = this.random.nextFloat() * 0.8F + 0.1F;
                    float f1 = this.random.nextFloat() * 0.8F + 0.1F;
                    EntityItem entityitem;

                    for (float f2 = this.random.nextFloat() * 0.8F + 0.1F; itemstack.stackSize > 0; p_149749_1_.spawnEntityInWorld(entityitem)) {
                        int j1 = this.random.nextInt(21) + 10;

                        if (j1 > itemstack.stackSize) {
                            j1 = itemstack.stackSize;
                        }

                        itemstack.stackSize -= j1;
                        entityitem = new EntityItem(p_149749_1_, (double) ((float) p_149749_2_ + f), (double) ((float) p_149749_3_ + f1), (double) ((float) p_149749_4_ + f2), new ItemStack(itemstack.getItem(), j1, itemstack.getItemDamage()));
                        float f3 = 0.05F;
                        entityitem.motionX = (double) ((float) this.random.nextGaussian() * f3);
                        entityitem.motionY = (double) ((float) this.random.nextGaussian() * f3 + 0.2F);
                        entityitem.motionZ = (double) ((float) this.random.nextGaussian() * f3);

                        if (itemstack.hasTagCompound()) {
                            entityitem.getEntityItem().setTagCompound((NBTTagCompound) itemstack.getTagCompound().copy());
                        }
                    }
                }
            }

            p_149749_1_.func_147453_f(p_149749_2_, p_149749_3_, p_149749_4_, p_149749_5_);
        }

    }
    
    @Override
    public boolean onBlockActivated(World world, int x, int y, int z,
                        EntityPlayer player, int metadata, float what, float these, float are){
       /* if (world.isRemote)
        {
            return true;
        }
        else
        { */
            TileEntityDustDye tileentityDD = (TileEntityDustDye)world.getTileEntity(x,y,z);
            
            if (tileentityDD == null || player.isSneaking()) {
                        return false;
            }
            player.openGui(RunesOfWizardry.instance, GuiDustDye.GUI_ID, world, x, y, z);            
            return true;
        }
    }

Posted

adding tileentityDustDye.invalidate(); at the end of the the breakBlock method seems to fix the issue where the issue of the container staying the same after breaking it, although I am unsure of what this method does.

Posted

SOLVED.

 

it seems the proper way of fixing the "ghost" tileEntity was to call super.breakBlock()

 

also, harvesting problem was solved by using setHardness() and making canHarvest() always return true.

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.