Jump to content

Removing item from tileentity


tiffit

Recommended Posts

So I have my own tile entity with a GUI. Everything works fine, except for 1 thing. Whenever I have the plugin remove an item from a slot, on the client it looks fine. When you click on the itemstack, or exit out of the inventory, the item stacks returns to how it was before. So lets say I put in 10 diamond into the GUI. I let it use up 5 diamond. There is 5 diamond left in the GUI. When I close the GUI and open it up again, there is 10 diamonds in the GUI. I don't know if this is a miscommunication between the server and the client, or what. Below is my tile entity class. It is probably something really obvious, but I spent a while and couldn't find anything

 

public class TileEntityControlledStriker extends TileEntity implements IInventory, IUpdatePlayerListBox{

public int storedMagic = 0;
public boolean isStriking;
public int timeUntilNextStrike = 100;
    public ItemStack[] stacks = new ItemStack[3];
    protected String customName;






    public int getSizeInventory(){
        return 3;
    }

    /**
     * Returns the stack in slot i
     */
    public ItemStack getStackInSlot(int index)
    {
        return this.stacks[index];
    }

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

            if (this.stacks[index].stackSize <= count)
            {
                itemstack = this.stacks[index];
                this.stacks[index] = null;
                this.markDirty();
                return itemstack;
            }
            else
            {
                itemstack = this.stacks[index].splitStack(count);

                if (this.stacks[index].stackSize == 0)
                {
                    this.stacks[index] = null;
                }

                this.markDirty();
                return itemstack;
            }
        }
        else
        {
            return null;
        }
    }

    /**
     * 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 index){
        return null;
    }

    /**
     * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections).
     */
    public void setInventorySlotContents(int index, ItemStack stack){
        this.stacks[index] = stack;

        if (stack != null && stack.stackSize > this.getInventoryStackLimit()){
            stack.stackSize = this.getInventoryStackLimit();
        }

        this.markDirty();
    }

    /**
     * Gets the name of this command sender (usually username, but possibly "Rcon")
     */
    public String getName()
    {
        return this.hasCustomName() ? this.customName : "container.dispenser";
    }

    public void setCustomName(String customName)
    {
        this.customName = customName;
    }

    /**
     * Returns true if this thing is named
     */
    public boolean hasCustomName()
    {
        return this.customName != null;
      

}

    public int getInventoryStackLimit()
    {
        return 64;
    }

    /**
     * Do not make give this method the name canInteractWith because it clashes with Container
     */
    public boolean isUseableByPlayer(EntityPlayer player)
    {
        return this.worldObj.getTileEntity(this.pos) != this ? false : player.getDistanceSq((double)this.pos.getX() + 0.5D, (double)this.pos.getY() + 0.5D, (double)this.pos.getZ() + 0.5D) <= 64.0D;
    }

    public void openInventory(EntityPlayer player) {}

    public void closeInventory(EntityPlayer player) {}

    /**
     * Returns true if automation is allowed to insert the given stack (ignoring stack size) into the given slot.
     */
    public boolean isItemValidForSlot(int index, ItemStack stack)
    {
        return false;
    }

    public Container createContainer(InventoryPlayer playerInventory, EntityPlayer playerIn)
    {
        return new ContainerDispenser(playerInventory, this);
    }

    public int getField(int id)
    {
        return 0;
    }

    public void setField(int id, int value) {}

    public int getFieldCount()
    {
        return 0;
    }

    public void clear()
    {
        for (int i = 0; i < this.stacks.length; ++i)
        {
            this.stacks[i] = null;
        }
    }

@Override
public IChatComponent getDisplayName() {
	return null;
}

@Override
 public void readFromNBT(NBTTagCompound compound){
        super.readFromNBT(compound);
        stacks = new ItemStack[3];
        NBTTagList invStacksTag = compound.getTagList("stacks", 10);
        for(int i = 0; i < invStacksTag.tagCount(); i++){
        	NBTTagCompound t = invStacksTag.getCompoundTagAt(i);
        	int index = t.getByte("index");
        	if(index >= 0 && index < stacks.length){
        		stacks[index] = ItemStack.loadItemStackFromNBT(t);
        	}
        }
        this.storedMagic = compound.getInteger("storedMagic");
        
        
 }

	@Override
    public void writeToNBT(NBTTagCompound compound){
    	super.writeToNBT(compound);
        NBTTagList invStacksTag = new NBTTagList();
        for(int i = 0; i < stacks.length; i++){
        	ItemStack stack = stacks[i];
        	if(stack != null){
	        	NBTTagCompound t = new NBTTagCompound();
	        	stack.writeToNBT(t);
	        	t.setByte("index", (byte)i);
	        	invStacksTag.appendTag(t);
        	}
        }
        compound.setTag("stacks", invStacksTag);
        compound.setInteger("storedMagic", this.storedMagic);
        
        
    }

	public void strike(){
        EntityLightningBolt lightning = new EntityLightningBolt(this.worldObj, pos.getX(), pos.getY(), pos.getZ());
        this.worldObj.spawnEntityInWorld(lightning);
        if(this.storedMagic != 1000){
        this.storedMagic += 10;
        }
        
        this.stacks[0].stackSize--;
        this.stacks[1].stackSize--;
        
        Random r = new Random();
        int dropChance = r.nextInt(10);
        if(dropChance == 4){
	       //TODO this.stacks[2].stackSize++;
        }
        this.markDirty();
	}

	@Override
	public void update() {
		if(this.isStriking){
		this.timeUntilNextStrike--;
        	if(this.timeUntilNextStrike <= 0){
        		this.timeUntilNextStrike = 100;
			this.strike();
        	}
        	}
	}

 

 

Link to comment
Share on other sites

Container, Gui? If you are using those - GuiHandler would be also nice.

 

You need to actually setup some packeting (synchro). You use markDirty(), but where is synchro code?

1.7.10 is no longer supported by forge, you are on your own.

Link to comment
Share on other sites

Container, Gui? If you are using those - GuiHandler would be also nice.

 

You need to actually setup some packeting (synchro). You use markDirty(), but where is synchro code?

 

I am using a GuiHandler.

Also, I am pretty new to packets, could you show me how to do this?

Link to comment
Share on other sites

You shouldn't need any packets for this. Please show your Container and Gui.

 

Ok here it is

 

Container:

 

 

public ContainerControlledStriker(InventoryPlayer pl, TileEntityControlledStriker tileEntity){
	this.addSlotToContainer(new Slot(tileEntity, 0,  56, 17){
            public boolean isItemValid(ItemStack stack){
                return stack.getItem() == Main.magicalCopperIngot;
            }
        });
	this.addSlotToContainer(new Slot(tileEntity, 1,  56, 53){
            public boolean isItemValid(ItemStack stack){
            	Item i = stack.getItem();
                return i == Items.diamond || i == Items.iron_ingot || i == Items.gold_ingot || i == Main.copperIngot;
            }
        });
        this.addSlotToContainer(new Slot(tileEntity, 2, 99, 53){
            public boolean isItemValid(ItemStack stack){
                return false;
            }
        });
	this.addPlayerSlots(pl, 8, 84);
	this.te = tileEntity;
}

@Override
public boolean canInteractWith(EntityPlayer playerIn) {
	return te.isUseableByPlayer(playerIn);
}

protected void addPlayerSlots(InventoryPlayer pi, int x, int y){
        for (int i = 0; i < 3; ++i){
            for (int j = 0; j < 9; ++j){
                this.addSlotToContainer(new Slot(pi, j + i * 9 + 9, x + j * 18, y + i * 18));
            }
        }

        for (int i = 0; i < 9; ++i){
            this.addSlotToContainer(new Slot(pi, i, x + i * 18, y + 58));
        }
}

@Override
public ItemStack transferStackInSlot(EntityPlayer pl, int i){
	return null;

}

 

 

Gui:

 

public class GuiControlledStriker extends GuiContainer{

private static final ResourceLocation GuiTexture = new ResourceLocation(Main.MODID + ":textures/gui/ControlledStriker.png");

TileEntityControlledStriker te;

public GuiControlledStriker(InventoryPlayer pi, TileEntityControlledStriker te) {
	super(new ContainerControlledStriker(pi, te));
	this.te = te;
}

@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) {
	mc.getTextureManager().bindTexture(GuiTexture);
	this.drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize);
	double size = (te.storedMagic/1000.0) * 52;
        int k = (this.width - this.xSize) / 2 + 126;
        int l = (this.height - this.ySize) / 2 + 69;
	for(int i = 0; i <= (int) size; i++){
		this.drawTexturedModalRect(k, l - i, 176, 52 - i, 20, 1);
        }


}

@Override
    protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY){
        this.fontRendererObj.drawString("Controlled Striker", 8, 6, 4210752);
        this.fontRendererObj.drawString("Inventory", 8, this.ySize - 96 + 2, 4210752);
        int timeSeconds = te.timeUntilNextStrike;
        if(te.isStriking){
        	this.fontRendererObj.drawString(timeSeconds + "", 8, this.ySize - 120, 4210752);
        	
        	}
        int k = (this.width - this.xSize) / 2 + 126;
        int l = (this.height - this.ySize) / 2 + 69;
        if(mouseX > k - 1 && mouseY > l - 52 && mouseX < k + 20 && mouseY < l){
            this.fontRendererObj.drawString(te.storedMagic + "/1000", this.xSize/2 + 30, 6, 4210752);
        }
        
        this.buttonList.clear();
        int posX = (this.width - this.xSize) / 2 + 126;
        int posY = (this.height - this.ySize) / 2 + 35;
        String isStriking = "Off";
        if(te.isStriking) isStriking = "On";
        
        this.buttonList.add(new GuiButton(0, posX - 40, posY - 15, 30, 20, isStriking));
    }

@Override
public void actionPerformed(GuiButton button){
	if(button.id == 0){
		if(!te.isStriking && te.stacks[1] != null && te.stacks[0] != null){
		te.isStriking = true;
		}else{
			te.timeUntilNextStrike = 100;
			te.isStriking = false;
		}
	}
}

}

 

 

GuiHandler:

 

public class GuiHandler implements IGuiHandler{

public enum GuiIDs{
	ControlledStriker;
}

@Override
public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
	switch(GuiIDs.values()[iD]){
		case ControlledStriker:
			return new ContainerControlledStriker(player.inventory, (TileEntityControlledStriker)world.getTileEntity(new BlockPos(x, y, z)));
	}
	throw new IllegalArgumentException("No gui with id " + ID);
}

@Override
public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
	switch(GuiIDs.values()[iD]){
	case ControlledStriker:
		return new GuiControlledStriker(player.inventory, (TileEntityControlledStriker)world.getTileEntity(new BlockPos(x, y, z)));
	}
	 throw new IllegalArgumentException("No gui with id " + ID);
}

}

 

Link to comment
Share on other sites

You are setting the "isStriking" field from your GUI directly, meaning it will be set in the client version of the TileEntity. You cannot do stuff like spawn entities or modify inventories (such as your TileEntity) on the client. In your GUI you need to instead send a packet to the server to set the field there.

I am confused, can you go into more detail please? What exactly do I need to do?

 

Link to comment
Share on other sites

Instead of setting isStriking to true in your GUI class (on the Client), you need to send a packet to the server, and then in your packet handler, you set isStriking to true (on the Server).

 

Sorry for these "stupid" questions, I am still getting used to packeting. So would I use description packets?

Link to comment
Share on other sites

Well, you need to send the data you need and then do stuff in the packet handler. But yes, it is that simple. Packets are very easy actually.

 

Sorry for the (probably) stupid questions, but can you define "stuff"

Link to comment
Share on other sites

Ok. I get everything setup, but it keeps giving me an NPE on the onMessage part of it.

 

Here is my Message class:

package tiffit.tiffitsmachines.packets;

import io.netty.buffer.ByteBuf;
import net.minecraft.util.BlockPos;
import net.minecraft.world.World;
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 tiffit.tiffitsmachines.tileEntity.TileEntityControlledStriker;

public class ControlledStrikerPackets implements IMessage {

public int x;
public int y;
public int z;
public World w;

    public ControlledStrikerPackets() {}

    public ControlledStrikerPackets(int x, int y, int z, World w) {
        this.x = x;
        this.y = y;
        this.z = z;
        this.w = w;
    }

    @Override
    public void fromBytes(ByteBuf buf) {
    	
    }

    @Override
    public void toBytes(ByteBuf buf) {
    }

    public static class Handler implements IMessageHandler<ControlledStrikerPackets, IMessage> {
        
        @Override
        public IMessage onMessage(ControlledStrikerPackets message, MessageContext ctx){
        	System.out.print(message != null);
        	TileEntityControlledStriker te = (TileEntityControlledStriker) message.w.getTileEntity(new BlockPos(message.x, message.y, message.z));
        
    			if(!te.isStriking && te.stacks[1] != null && te.stacks[0] != null){
    				te.isStriking = true;
    				}else{
    					te.timeUntilNextStrike = 100;
    					te.isStriking = false;
    			}
        	return null;
        }
    }
}

 

Apparently, the "message" object (ControlledStrikerPackets) that it gives me is empty.

 

By empty, I mean all of its fields are null, even though I set them when I send a packet.

 

This is how I send my packet:

Main.network.sendToServer(new ControlledStrikerPackets(te.getPos().getX(), te.getPos().getY(), te.getPos().getZ(), te.getWorld()));

 

 

 

EDIT:

Nevermind, completely forgot about the byte bufs, I got it working now :)

Link to comment
Share on other sites

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.



×
×
  • Create New...

Important Information

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