Views
Actions
Difference between revisions of "Capabilities/Attaching/1.17"
(Copy Capabilities/Attaching to MC1.17 archive) |
(No difference)
|
Latest revision as of 05:49, 6 December 2021
As mentioned, attaching capabilities to objects that you have not created can be done using AttachCapabilitiesEvent
. The same event is used for all objects that can provide capabilities. AttachCapabilitiesEvent
has five valid generic types providing the following events:
AttachCapabilitiesEvent<Entity>
: Fires only for entities.AttachCapabilitiesEvent<BlockEntity>
: Fires only for block entities.AttachCapabilitiesEvent<ItemStack>
: Fires only for item stacks.AttachCapabilitiesEvent<Level>
: Fires only for levels.AttachCapabilitiesEvent<LevelChunk>
: Fires only for level chunks.
The generic type cannot be more specific than the above types. For example: If you want to attach capabilities to Player
, you have to subscribe to the AttachCapabilitiesEvent<Entity>
, and then determine that the provided object is an Player
before attaching the capability.
In all cases, the event has a method addCapability
, which can be used to attach capabilities to the target object. Instead of adding capabilities themselves to the list, you add capability providers, which have the chance to return capabilities only from certain sides. While the provider only needs to implement ICapabilityProvider
, if the capability needs to store data persistently it is possible to implement ICapabilitySerializable<T extends Tag>
which, on top of returning the capabilities, will allow providing NBT save/load functions.
For information on how to implement ICapabilityProvider
, refer to the a Capability section.
Creating Your Own Capability
In general terms, a capability is registered through the event RegisterCapabilitiesEvent
on the MOD
event bus via the #register
method.
@SubscribeEvent public void registerCaps(RegisterCapabilitiesEvent event) { event.register(IExampleCapability.class); }
Persisting LevelChunk and BlockEntity capabilities
Unlike Levels
, Entities
and ItemStacks
, LevelChunks
and BlockEntities
are only written to disk when they have been marked as dirty. A capability
implementation with persistent state for a LevelChunk
or a BlockEntity
should therefore ensure that whenever its state changes, its owner is marked as dirty.
ItemStackHandler
, commonly used for inventories in BlockEntities
, has an overridable method void onContentsChanged(int slot)
designed to be used to mark the BlockEntity
as dirty.
public class MyBlockEntity extends BlockEntity { private final IItemHandler inventory = new ItemStackHandler(...) { @Override protected void onContentsChanged(int slot) { super.onContentsChanged(slot); setChanged(); } } ... }
Synchronizing Data with Clients
By default, Capability data is not sent to clients. In order to change this, the mods have to manage their own synchronization code using packets.
There are three different situation in which you may want to send synchronization packets, all of them optional:
- When the entity spawns in the level, or the block is placed, you may want to share the initialization-assigned values with the clients.
- When the stored data changes, you may want to notify some or all of the watching clients.
- When a new client starts viewing the entity or block, you may want to notify it of the existing data.
Refer to the Networking page for more information on implementing network packets.
Persisting across Player Deaths
By default, the capability data does not persist on death. In order to change this, the data has to be manually copied when the player entity is cloned during the respawn process.
This can be done by handling the PlayerEvent$Clone
event, reading the data from the original entity, and assigning it to the new entity. In this event, the wasDead
field can be used to distinguish between respawning after death, and returning from the End. This is important because the data will already exist when returning from the End, so care has to be taken to not duplicate values in this case.