fabric/fabric-data-attachment-api-v1
Syst3ms ca8aad0623 Data Attachment Sync API (#4049)
Completes the data attachment API with client-server syncing capabilities.

## Motivation

The existing API works great for attaching data to game objects, be they serverside or clientside, but lacks any ability to synchronize between the two.

A mod that wants to add a "thirst" mechanic can easily do so on the server side by attaching an integer to every player. However, the mod may also want to use this information to render additional HUD elements on the client. Currently, informing the client of this data can only be done manually, which is cumbersome, error-prone, and is much better-suited as an API feature.

## API Changes

The API doesn't change a lot (at least compared to the implementation), with a few new methods and one new class.

One new method has been added to `AttachmentRegistry.Builder`, namely `syncWith`. It declares that an attachment type may be synchronized with some clients, and takes a `PacketCodec` to encode attachment data over the network, as well as an element of the new `AttachmentSyncPredicate` interface.

This interface extends `BiPredicate<AttachmentTarget, ServerPlayerEntity>` to allow for user-defined predicates, and provides some common presets:
* `all()`: attachment data will be synchronized with all clients (that track the target).
* `targetOnly()`: attachment data will only be synchronized with the target it is attached to, when it is a player. If the target is not a player, it won't be synchronized with any client.
* `allButTarget()`: reverse of the above. For non-player targets, attachment data will be synchronized with all clients.

**NOTE**: for a user-defined condition, whether attachment data is synchronized with a client can change at runtime (e.g. "sync only with operators" when a player changes operator status). A specialized method to "refresh" data was considered, but in the end discarded due to complexity. It falls to individual mods to handle these edge cases.

AttachmentType also gets one new `isSynced` method to know whether a given attachment type can be synced.

## Usage

Here is how one could register an attachment for a "thirst" meter like mentioned above.
```java
public static final AttachmentType<Integer> THIRST = AttachmentRegistry.<Integer>builder()
    .initializer(() -> 20) // start with a default value like hunger
    .persistent(Codec.INT) // persist across restarts
    .syncWith(PacketCodecs.VAR_INT.cast(), AttachmentSyncPredicate.targetOnly()) // only the player's own client needs the value for rendering
    .buildAndRegister(Identifier.of("modid", "thirst"));
```
2024-11-12 18:31:14 +00:00
..
src Data Attachment Sync API (#4049) 2024-11-12 18:31:14 +00:00
build.gradle Data Attachment Sync API (#4049) 2024-11-12 18:31:14 +00:00