Jump to content

[solved] Grab and sync TileEntity via SimpleNetworkWrapper


strumshot

Recommended Posts

So I'm working with a custom block/gui and have some buttons on the gui that are changing a value stored in a TileEntity. Unless I am mistaken the button actions and therefore the value changes corresponding to pressing them occur on client side only. I have, then, set up a packet to be sent to the server so this value can be updated globally and other players "see" the updated values. I am using the SimpleNetworkWrapper so I am simply sending a string. I imagine I will be sending a constructed string containing an id for the TileEntity and the updated value, and then grabbing that TileEntity by that id on the server/packet receive? Should I be using hashCode? And what list/map am I looking it up in? Or should I be approaching this some other way... thanks for any pointers! (I mean tips, not programmatic 'pointers' lol - bad programming joke)

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

Link to comment
Share on other sites

Yeah, it sure does. I'd be happy to share code, but I have no errors so to speak..

 

Its a block, TileEntity, Container, and gui. The setup displays the player inventory, the 12-slot 'inventory' of the container, the 'value' in question (currently held by the TileEntity) and buttons to change the value. I have a blank string packet sent to server upon button click.

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

Link to comment
Share on other sites

..so at the end of the day I know the button clicks happen privately on the client, but I need them to adjust the value on the server so any other player would see the updated value when opening the gui. Maybe I misunderstand what automatically gets synced to the server, and maybe I am storing the value in the wrong spot (I have options. Container, gui, TileEntity...) but I can't find a solution and its a hard topic to google!

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

Link to comment
Share on other sites

Thanks for the quick responses! I should clarify that when I say 'button' I mean a clickable gui control. And then my follow-up question is such: my packet handling method currently has no objects to access aside from the packet class and the message text. That is why I imagined I would be sending an ID of sorts in the string, and then looking that ID up in a static server list. Does that make sense?

 

Something like...

       protected void actionPerformed(GuiButton button) {

	        	++chest.Cost;
            IShop.network.sendToServer(new ChangeCost(chest.hashCode() + ":" + chest.Cost));
            break;

 

public static class Handler implements IMessageHandler<ChangeCost, IMessage> {
        
        @Override
        public IMessage onMessage(ChangeCost message, MessageContext ctx) {
        	
        	String[] incoming = message.text.split(":");
            
            if(incoming != null && incoming.length == 2){
            	int hash = Integer.parseInt(incoming[0]);
            	int cost = Integer.parseInt(incoming[1]);

       // lookup chest # here and adjust value of 'cost'

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

Link to comment
Share on other sites

this is extra nice because I can shorten the message to one character - no numbers - and do all the logic on the server side! whenever I find my code getting long and myself inventing solutions there is usually a simpler already available approach.and it usually gets pointed out to me by you. Haha at this point you have virtually written half of my mods and I'm sure I'm not the only one on this forum with that experience. :D

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

Link to comment
Share on other sites

right that is basically my point. I guess I could make 2 separate packet classes as there are two different buttons. I was using one packet for both buttons; the character would be either a plus or a minus - or whatever. An increment button and a decrement button. i 100% see your point although in this scenario cheating isn't really possible but I will still take that advice!

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

Link to comment
Share on other sites

Okay.. Setting up the custom packets and sending safe information to the server upon button click, I'm good. But that's as far as I can get! Ugh.

 

I have a few issues. Ultimately I'm not sure how to send that update back to the client (and others who may open this container.) I've played with many methods and approaches, such as simply reversing the process; but there seems to be no direct access to the player through the client side of the handler to grab the open container from. Also, upon closing the container, the value seems to reset on the server side - I am logging the server-side value every time the server receives the packet. I'm writing the value to NBT in the generic writeToNBT method, which doesn't seem to affect it.

 

Again, I'm sure there's some simple mechanism already in place for updating custom values in a TileEntity and then propogating that update back to nearby clients; maybe through a custom packet and sendToAllAround()? Any tutorials I've found near this topic are deprecated which is frustrating!

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

Link to comment
Share on other sites

Update: of course, the moment I posted I solved the issue of getting the info back to the client... at least I think.

 

 

player.worldObj.markBlockForUpdate(container.tileEntity.xCoord, container.tileEntity.yCoord, container.tileEntity.zCoord);
        	
        	return new SendCost(container.tileEntity.Cost); 

 

 

public static class Handler implements IMessageHandler<SendCost, IMessage> {
        
        @Override
        public IMessage onMessage(SendCost message, MessageContext ctx) {
        	
        	
        	EntityPlayer player = Minecraft.getMinecraft().thePlayer;
        	ContainerShop container = (ContainerShop)player.openContainer;     
        	
        	container.tileEntity.Cost = message.value;

 

But the value is still resetting upon close.

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

Link to comment
Share on other sites

TileEntity

 

package com.kotr.ishop.tile_entity;

import java.util.Iterator;
import java.util.List;

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;
import net.minecraft.util.AxisAlignedBB;

import com.kotr.ishop.block.ShopChest;
import com.kotr.ishop.container.ContainerShop;

public class TileEntityShopChest extends TileEntity implements IInventory{

private ItemStack[] chestContents = new ItemStack[39];

    private String customName;
    public int numPlayersUsing;
public float prevLidAngle;
public float lidAngle;
private int ticksSinceSync;
private Object adjacentChestZNeg;
private Object adjacentChestXNeg;
private Object adjacentChestZPos;
private Object adjacentChestXPos;

public int Cost;

   
    /**
     * Returns the name of the inventory
     */
    public String getInventoryName()
    {
        return this.hasCustomInventoryName() ? this.customName : "Shop Inventory";
    }
    
    /**
     * Returns the stack in slot i
     */
    public ItemStack getStackInSlot(int p_70301_1_)
    {
        return this.chestContents[p_70301_1_];
    }

    /**
     * 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 p_70298_1_, int p_70298_2_)
    {
        if (this.chestContents[p_70298_1_] != null)
        {
            ItemStack itemstack;

            if (this.chestContents[p_70298_1_].stackSize <= p_70298_2_)
            {
                itemstack = this.chestContents[p_70298_1_];
                this.chestContents[p_70298_1_] = null;
                this.markDirty();
                return itemstack;
            }
            else
            {
                itemstack = this.chestContents[p_70298_1_].splitStack(p_70298_2_);

                if (this.chestContents[p_70298_1_].stackSize == 0)
                {
                    this.chestContents[p_70298_1_] = 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 p_70304_1_)
    {
        if (this.chestContents[p_70304_1_] != null)
        {
            ItemStack itemstack = this.chestContents[p_70304_1_];
            this.chestContents[p_70304_1_] = null;
            return itemstack;
        }
        else
        {
            return null;
        }
    }
    
    /**
     * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections).
     */
    public void setInventorySlotContents(int p_70299_1_, ItemStack p_70299_2_)
    {
        this.chestContents[p_70299_1_] = p_70299_2_;

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

        this.markDirty();
    }
    
    public void readFromNBT(NBTTagCompound p_145839_1_)
    {
        super.readFromNBT(p_145839_1_);
        NBTTagList nbttaglist = p_145839_1_.getTagList("Items", 10);
        this.chestContents = new ItemStack[this.getSizeInventory()];

        if (p_145839_1_.hasKey("Shop Chest", )
        {
            this.customName = p_145839_1_.getString("Shop Chest");
        }
        
        this.Cost = p_145839_1_.getByte("Cost");

        for (int i = 0; i < nbttaglist.tagCount(); ++i)
        {
            NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i);
            int j = nbttagcompound1.getByte("Slot") & 255;

            if (j >= 0 && j < this.chestContents.length)
            {
                this.chestContents[j] = ItemStack.loadItemStackFromNBT(nbttagcompound1);
            }
        }
    }

    public void writeToNBT(NBTTagCompound p_145841_1_)
    {
        super.writeToNBT(p_145841_1_);
        NBTTagList nbttaglist = new NBTTagList();

        
        for (int i = 0; i < this.chestContents.length; ++i)
        {
            if (this.chestContents[i] != null)
            {
                NBTTagCompound nbttagcompound1 = new NBTTagCompound();
                nbttagcompound1.setByte("Slot", (byte)i);
                this.chestContents[i].writeToNBT(nbttagcompound1);
                nbttaglist.appendTag(nbttagcompound1);
            }
        }

        p_145841_1_.setTag("Items", nbttaglist);

        p_145841_1_.setByte("Cost", (byte)this.Cost);
        
        if (this.hasCustomInventoryName())
        {
            p_145841_1_.setString("Shop Chest", this.customName);
        }
    }
    
    
    

//    private boolean func_145977_a(int p_145977_1_, int p_145977_2_, int p_145977_3_)
//    {
//        if (this.worldObj == null)
//        {
//            return false;
//        }
//        else
//        {
//            Block block = this.worldObj.getBlock(p_145977_1_, p_145977_2_, p_145977_3_);
//            return block instanceof ShopChest && ((ShopChest)block).field_149956_a == this.func_145980_j();
//        }
//    }
    
    public void func_145976_a(String p_145976_1_)
    {
        this.customName = p_145976_1_;
    }
    
    public void openInventory()
    {
        if (this.numPlayersUsing < 0)
        {
            this.numPlayersUsing = 0;
        }

        ++this.numPlayersUsing;
        this.worldObj.addBlockEvent(this.xCoord, this.yCoord, this.zCoord, this.getBlockType(), 1, this.numPlayersUsing);
        this.worldObj.notifyBlocksOfNeighborChange(this.xCoord, this.yCoord, this.zCoord, this.getBlockType());
        this.worldObj.notifyBlocksOfNeighborChange(this.xCoord, this.yCoord - 1, this.zCoord, this.getBlockType());
    }
    
    public void closeInventory()
    {
        if (this.getBlockType() instanceof ShopChest)
        {
            --this.numPlayersUsing;
            this.worldObj.addBlockEvent(this.xCoord, this.yCoord, this.zCoord, this.getBlockType(), 1, this.numPlayersUsing);
            this.worldObj.notifyBlocksOfNeighborChange(this.xCoord, this.yCoord, this.zCoord, this.getBlockType());
            this.worldObj.notifyBlocksOfNeighborChange(this.xCoord, this.yCoord - 1, this.zCoord, this.getBlockType());
        }
    }

@Override
public int getSizeInventory() {
	// TODO Auto-generated method stub
	return this.chestContents.length;
}

@Override
public boolean hasCustomInventoryName() {
	// TODO Auto-generated method stub
	return false;
}

@Override
public int getInventoryStackLimit() {
	// TODO Auto-generated method stub
	return 64;
}

@Override
public boolean isUseableByPlayer(EntityPlayer p_70300_1_) {
        return this.worldObj.getTileEntity(this.xCoord, this.yCoord, this.zCoord) != this ? false : p_70300_1_.getDistanceSq((double)this.xCoord + 0.5D, (double)this.yCoord + 0.5D, (double)this.zCoord + 0.5D) <= 64.0D;
}

@Override
public boolean isItemValidForSlot(int p_94041_1_, ItemStack p_94041_2_) {
	// TODO Auto-generated method stub
	return true;
}    

public void updateEntity()
    {
        super.updateEntity();
         ++this.ticksSinceSync;
        float f;

        if (!this.worldObj.isRemote && this.numPlayersUsing != 0 && (this.ticksSinceSync + this.xCoord + this.yCoord + this.zCoord) % 200 == 0)
        {
            this.numPlayersUsing = 0;
            f = 5.0F;
            List list = this.worldObj.getEntitiesWithinAABB(EntityPlayer.class, AxisAlignedBB.getBoundingBox((double)((float)this.xCoord - f), (double)((float)this.yCoord - f), (double)((float)this.zCoord - f), (double)((float)(this.xCoord + 1) + f), (double)((float)(this.yCoord + 1) + f), (double)((float)(this.zCoord + 1) + f)));
            Iterator iterator = list.iterator();

            while (iterator.hasNext())
            {
                EntityPlayer entityplayer = (EntityPlayer)iterator.next();

                if (entityplayer.openContainer instanceof ContainerShop)
                {
                    ++this.numPlayersUsing;                    
                }
            }
        }

        this.prevLidAngle = this.lidAngle;
        f = 0.1F;
        double d2;

        if (this.numPlayersUsing > 0 && this.lidAngle == 0.0F && this.adjacentChestZNeg == null && this.adjacentChestXNeg == null)
        {
            double d1 = (double)this.xCoord + 0.5D;
            d2 = (double)this.zCoord + 0.5D;

            if (this.adjacentChestZPos != null)
            {
                d2 += 0.5D;
            }

            if (this.adjacentChestXPos != null)
            {
                d1 += 0.5D;
            }

            this.worldObj.playSoundEffect(d1, (double)this.yCoord + 0.5D, d2, "random.chestopen", 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F);
        }

        if (this.numPlayersUsing == 0 && this.lidAngle > 0.0F || this.numPlayersUsing > 0 && this.lidAngle < 1.0F)
        {
            float f1 = this.lidAngle;

            if (this.numPlayersUsing > 0)
            {
                this.lidAngle += f;
            }
            else
            {
                this.lidAngle -= f;
            }

            if (this.lidAngle > 1.0F)
            {
                this.lidAngle = 1.0F;
            }

            float f2 = 0.5F;

            if (this.lidAngle < f2 && f1 >= f2 && this.adjacentChestZNeg == null && this.adjacentChestXNeg == null)
            {
                d2 = (double)this.xCoord + 0.5D;
                double d0 = (double)this.zCoord + 0.5D;

                if (this.adjacentChestZPos != null)
                {
                    d0 += 0.5D;
                }

                if (this.adjacentChestXPos != null)
                {
                    d2 += 0.5D;
                }

                this.worldObj.playSoundEffect(d2, (double)this.yCoord + 0.5D, d0, "random.chestclosed", 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F);
            }

            if (this.lidAngle < 0.0F)
            {
                this.lidAngle = 0.0F;
            }
        }
    }

    
}

 

 

there are other variables in this class such as the contents that save just fine when closing the chest, but I cant find anywhere they are referenced that the 'Cost' is not... could it be associated to it being updated within the network handler? Like its another instance of the TileEntity or something?

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

Link to comment
Share on other sites

Thats actually exactly what I have done. The server side thread prints out the value immediately after incrementing in the server packet handler, and I can watch it climb with each bitton click. I can also watch the client reflect the change visually on the gui, which is only adjusted in the SendCost handler as shown above, which is the return value of successfully handling the server packet. Then I close the chest, reopen, and its at 0. My current guesses are that Coin gets reinitialized somehow or I am changing a temporary instance/clone of the TileEntity? I tried MarkDirty, markforUpdate. .. im lost for words!

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

Link to comment
Share on other sites

Well when I get at my computer I will post my container, gui, and packets; TileEntity is above. Surely the issue is there or missing from there. Maybe I have a lost line of code that reinitialized Coin somewhere I am overlooking or something. Are there any classes that could be related that I am not thinking of?

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

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.

Announcements



×
×
  • Create New...

Important Information

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