Skip to content

Commit

Permalink
Review
Browse files Browse the repository at this point in the history
  • Loading branch information
Technici4n committed Dec 11, 2023
1 parent c58e8cb commit b24a283
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 18 deletions.
33 changes: 19 additions & 14 deletions docs/datastorage/attachments.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,26 @@ _To store additional level data, you can use [SavedData](saveddata)._
## Creating an attachment type

To use the system, you need to register an `AttachmentType`.
The attachment type contains:
- a default value supplier to create the instance when the data is first accessed, or to compare stacks that have the data and stacks that don't have it;
- an optional serializer if the attachment should be persisted;
- additional configuration options for the attachment, for example the `copyOnDeath` flag.
The attachment type contains the following configuration:
- A default value supplier to create the instance when the data is first accessed. Also used to compare stacks that have the data with stacks that don't have it.
- An optional serializer if the attachment should be persisted.
- (If a serializer was configured) The `copyOnDeath` flag to automatically copy entity data on death (see below).
- (Advanced) (If a serializer was configured) A custom `comparator` to use when checking if the data is the same for two item stacks.

:::tip
If you don't want your attachment to persist, do not provide a serializer.
:::

There are a few ways to provide an attachment serializer: directly implementing `IAttachmentSerializer`, implementing `INBTSerializable` and using the static `AttachmentSerializer.serializable()` method to create the builder, or providing a codec to the builder.

:::warning
If you don't provide a serializer, the attachment will not be saved to disk.
(This can be intended).
If your data attachment disappears when you reload the world but you want it to persist, you probably forgot to provide a serializer.
Avoid serialization with codecs for item stack attachments, as it is comparatively slow.
:::

There are a few ways to provide an attachment serializer: directly implementing `IAttachmentSerializer`, implementing `INBTSerializable` and using the static `AttachmentSerializer.serializable()` method to create the builder, or providing a codec to the builder. (This latter option is not recommended for item stacks due to relatively slowness).

In any case, we recommend using a `DeferredRegister` for registration:
In any case, the attachment **must be registered** to the `NeoForgeRegistries.ATTACHMENT_TYPES` registry. Here is an example:
```java
// Create the DeferredRegister for attachment types
private static final DeferredRegister<AttachmentType<?>> ATTACHMENT_TYPES = DeferredRegister.create(NeoForgeRegistries.Keys.ATTACHMENT_TYPES, MOD_ID);
private static final DeferredRegister<AttachmentType<?>> ATTACHMENT_TYPES = DeferredRegister.create(NeoForgeRegistries.ATTACHMENT_TYPES, MOD_ID);

// Serialization via INBTSerializable
private static final Supplier<AttachmentType<ItemStackHandler>> HANDLER = ATTACHMENT_TYPES.register(
Expand All @@ -36,7 +39,7 @@ private static final Supplier<AttachmentType<SomeCache>> SOME_CACHE = ATTACHMENT
"some_cache", () -> AttachmentType.builder(() -> new SomeCache()).build()
);

// Don't forget to register the DeferredRegister to your mod bus:
// In your mod constructor, don't forget to register the DeferredRegister to your mod bus:
ATTACHMENT_TYPES.register(modBus);
```

Expand Down Expand Up @@ -68,6 +71,7 @@ The data can also be updated with `setData`:
player.setData(MANA, player.getData(MANA) + 10);
```

:::important
Usually, block entities and chunks need to be marked as dirty when they are modified (with `setChanged` and `setUnsaved(true)`). This is done automatically for calls to `setData`:
```java
chunk.setData(MANA, chunk.getData(MANA) + 10); // will call setUnsaved automatically
Expand All @@ -78,12 +82,13 @@ var mana = chunk.getData(MUTABLE_MANA);
mana.set(10);
chunk.setUnsaved(true); // must be done manually because we did not use setData
```
:::

## Sharing data with the client
Currently, only serializable item stack attachments are synced with the client.
Currently, only serializable item stack attachments are synced between the client and the server.
This is done automatically.

To sync block entity, chunk, or entity attachments, you need to [send a packet to the client][network] yourself.
To sync block entity, chunk, or entity attachments to a client, you need to [send a packet to the client][network] yourself.

## Copying data on player death
By default, entity data attachments are not copied on player death.
Expand Down
10 changes: 6 additions & 4 deletions docs/datastorage/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,13 +224,13 @@ level.invalidateCapabilities(pos);
NeoForge already handles common cases such as chunk load/unloads and block entity creation/removal,
but other cases need to be handled explicitly by modders.
For example, modders must invalidate capabilities in the following cases:
- If the configuration of a capability-providing block entity changes.
- If a previously returned capability is no longer valid.
- If a capability-providing block (without a block entity) is placed or changes state, by overriding `onPlace`.
- If a capability-providing block (without a block entity) is removed, by overriding `onRemove`.

For a plain block example, refer to the `ComposterBlock.java` file.

For more information, refer to the javadoc of `IBlockCapabilityProvider`.
For more information, refer to the javadoc of [`IBlockCapabilityProvider`][block-cap-provider].

## Registering capabilities
A capability _provider_ is what ultimately supplies a capability.
Expand Down Expand Up @@ -290,7 +290,7 @@ event.registerItem(
If for some reason you need to register a provider for all blocks, entities, or items,
you will need to iterate the corresponding registry and register the provider for each object.

For example, NeoForge uses this system to register a fluid handler capability for all buckets:
For example, NeoForge uses this system to register a fluid handler capability for all `BucketItem`s (excluding subclasses):
```java
// For reference, you can find this code in the `CapabilityHooks` class.
for (Item item : BuiltInRegistries.ITEM) {
Expand All @@ -313,6 +313,8 @@ modBus.addListener(RegisterCapabilitiesEvent.class, event -> {
MY_CUSTOM_BUCKET);
}, EventPriority.HIGH); // use HIGH priority to register before NeoForge!
```
See `CapabilityHooks` for a list of the providers registered by NeoForge itself.
See [`CapabilityHooks`][capability-hooks] for a list of the providers registered by NeoForge itself.

[block-cap-provider]: https://github.com/neoforged/NeoForge/blob/1.20.x/src/main/java/net/neoforged/neoforge/capabilities/IBlockCapabilityProvider.java
[capability-hooks]: https://github.com/neoforged/NeoForge/blob/1.20.x/src/main/java/net/neoforged/neoforge/capabilities/CapabilityHooks.java
[invalidation]: #block-capability-invalidation

1 comment on commit b24a283

@neoforged-pages-deployments
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploying with Cloudflare Pages

Name Result
Last commit: b24a2838d2cc7c707b3132146c3feaa0792bdcfb
Status: ✅ Deploy successful!
Preview URL: https://cd2372fd.neoforged-docs-previews.pages.dev
PR Preview URL: https://pr-34.neoforged-docs-previews.pages.dev

Please sign in to comment.