-
-
Notifications
You must be signed in to change notification settings - Fork 159
chore: update pdc docs #620
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
fb56eef
a232b07
938df9a
4be6a5b
3e40d6d
abfd04b
d95441d
65610cc
6803f6a
bb725f5
76e717a
074bce9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -2,21 +2,22 @@ | |||
title: Persistent data container (PDC) | ||||
description: A guide to the PDC API for storing data. | ||||
slug: paper/dev/pdc | ||||
version: "1.21.4 and below" | ||||
--- | ||||
|
||||
The Persistent Data Container (PDC) is a way to store custom data on a whole range of objects; such as items, entities, and block entities. | ||||
The full list of classes that support the PDC are: | ||||
|
||||
- [`ItemStack`](#itemstack) | ||||
- [`Chunk`](#chunk) | ||||
- [`World`](#world) | ||||
- [`Entity`](#entity) | ||||
- [`TileState`](#tilestate) | ||||
- [`Structure`](#structure) | ||||
- [`ItemMeta`](#itemmeta) | ||||
- [`GeneratedStructure`](#generatedstructure) | ||||
- [`Raid`](#raid) | ||||
- [`OfflinePlayer`](#offlineplayer) | ||||
- [`ItemStack`](#itemstack) | ||||
- [`ItemMeta`](#itemmeta) | ||||
|
||||
## What is it used for? | ||||
In the past, developers resorted to a variety of methods to store custom data on objects: | ||||
|
@@ -37,20 +38,40 @@ which is the object you want to store the data on. The third is the data itself. | |||
// Create a NamespacedKey | ||||
NamespacedKey key = new NamespacedKey(pluginInstance, "example-key"); | ||||
|
||||
ItemStack item = ItemStack.of(Material.DIAMOND); | ||||
// ItemMeta implements PersistentDataHolder, so we can get the PDC from it | ||||
item.editMeta(meta -> { | ||||
meta.getPersistentDataContainer().set(key, PersistentDataType.STRING, "I love Tacos!"); | ||||
World world = Bukkit.getServer().getWorlds().getFirst(); | ||||
|
||||
PersistentDataContainer pdc = world.getPersistentDataContainer(); | ||||
|
||||
pdc.set(key, PersistentDataType.STRING, "I love Tacos!"); | ||||
``` | ||||
|
||||
[`ItemStack`](jd:paper:org.bukkit.inventory.ItemStack) however doesn't have this method and instead requires you to use its builder-style consumer: | ||||
|
||||
```java | ||||
NamespacedKey key = ...; // Retrieve the key from before | ||||
|
||||
// For 1.20.4 and below, use 'new ItemStack(Material.DIAMOND)' instead | ||||
ItemStack item = ItemType.DIAMOND.createItemStack(); | ||||
// ItemStack provides a util method, so we can directly edit its PDC | ||||
item.editPersistentDataContainer(pdc -> { | ||||
pdc.set(key, PersistentDataType.STRING, "I love Tacos!"); | ||||
}); | ||||
``` | ||||
|
||||
:::note | ||||
|
||||
The [`ItemStack#editPersistentDataContainer()`](jd:paper:org.bukkit.inventory.ItemStack#editPersistentDataContainer(java.util.function.Consumer)) method on `ItemStack` is only available in 1.21.4+. For older versions, you need to access and modify the `ItemMeta` instead. | ||||
For 1.16.5+, there's the [`ItemStack#editMeta()`](jd:paper:org.bukkit.inventory.ItemStack#editMeta(java.util.function.Consumer)) method though. | ||||
|
||||
::: | ||||
|
||||
:::note | ||||
|
||||
It is considered good practice to reuse `NamespacedKey` objects. They can be constructed with either: | ||||
- A [`Plugin`](jd:paper:org.bukkit.plugin.Plugin) instance and a [`String`](jd:java:java.lang.String) identifier | ||||
- A [`String`](jd:java:java.lang.String) namespace and a [`String`](jd:java:java.lang.String) identifier | ||||
|
||||
The first option is often preferred as it will automatically use the plugin's namespace; however, the second option can be used if you | ||||
The first option is often preferred as it will automatically use the plugin's lowercased name as namespace; however, the second option can be used if you | ||||
want to use a different namespace or access the data from another plugin. | ||||
|
||||
::: | ||||
|
@@ -63,15 +84,21 @@ To get data from the PDC, you need to know the `NamespacedKey` and the `Persiste | |||
NamespacedKey key = new NamespacedKey(pluginInstance, "example-key"); | ||||
|
||||
ItemStack item = ...; // Retrieve the item from before | ||||
// Get the data from the PDC | ||||
PersistentDataContainer container = item.getItemMeta().getPersistentDataContainer(); | ||||
if (container.has(key, PersistentDataType.STRING)) { | ||||
String value = container.get(key, PersistentDataType.STRING); | ||||
// Get the data from the PDC. Do note that ItemStack provides a "view", which is read-only | ||||
PersistentDataContainerView containerView = item.getPersistentDataContainer(); | ||||
if (containerView.has(key, PersistentDataType.STRING)) { | ||||
String value = containerView.get(key, PersistentDataType.STRING); | ||||
// Do something with the value | ||||
player.sendMessage(Component.text(value)); | ||||
} | ||||
``` | ||||
|
||||
:::note | ||||
|
||||
The [`ItemStack#getPersistentDataContainer()`](jd:paper:org.bukkit.inventory.ItemStack#getPersistentDataContainer()) method on `ItemStack` is only available in 1.21.1+. For older versions, you need to access and modify the `ItemMeta` instead. | ||||
|
||||
::: | ||||
|
||||
## Data types | ||||
|
||||
The PDC supports a wide range of data types, such as: | ||||
|
@@ -124,7 +151,14 @@ The `PersistentDataType`'s job is to "deconstruct" a complex data type into some | |||
Here is an example of how to do that for a UUID: | ||||
|
||||
```java title="UUIDDataType.java" | ||||
@NullMarked | ||||
public class UUIDDataType implements PersistentDataType<byte[], UUID> { | ||||
|
||||
public static final UUIDDataType INSTANCE = new UUIDDataType(); | ||||
|
||||
// We just need a singleton, so there's no need to allow instantiation | ||||
private UUIDDataType() {} | ||||
|
||||
zlataovce marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
@Override | ||||
public Class<byte[]> getPrimitiveType() { | ||||
return byte[].class; | ||||
|
@@ -160,11 +194,23 @@ In order to use your own `PersistentDataType`, you must pass an instance of it t | |||
[`set`](jd:paper:org.bukkit.persistence.PersistentDataContainer#set(org.bukkit.NamespacedKey,org.bukkit.persistence.PersistentDataType,C))/ | ||||
[`has`](jd:paper:io.papermc.paper.persistence.PersistentDataContainerView#has(org.bukkit.NamespacedKey,org.bukkit.persistence.PersistentDataType)) methods. | ||||
```java | ||||
container.set(key, new UUIDDataType(), uuid); | ||||
container.set(key, UUIDDataType.INSTANCE, uuid); | ||||
``` | ||||
|
||||
::: | ||||
|
||||
|
||||
## Read-only containers | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this should be just an aside
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, because then it wouldn't be in the sidebar There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if it's supposed to be a full-fledged section, it should elaborate on the purpose and benefit of accessing a view instead of a mutable version in general, not just a single note that duplicates information from the "Storing on different objects" section There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. well currently the purpose of the view is to side-step technical limitations, like the ItemMeta snapshot costliness or the file I/O intensity of having a mutable offline player PDC, which is pretty noteworthy |
||||
:::note | ||||
|
||||
- Certain classes, like `ItemStack` or [`OfflinePlayer`](jd:paper:org.bukkit.OfflinePlayer), provide a read-only view of their PDC. | ||||
In contrast to `ItemStack`, `OfflinePlayer` does <u>not</u> provide any way to modify the underlying container. | ||||
- This is because the `OfflinePlayer` is directly read from disk and would require a blocking file operation. | ||||
Mutable objects, like the `PersistentDataHolder#getPersistentDataContainer()`, generally need to be re-saved even without modification or monitored. | ||||
That's why it's better to use unmodifiable "views" for read-only operations. | ||||
|
||||
::: | ||||
|
||||
## Storing on different objects | ||||
|
||||
:::caution | ||||
|
@@ -178,6 +224,19 @@ E.g. Placing an ItemStack as a Block (with a TileState) ***does not*** copy over | |||
Objects that can have a PDC implement the [`PersistentDataHolder`](jd:paper:org.bukkit.persistence.PersistentDataHolder) interface | ||||
and their PDC can be fetched with [`PersistentDataHolder#getPersistentDataContainer()`](jd:paper:org.bukkit.persistence.PersistentDataHolder#getPersistentDataContainer()). | ||||
|
||||
- ##### [`ItemStack`](jd:paper:org.bukkit.inventory.ItemStack) | ||||
- The persistent data container of an `ItemStack` has historically been accessed by | ||||
the `ItemStack`'s `ItemMeta`. This, however, includes the overhead of constructing the entire `ItemMeta`, which acts as a snapshot of the `ItemStack`'s data at the point of creation. | ||||
|
||||
To avoid this overhead in 1.21.1+, ItemStack exposes a read-only view of its persistent data container at `ItemStack#getPersistentDataContainer()`. | ||||
Edits to the persistent data container can also be simplified in 1.21.4+ using `ItemStack#editPersistentDataContainer(java.util.function.Consumer)`. | ||||
The persistent data container available in the consumer is not valid outside the consumer. | ||||
```java | ||||
ItemStack itemStack = ...; | ||||
itemStack.editPersistentDataContainer(pdc -> { | ||||
pdc.set(key, PersistentDataType.STRING, "I love Tacos!"); | ||||
}); | ||||
``` | ||||
- ##### [`Chunk`](jd:paper:org.bukkit.Chunk) | ||||
- `Chunk#getPersistentDataContainer()` | ||||
- ##### [`World`](jd:paper:org.bukkit.World) | ||||
|
@@ -196,27 +255,12 @@ and their PDC can be fetched with [`PersistentDataHolder#getPersistentDataContai | |||
``` | ||||
- ##### [`Structure`](jd:paper:org.bukkit.structure.Structure) | ||||
- `Structure#getPersistentDataContainer()` | ||||
- ##### [`ItemMeta`](jd:paper:org.bukkit.inventory.meta.ItemMeta) | ||||
- `ItemMeta#getPersistentDataContainer()` | ||||
- ##### [`GeneratedStructure`](jd:paper:org.bukkit.generator.structure.GeneratedStructure) | ||||
- `GeneratedStructure#getPersistentDataContainer()` | ||||
- ##### [`Raid`](jd:paper:org.bukkit.Raid) | ||||
- `Raid#getPersistentDataContainer()` | ||||
- ##### [`OfflinePlayer`](jd:paper:org.bukkit.OfflinePlayer) | ||||
- OfflinePlayer only exposes a read-only version of the persistent data container. | ||||
It can be accessed via `OfflinePlayer#getPersistentDataContainer()`. | ||||
- ##### [`ItemStack`](jd:paper:org.bukkit.inventory.ItemStack) | ||||
- The persistent data container of an `ItemStack` has historically been accessed by | ||||
the `ItemStack`'s `ItemMeta`. This, however, includes the overhead of constructing the entire | ||||
`ItemMeta`, which acts as a snapshot of the `ItemStack`'s data at the point of creation. | ||||
|
||||
To avoid this overhead, ItemStack exposes a read-only view of its persistent data container at | ||||
`ItemStack#getPersistentDataContainer()`. | ||||
Edits to the persistent data container can be achieved via `ItemStack#editPersistentDataContainer(Consumer)`. | ||||
The persistent data container available in the consumer is not valid outside the consumer. | ||||
```java | ||||
ItemStack itemStack = ...; | ||||
itemStack.editPersistentDataContainer(pdc -> { | ||||
pdc.set(key, PersistentDataType.STRING, "I love Tacos!"); | ||||
}); | ||||
``` | ||||
- ##### [`ItemMeta`](jd:paper:org.bukkit.inventory.meta.ItemMeta) | ||||
- `ItemMeta#getPersistentDataContainer()` |
Uh oh!
There was an error while loading. Please reload this page.