Entity sub-classes save and load information using the writeToNBT() and readFromNBT() methods. For custom entities you have the ability to directly @Override these methods, so that's all you need to do.
Warning: The Entity class actually has some other similarly-named methods called writeEntityToNBT() and readEntityFromNBT() which are different -- they include a bunch of other information about the entity like UUID that are not typically needed.
However, if you need to add information for vanilla entities you won't be able to directly override these methods. So to allow this (adding information to entities):
- in 1.9 and later, you should use the Capability system.
- in 1.8 and earlier there is an interface provided called IExtendedEntityProperties that helps handle these properties. See Jabelar's Extended Entity Properties Tutorial.
Note: If the information you want to add to the vanilla entity isn't changeable, you can instead use the IEntityAdditionalSpawnData interface. This is available in all versions of Forge.
Warning: Both IEEP and Capability are not automatically synced between client and server, so if you need that then you will want to add a custom packet whenever the value changes to sync.
References To Other Information On Capabilities
You should also check out:
- Official Forge documentation
- Tutorial by williewillus
- Tutorial by McHorse
- Choonster's example Capability implementation (API, implementation)
Converting IEEP To Capabilities
If you're upgrading your mod you may need to convert your IEEP to Capabilities. The official Forge documentation explains how to convert.
Capabilities (Version 1.9 and Later)
Capabilities can be attached to entities, tile entities, items and worlds.
The concept of a capability is that you need to both register and "attach" the capability. Registration happens in your pre-init handling code using the CapabilityManager.INSTANCE.register() method. Attaching the capability depends on whether you're attaching to your own class (in which case you @Override the hasCapability() and getCapability() methods) or you handle the AttachCapabilitiesEvent.
You can attach existing capabilities, like IItemHolder or create your own custom one (e.g. for "mana" level).
So there are actually four different cases where you might use capabilities, and they are actually fairly different in terms of what you need to do:
- Using existing capabilities (e.g. IItemHolder) in your custom classes
- Using custom capabilities in your custom classes
- Using existing capabilities on vanilla (or other mod's) classes
- Using custom capabilities on vanilla (or other mod's) classes
The rest of my tutorial covers the most complicated case, Case #4, of making custom capabilities and attaching them to vanilla classes.
Attaching Custom Capabilities To Vanilla Classes
Here are the steps for using creating custom capabilities and using them on vanilla classes:
- Create a Capability interface (e.g. IMana) for each capability that has a getter and setter method for that capability. This class does not need to extend or implement anything and the getter and setter methods can have any name you wish (e.g. setMana() and getMana()).
- Create a class (e.g. Mana) that implements your capability interface. Typically this simply has a private field that holds the data and @Overrides the interface getter and setter methods.
- Create a class (e.g. ManaStorage) that implements IStorage that writes and reads classes that implement your capability interface(s). You will have to @Override the writeNBT() and readNBT() methods. To write you need to create a NBTTagCompound (or related NBTBase extension) and copy the capability data into it. To read you will expect to get the same format NBTTagCompound and simply have to read out the data in the reverse order.
- Create a provider class (e.g. ManaProvider) that implements ICapabilitySerializable
- Create a constant field that is declared as type of your capability interface (e.g. public final static Capability
MANA = null;) and "inject" your capability to it by adding the @CapabilityInject annotation.
- @Override the hasCapability() and getCapability() methods to provide the constant field.
- @Override the serializeNBT() and deserializeNBT() methods to use the storage (e.g. MANA.getStorage()) to call the related writeNBT() and readNBT() methods.
Key Point: To use your capability in your code, you simply use the getCapability() method on the appropriate thing and further call the getter and setter methods as appropriate (e.g. if you attached the capability to a player you'd use player.getCapability().getMana()).
Tip: You can attach multiple different capabilities to a capability provider.
Warning: For player entities, capabilities attached to them will not persist across death and respawn. To copy them, you will need to handle the PlayerEvent.Clone event. For example, something like this in the event handler:
// clone capabilities
EntityPlayer player = event.getEntityPlayer();
IMana mana = player.getCapability(ManaProvider.MANA, null);
IMana oldMana = event.getOriginal().getCapability(ManaProvider.MANA, null);
Syncing ItemStack Capabilities To Client
It is a fairly common modding desire to do some sort of rendering or client side logic based on capability data. However, as mentioned above, the capability data is not automatically synced between server and client.
It is possible to solve this in multiple ways, but all of them will require some sort of networking. For ItemStack syncing I recommend using the Item#getNBTShareTag() method to append the capability data that needs to sync to client.
The recommended steps are:
- Make sure your custom Capability IStorage properly implements a readNBT() and writeNBT() methods.
- In your custom Item class make sure that the getShareTag() returns true and that the getNBTShareTag() method adds the cability NBT (which you can get from Capability#writeNBT()). Important: You will want to specify some sort of key that you can use on client side to extract the tag data.
- In your client rendering or wherever you need it, you just look in the ItemStack NBT for the key that you specified in Step 2 above.
- Optionally. You can sync the entire client-side capability, however for most cases I think you can use the NBT data.
The Capability system is very important interfaces when changing the behavior of vanilla entities. It is worth your time to make sure you understand these useful tools.