Minecraft Modding: TileEntity Quick Tips

Turning Off Updates For TileEntity When Possible


The reason why Minecraft uses single block instances per type and limited metadata per block location is to ensure perf is acceptable in a world with a million (literally) block locations.  However, sometimes you want a "smarter" block that contains more information than the 4 bits that metadata allows.  So there is ability to associate a TileEntity with certain blocks.  However, if you place too many of these, it will again hurt performance.

In some cases you may have a TileEntity that stores information or controls rendering but does not need to execute code.  In such cases, you just need to @Override the canUpdate() method to return false.

Note: the canUpdate() method is only checked at time tile entities are loaded, so you cannot dynamically change the return value in this method.  Also, even though the World.loadedTileEntityList is public, modifying it can cause co=modification error crashes.

Retaining Tile Entity When Block State Changes (1.8)


In 1.8, each time the block state changes, the default behavior is that the TileEntity is replaced. This is often not what you want, so to change this you need to override the shouldRefresh() method. However, you shouldn't just return false because you need to handle the case where the block is replaced with different block.

Key Point: You should probably always override this method unless you're sure that the default behavior is what you want.

So proper override is:

public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newSate)
{
    return (oldState.getBlock() != newSate.getBlock());
}

Syncing Tile Entity Data Across All Clients


For efficiency reasons, tile entities normally only update other clients when the GUI is active. However it is possible that you want to communicate something else more continuously.  You can update the tile entities at any time by using the description packets approach.

Simply, the description packet should contain the data you want to sync.  So you should @Override the getDescriptionPacket() method in your custom tile entity to return a Packet (make sure you import this from the net.minecraft.network package not some other package).  In the payload for that packet you will put a buffer filled with your data.  I personally use an NBTCompound to hold all the data and pack that into the buffer, but you can also just put a series of integers, strings, booleans, etc.

You also need to @Override the onDataPacket() method to take any received packets and update the local field values based on the contents of the packet payload.

You do not want to sync every tick as that will create performance problems.  Instead you will want to only send a packet when there is a change worth sharing with the other clients.  In whatever code detects such a change you can then send a packet as needed using the following code:

worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); // Makes the server call getDescriptionPacket for a full data sync
markDirty(); // Marks the chunk as dirty, so that it is saved properly on changes.

That's it!

What Happened To updateEntity() Method In 1.8?


When porting a mod to 1.8 you might notice that there is no longer an updateEntity() method in TileEntity. Tile entities don't receive tick updates by default anymore, to improve performance. You need to opt-in by implementing IUpdatePlayerListBox (it will be renamed to something like ITickable in 1.8.3 most likely).

1 comment:

  1. Oh wow thank you so much for this! I was trying so hard to figure out how to animate my model blocks in my mod, and this helped me figure it out!

    ReplyDelete