Lycanus Darkbinder Posted September 8, 2013 Posted September 8, 2013 I have TileEntity with a field called isRemote that gets set in onBlockPlacedBy() based on world.isRemote. When a block is placed, two TileEntity are created and the fields set to true and false. When I press ESC, writeToNBT() gets called only once and isRemote is false indicating this is the server TileEntity. It seems that the TileEntity where isRemote is true never gets a call to writeToNBT(). I print to the console the value of isRemote every time the function is called and it never prints "true". Quote
Lycanus Darkbinder Posted September 8, 2013 Author Posted September 8, 2013 I have TileEntity with a field called isRemote that gets set in onBlockPlacedBy() based on world.isRemote.Why that? TileEntity has a field worldObj . Use that. Well for one, worldObj is not available while in the constructor. All properties from the TileEntity super class are NULL while in the constructor. My constructor accepts a boolean. When a block is placed, two TileEntity are created and the fields set to true and false. When I press ESC, writeToNBT() gets called only once and isRemote is false indicating this is the server TileEntity.Of course. Why should the client save any NBT data? The server is the side that manages the game, saves the world, etc. The client only has dummy values for everything. Think of a dedicated server (connect via IP): Where should the client save the world to if it would? On a singleplayer world, the chunkcache attempts to load the TileEntity for the client but fails so it builds a new one. After the server TileEntity is loaded with readFromNBT, the call stack looks like this: TileEntitySmartLight.<init>(World) line: 48 BlockSmartLight.createTileEntity(World, int) line: 375 Chunk.getChunkBlockTileEntity(int, int, int) line: 995 ChunkCache.getBlockTileEntity(int, int, int) line: 115 WorldRenderer.updateRenderer() line: 208 The bolded part is where it falls down because the TileEntity is not saved so it builds a brand new one. Here's the piece from Chunk.getChunkBlockTileEntity if (tileentity == null) { tileentity = Block.blocksList[l].createTileEntity(this.worldObj, meta); this.worldObj.setBlockTileEntity(this.xPosition * 16 + par1, par2, this.zPosition * 16 + par3, tileentity); } In the above code, this.worldObj is a WorldClient. Why is the client expecting chunkcache to have a TileEntity if, as you say, they're not supposed to be saved? More importantly, could you please point me in the direction of some up-to-date documentation on how people save and load TileEntities? My TileEntity isn't even that fancy but it seems like it's a lot more work than advertised in the wiki. Quote
Lycanus Darkbinder Posted September 9, 2013 Author Posted September 9, 2013 More importantly, could you please point me in the direction of some up-to-date documentation on how people save and load TileEntities? My TileEntity isn't even that fancy but it seems like it's a lot more work than advertised in the wiki. It seems like you are doing or understanding something very wrong here. To save a TE put the data you need into the NBTTagCompound passed to writeToNBT and read the data back in readFromNBT. Done. If you need the data on the client, too, you need to sync it with packets. Let me explain what's happening so you can better understand my issue: 1. Click "Single Player" 2. Choose a world and click "Play Selected World" 3. createAndLoadEntity() gets called (TileEntity.java) 4. This calls the default constructor of my TileEntitySmartLight (only here for breakpoint purposes) 5. Then my readFromNBT() gets called which indicates the server is requesting this TileEntity 6. Then WorldRenderer.updateRenderer() checks the chunkcache for a client side TileEntity 7. ChunkCache.getBlockTileEntity() calls chunk.getTileEntity() 8. This leads to BlockSmartLight.createTileEntity() indicating we're creating a client TileEntity 9. BlockSmartLight.getLightValue() gets called which has a parameter of IBlockAccess 10. IBlockAccess.getBlockTileEntity() returns the client TileEntity from #8, not the server TileEntity from #5 So, how do I synchronize the client TileEntity that getLightValue() is asking for when this is happening at world load and there is no function override between steps #5 and steps #6 when the game requests the two TileEntities? It wouldn't be a problem if getLightValue() didn't use IBlockAccess but that always gets a client version of the TileEntity, it never loads a server version. Any advice would be appreciated. I don't see how packets can help the situation but since I've not seen any good documentation on packets I can't really comment. PS: As for the constructor, I kept getting console messages "Ignoring entity with TileEntitySmartLight" until I added the constructor. Once I put it in (even an empty one) the messages stopped. Quote
Mazetar Posted September 9, 2013 Posted September 9, 2013 You need to send packets in order for the client to get the TE from the server on entering the world, check out this thread, it may be of interest to you: http://www.minecraftforum.net/topic/1969772-solvedhow-to-load-data-from-tileentity-before-activating-its-block/ Quote If you guys dont get it.. then well ya.. try harder...
Lycanus Darkbinder Posted September 9, 2013 Author Posted September 9, 2013 You need to send packets in order for the client to get the TE from the server on entering the world, check out this thread, it may be of interest to you: http://www.minecraftforum.net/topic/1969772-solvedhow-to-load-data-from-tileentity-before-activating-its-block/ Thanks for that. It's still not clicking in my brain how that all works. createTileEntity() has to be called for the client because it doesn't exist yet. This is where my disconnect comes in. I don't understand how those packet functions tell the server to give me a copy of it's TileEntity so I can stuff the data into the client version. TileEntity.getDescriptionPacket() only gets called for server TileEntities (worldObj.isRemote == false) and TileEntity.onDataPacket() never got called at all. edit: oops, I was returning null from getDescriptionPacket() instead of my actual packet... I'm sure it's one of those "why didn't I think of that" moments when it clicks but right now it's just eluding me. Quote
Lycanus Darkbinder Posted September 10, 2013 Author Posted September 10, 2013 Thanks for the help everyone, this did the trick: @Override public Packet getDescriptionPacket() { // The server calls this function and if we return the NBT filled // with data, this.onDataPacket() will be called for the client with // the server's NBT info NBTTagCompound tag = new NBTTagCompound(); this.writeToNBT(tag); return new Packet132TileEntityData(this.xCoord, this.yCoord, this.zCoord, 1, tag); } @Override public void onDataPacket(INetworkManager net, Packet132TileEntityData pkt) { // PKT contains an NBTTagCompound with the server's TileEntity info. // We can parse that into our local variables so we stay in sync when our various // "get" methods are called to access TileEntity data. this.readFromNBT(pkt.customParam1); } Quote
Recommended Posts
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.