From b16c0ae023e9ee0114db520aa3e2324c7fbf5dea Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Sat, 12 Oct 2024 21:38:18 +0200 Subject: [PATCH] Add offline PDC API (#8117) --- patches/api/0495-Add-Offline-PDC-API.patch | 40 +++++++++ ...w-accessible-directly-from-ItemStack.patch | 85 ++++++++++--------- patches/server/1065-Add-Offline-PDC-API.patch | 45 ++++++++++ 3 files changed, 130 insertions(+), 40 deletions(-) create mode 100644 patches/api/0495-Add-Offline-PDC-API.patch create mode 100644 patches/server/1065-Add-Offline-PDC-API.patch diff --git a/patches/api/0495-Add-Offline-PDC-API.patch b/patches/api/0495-Add-Offline-PDC-API.patch new file mode 100644 index 0000000000..32bafdb4b3 --- /dev/null +++ b/patches/api/0495-Add-Offline-PDC-API.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Sat, 9 Jul 2022 17:17:04 +0200 +Subject: [PATCH] Add Offline PDC API + + +diff --git a/src/main/java/org/bukkit/OfflinePlayer.java b/src/main/java/org/bukkit/OfflinePlayer.java +index 3993fecec5b4c2bbd77e175a168afcad571ce4d1..a028f2fe541491729856051780b33dba07832fb6 100644 +--- a/src/main/java/org/bukkit/OfflinePlayer.java ++++ b/src/main/java/org/bukkit/OfflinePlayer.java +@@ -19,7 +19,7 @@ import org.jetbrains.annotations.Nullable; + * player that is stored on the disk and can, thus, be retrieved without the + * player needing to be online. + */ +-public interface OfflinePlayer extends ServerOperator, AnimalTamer, ConfigurationSerializable { ++public interface OfflinePlayer extends ServerOperator, AnimalTamer, ConfigurationSerializable, io.papermc.paper.persistence.PersistentDataViewHolder { // Paper - Add Offline PDC API + + /** + * Checks if this player is currently online +@@ -557,4 +557,20 @@ public interface OfflinePlayer extends ServerOperator, AnimalTamer, Configuratio + */ + @Nullable + public Location getLocation(); ++ // Paper start - add pdc to offline player ++ /** ++ * Yields a view of the persistent data container for this offline player. ++ * In case this {@link OfflinePlayer} instance was created for an offline player, the returned view will wrap the persistent ++ * data on disk. ++ *

++ * As such, this method as well as queries to the {@link io.papermc.paper.persistence.PersistentDataContainerView} ++ * may produce blocking IO requests to read the requested data from disk. ++ * Caution in its usage is hence advised. ++ * ++ * @return the persistent data container view ++ * @see io.papermc.paper.persistence.PersistentDataViewHolder#getPersistentDataContainer() ++ */ ++ @Override ++ io.papermc.paper.persistence.@NotNull PersistentDataContainerView getPersistentDataContainer(); ++ // Paper end - add pdc to offline player + } diff --git a/patches/server/1018-Make-a-PDC-view-accessible-directly-from-ItemStack.patch b/patches/server/1018-Make-a-PDC-view-accessible-directly-from-ItemStack.patch index 31fdc957f8..f86fe8c7dd 100644 --- a/patches/server/1018-Make-a-PDC-view-accessible-directly-from-ItemStack.patch +++ b/patches/server/1018-Make-a-PDC-view-accessible-directly-from-ItemStack.patch @@ -6,29 +6,33 @@ Subject: [PATCH] Make a PDC view accessible directly from ItemStack diff --git a/src/main/java/io/papermc/paper/persistence/PaperPersistentDataContainerView.java b/src/main/java/io/papermc/paper/persistence/PaperPersistentDataContainerView.java new file mode 100644 -index 0000000000000000000000000000000000000000..fac401280d3f3689b00e16c19155ca753faa06e0 +index 0000000000000000000000000000000000000000..122c32e82b299cafd7d0c6a9f4818523470c9f05 --- /dev/null +++ b/src/main/java/io/papermc/paper/persistence/PaperPersistentDataContainerView.java -@@ -0,0 +1,86 @@ +@@ -0,0 +1,120 @@ +package io.papermc.paper.persistence; + +import com.google.common.base.Preconditions; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; ++import java.util.Collections; ++import java.util.HashSet; ++import java.util.Set; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.Tag; +import org.bukkit.NamespacedKey; +import org.bukkit.craftbukkit.persistence.CraftPersistentDataAdapterContext; ++import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer; +import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry; +import org.bukkit.persistence.PersistentDataAdapterContext; ++import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.checker.nullness.qual.Nullable; -+import org.checkerframework.framework.qual.DefaultQualifier; ++import org.jspecify.annotations.NullMarked; ++import org.jspecify.annotations.Nullable; + -+@DefaultQualifier(NonNull.class) ++@NullMarked +public abstract class PaperPersistentDataContainerView implements PersistentDataContainerView { + + protected final CraftPersistentDataTypeRegistry registry; @@ -48,7 +52,7 @@ index 0000000000000000000000000000000000000000..fac401280d3f3689b00e16c19155ca75 + Preconditions.checkArgument(key != null, "The NamespacedKey key cannot be null"); + Preconditions.checkArgument(type != null, "The provided type cannot be null"); + -+ final @Nullable Tag value = this.getTag(key.toString()); ++ final Tag value = this.getTag(key.toString()); + if (value == null) { + return false; + } @@ -67,7 +71,7 @@ index 0000000000000000000000000000000000000000..fac401280d3f3689b00e16c19155ca75 + Preconditions.checkArgument(key != null, "The NamespacedKey key cannot be null"); + Preconditions.checkArgument(type != null, "The provided type cannot be null"); + -+ final @Nullable Tag value = this.getTag(key.toString()); ++ final Tag value = this.getTag(key.toString()); + if (value == null) { + return null; + } @@ -82,13 +86,43 @@ index 0000000000000000000000000000000000000000..fac401280d3f3689b00e16c19155ca75 + } + + @Override ++ public Set getKeys() { ++ final Set names = this.toTagCompound().getAllKeys(); ++ final Set keys = new HashSet<>(names.size()); ++ names.forEach(key -> { ++ final String[] keyPart = key.split(":", 2); ++ if (keyPart.length == 2) { ++ keys.add(new NamespacedKey(keyPart[0], keyPart[1])); ++ } ++ }); ++ return Collections.unmodifiableSet(keys); ++ } ++ ++ @Override ++ public boolean isEmpty() { ++ return this.toTagCompound().isEmpty(); ++ } ++ ++ @Override ++ public void copyTo(final PersistentDataContainer other, final boolean replace) { ++ Preconditions.checkArgument(other != null, "The target container cannot be null"); ++ final CraftPersistentDataContainer target = (CraftPersistentDataContainer) other; ++ final CompoundTag tag = this.toTagCompound(); ++ for (final String key : tag.getAllKeys()) { ++ if (replace || !target.getRaw().containsKey(key)) { ++ target.getRaw().put(key, tag.get(key).copy()); ++ } ++ } ++ } ++ ++ @Override + public PersistentDataAdapterContext getAdapterContext() { + return this.adapterContext; + } + + @Override + public byte[] serializeToBytes() throws IOException { -+ final net.minecraft.nbt.CompoundTag root = this.toTagCompound(); ++ final CompoundTag root = this.toTagCompound(); + final ByteArrayOutputStream byteArrayOutput = new ByteArrayOutputStream(); + try (final DataOutputStream dataOutput = new DataOutputStream(byteArrayOutput)) { + NbtIo.write(root, dataOutput); @@ -97,10 +131,10 @@ index 0000000000000000000000000000000000000000..fac401280d3f3689b00e16c19155ca75 + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -index db0fe1b755f59eafca6e57917429fb7889889c3a..454d1ad710159a47f2112f77ea4b6c87241caf4e 100644 +index a3c6d2cbdce60b1cf935d798568b8bb5d97e1229..6081c588c61406d0d21a15e8e6140d5d5240f0a8 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -@@ -484,4 +484,63 @@ public final class CraftItemStack extends ItemStack { +@@ -484,4 +484,34 @@ public final class CraftItemStack extends ItemStack { return mirrored; } // Paper end @@ -128,35 +162,6 @@ index db0fe1b755f59eafca6e57917429fb7889889c3a..454d1ad710159a47f2112f77ea4b6c87 + public net.minecraft.nbt.Tag getTag(final String key) { + return CraftItemStack.this.getPdcTag().get(key); + } -+ -+ @Override -+ public java.util.Set getKeys() { -+ java.util.Set keys = new java.util.HashSet<>(); -+ CraftItemStack.this.getPdcTag().getAllKeys().forEach(key -> { -+ final String[] keyData = key.split(":", 2); -+ if (keyData.length == 2) { -+ keys.add(new org.bukkit.NamespacedKey(keyData[0], keyData[1])); -+ } -+ }); -+ return java.util.Collections.unmodifiableSet(keys); -+ }; -+ -+ @Override -+ public boolean isEmpty() { -+ return CraftItemStack.this.getPdcTag().isEmpty(); -+ } -+ -+ @Override -+ public void copyTo(final org.bukkit.persistence.PersistentDataContainer other, final boolean replace) { -+ Preconditions.checkArgument(other != null, "The target container cannot be null"); -+ final org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer target = (org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer) other; -+ final net.minecraft.nbt.CompoundTag pdcTag = org.bukkit.craftbukkit.inventory.CraftItemStack.this.getPdcTag(); -+ for (final String key : pdcTag.getAllKeys()) { -+ if (replace || !target.getRaw().containsKey(key)) { -+ target.getRaw().put(key, pdcTag.get(key).copy()); -+ } -+ } -+ } + }; + @Override + public io.papermc.paper.persistence.PersistentDataContainerView getPersistentDataContainer() { diff --git a/patches/server/1065-Add-Offline-PDC-API.patch b/patches/server/1065-Add-Offline-PDC-API.patch new file mode 100644 index 0000000000..f1513955cb --- /dev/null +++ b/patches/server/1065-Add-Offline-PDC-API.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Sat, 9 Jul 2022 17:28:42 +0200 +Subject: [PATCH] Add Offline PDC API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java +index 4f4e3ee18d586f61706504218cddc06a38ca5580..94ca0407303c4493ab4928b12ec6ecc75aaca549 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java +@@ -325,6 +325,34 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa + } + // Paper end + ++ // Paper start - Add Offline PDC API ++ private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry(); ++ private io.papermc.paper.persistence.@org.checkerframework.checker.nullness.qual.MonotonicNonNull PersistentDataContainerView persistentDataContainerView; ++ ++ @Override ++ public io.papermc.paper.persistence.PersistentDataContainerView getPersistentDataContainer() { ++ if (this.persistentDataContainerView == null) { ++ this.persistentDataContainerView = new io.papermc.paper.persistence.PaperPersistentDataContainerView(DATA_TYPE_REGISTRY) { ++ ++ private CompoundTag getPersistentTag() { ++ return net.minecraft.Optionull.map(CraftOfflinePlayer.this.getData(), data -> data.getCompound("BukkitValues")); ++ } ++ ++ @Override ++ public CompoundTag toTagCompound() { ++ return java.util.Objects.requireNonNullElseGet(this.getPersistentTag(), CompoundTag::new); ++ } ++ ++ @Override ++ public net.minecraft.nbt.Tag getTag(String key) { ++ return net.minecraft.Optionull.map(this.getPersistentTag(), tag -> tag.get(key)); ++ } ++ }; ++ } ++ return this.persistentDataContainerView; ++ } ++ // Paper end - Add Offline PDC API ++ + @Override + public Location getLastDeathLocation() { + if (this.getData().contains("LastDeathLocation", 10)) {