From b24a2838d2cc7c707b3132146c3feaa0792bdcfb Mon Sep 17 00:00:00 2001 From: Technici4n <13494793+Technici4n@users.noreply.github.com> Date: Mon, 11 Dec 2023 10:35:01 +0100 Subject: [PATCH] Review --- docs/datastorage/attachments.md | 33 ++++++++++++++++++-------------- docs/datastorage/capabilities.md | 10 ++++++---- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/docs/datastorage/attachments.md b/docs/datastorage/attachments.md index 8694e40e1..06df77274 100644 --- a/docs/datastorage/attachments.md +++ b/docs/datastorage/attachments.md @@ -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> ATTACHMENT_TYPES = DeferredRegister.create(NeoForgeRegistries.Keys.ATTACHMENT_TYPES, MOD_ID); +private static final DeferredRegister> ATTACHMENT_TYPES = DeferredRegister.create(NeoForgeRegistries.ATTACHMENT_TYPES, MOD_ID); // Serialization via INBTSerializable private static final Supplier> HANDLER = ATTACHMENT_TYPES.register( @@ -36,7 +39,7 @@ private static final Supplier> 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); ``` @@ -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 @@ -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. diff --git a/docs/datastorage/capabilities.md b/docs/datastorage/capabilities.md index fa2568a8c..a7ef29b24 100644 --- a/docs/datastorage/capabilities.md +++ b/docs/datastorage/capabilities.md @@ -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. @@ -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) { @@ -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