aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/1036-Switch-Impl-types-to-Holderable.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/server/1036-Switch-Impl-types-to-Holderable.patch')
-rw-r--r--patches/server/1036-Switch-Impl-types-to-Holderable.patch494
1 files changed, 494 insertions, 0 deletions
diff --git a/patches/server/1036-Switch-Impl-types-to-Holderable.patch b/patches/server/1036-Switch-Impl-types-to-Holderable.patch
new file mode 100644
index 0000000000..b695639796
--- /dev/null
+++ b/patches/server/1036-Switch-Impl-types-to-Holderable.patch
@@ -0,0 +1,494 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jake Potrebic <[email protected]>
+Date: Sun, 24 Nov 2024 15:08:19 -0800
+Subject: [PATCH] Switch Impl types to Holderable
+
+
+diff --git a/src/main/java/io/papermc/paper/util/Holderable.java b/src/main/java/io/papermc/paper/util/Holderable.java
+index 404ab0df12bc8182520c77328017c128d22993eb..3401d0073f1a98360495c1e73ae2de0146601604 100644
+--- a/src/main/java/io/papermc/paper/util/Holderable.java
++++ b/src/main/java/io/papermc/paper/util/Holderable.java
+@@ -1,8 +1,21 @@
+ package io.papermc.paper.util;
+
++import com.google.gson.JsonElement;
++import com.google.gson.JsonObject;
++import com.mojang.serialization.Codec;
++import com.mojang.serialization.JsonOps;
++import net.kyori.adventure.key.Key;
+ import net.minecraft.core.Holder;
++import net.minecraft.resources.RegistryOps;
++import org.bukkit.Keyed;
++import org.bukkit.Registry;
++import org.bukkit.craftbukkit.CraftRegistry;
+ import org.bukkit.craftbukkit.util.Handleable;
++import org.intellij.lang.annotations.Subst;
++import org.jspecify.annotations.NullMarked;
++import org.jspecify.annotations.Nullable;
+
++@NullMarked
+ public interface Holderable<M> extends Handleable<M> {
+
+ Holder<M> getHolder();
+@@ -11,4 +24,55 @@ public interface Holderable<M> extends Handleable<M> {
+ default M getHandle() {
+ return this.getHolder().value();
+ }
++
++ static <T extends Keyed, M> @Nullable T fromBukkitSerializationObject(final Object deserialized, final Codec<? extends Holder<M>> codec, final Registry<T> registry) { // TODO remove Keyed
++ return switch (deserialized) {
++ case @Subst("key:value") final String string -> {
++ if (!(Key.parseable(string))) {
++ yield null;
++ }
++ yield registry.get(Key.key(string));
++ }
++ case JsonObjectWrapper(final JsonObject element) -> {
++ if (!(registry instanceof final CraftRegistry<?, ?> craftRegistry) || !craftRegistry.supportsDirectHolders()) {
++ throw new IllegalArgumentException("Cannot deserialize direct holders for " + registry);
++ }
++ final RegistryOps<JsonElement> ops = CraftRegistry.getMinecraftRegistry().createSerializationContext(JsonOps.INSTANCE);
++ final Holder<M> holder = codec.decode(ops, element).getOrThrow().getFirst();
++ yield ((CraftRegistry<T, M>) registry).convertDirectHolder(holder);
++ }
++ default -> throw new IllegalArgumentException("Cannot deserialize " + deserialized);
++ };
++ }
++
++ default Object toBukkitSerializationObject(final Codec<? super Holder<M>> codec) {
++ return switch (this.getHolder()) {
++ case final Holder.Direct<M> direct -> {
++ final RegistryOps<JsonElement> ops = CraftRegistry.getMinecraftRegistry().createSerializationContext(JsonOps.INSTANCE);
++ yield new JsonObjectWrapper(codec.encodeStart(ops, direct).getOrThrow().getAsJsonObject());
++ }
++ case final Holder.Reference<M> reference -> reference.key().location().toString();
++ default -> throw new IllegalArgumentException("Cannot serialize " + this.getHolder());
++ };
++ }
++
++ /**
++ * All implementations should use this as their hashCode implementation
++ */
++ default int implHashCode() {
++ return this.getHolder().hashCode();
++ }
++
++ /**
++ * All implementations should use this as their equals implementation
++ */
++ default boolean implEquals(final @Nullable Object o) {
++ if (o == null || this.getClass() != o.getClass()) return false;
++ final Holderable<?> that = (Holderable<?>) o;
++ return this.getHolder().equals(that.getHolder());
++ }
++
++ default String implToString() {
++ return "%s{holder=%s}".formatted(this.getClass().getSimpleName(), this.getHolder().toString());
++ }
+ }
+diff --git a/src/main/java/io/papermc/paper/util/JsonObjectWrapper.java b/src/main/java/io/papermc/paper/util/JsonObjectWrapper.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..4522eb172b2894a950b2a32ac5af602991daa2e9
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/util/JsonObjectWrapper.java
+@@ -0,0 +1,34 @@
++package io.papermc.paper.util;
++
++import com.google.gson.Gson;
++import com.google.gson.JsonElement;
++import com.google.gson.JsonObject;
++import com.google.gson.JsonParser;
++import java.util.Map;
++import org.bukkit.configuration.serialization.ConfigurationSerializable;
++import org.bukkit.configuration.serialization.ConfigurationSerialization;
++import org.jspecify.annotations.NullMarked;
++
++@NullMarked
++public record JsonObjectWrapper(JsonObject element) implements ConfigurationSerializable {
++
++ private static final String KEY = "value";
++ private static final Gson GSON = new Gson();
++
++ static {
++ ConfigurationSerialization.registerClass(JsonObjectWrapper.class);
++ }
++
++ public JsonObjectWrapper(final JsonElement element) {
++ this(element.getAsJsonObject());
++ }
++
++ public JsonObjectWrapper(final Map<String, Object> input) {
++ this(JsonParser.parseString((String) input.get(KEY)).getAsJsonObject());
++ }
++
++ @Override
++ public Map<String, Object> serialize() {
++ return Map.of(KEY, GSON.toJson(this.element));
++ }
++}
+diff --git a/src/main/java/org/bukkit/craftbukkit/CraftMusicInstrument.java b/src/main/java/org/bukkit/craftbukkit/CraftMusicInstrument.java
+index 2838ef9d89ec8d7bd8981eff4a2ffe2c11ee9271..aa19ac75135893b81000d1bd63795457a777e9eb 100644
+--- a/src/main/java/org/bukkit/craftbukkit/CraftMusicInstrument.java
++++ b/src/main/java/org/bukkit/craftbukkit/CraftMusicInstrument.java
+@@ -10,14 +10,14 @@ import org.bukkit.Registry;
+ import org.bukkit.craftbukkit.util.Handleable;
+ import org.jetbrains.annotations.NotNull;
+
+-public class CraftMusicInstrument extends MusicInstrument implements Handleable<Instrument> {
++public class CraftMusicInstrument extends MusicInstrument implements io.papermc.paper.util.Holderable<Instrument> {
+
+ public static MusicInstrument minecraftToBukkit(Instrument minecraft) {
+ return CraftRegistry.minecraftToBukkit(minecraft, Registries.INSTRUMENT, Registry.INSTRUMENT);
+ }
+
+ public static MusicInstrument minecraftHolderToBukkit(Holder<Instrument> minecraft) {
+- return CraftMusicInstrument.minecraftToBukkit(minecraft.value());
++ return CraftRegistry.minecraftHolderToBukkit(minecraft, Registry.INSTRUMENT); // Paper - switch to Holder
+ }
+
+ public static Instrument bukkitToMinecraft(MusicInstrument bukkit) {
+@@ -25,41 +25,51 @@ public class CraftMusicInstrument extends MusicInstrument implements Handleable<
+ }
+
+ public static Holder<Instrument> bukkitToMinecraftHolder(MusicInstrument bukkit) {
+- Preconditions.checkArgument(bukkit != null);
+-
+- net.minecraft.core.Registry<Instrument> registry = CraftRegistry.getMinecraftRegistry(Registries.INSTRUMENT);
+-
+- if (registry.wrapAsHolder(CraftMusicInstrument.bukkitToMinecraft(bukkit)) instanceof Holder.Reference<Instrument> holder) {
+- return holder;
+- }
+-
+- throw new IllegalArgumentException("No Reference holder found for " + bukkit
+- + ", this can happen if a plugin creates its own instrument without properly registering it.");
++ return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.INSTRUMENT); // Paper - switch to Holder
+ }
+
+- public static String bukkitToString(MusicInstrument bukkit) {
++ public static Object bukkitToString(MusicInstrument bukkit) { // Paper - switch to Holder
+ Preconditions.checkArgument(bukkit != null);
+
+- return bukkit.getKey().toString();
++ return ((CraftMusicInstrument) bukkit).toBukkitSerializationObject(Instrument.CODEC); // Paper - switch to Holder
+ }
+
+- public static MusicInstrument stringToBukkit(String string) {
++ public static MusicInstrument stringToBukkit(Object string) { // Paper - switch to Holder
+ Preconditions.checkArgument(string != null);
+
+- return Registry.INSTRUMENT.get(NamespacedKey.fromString(string));
++ return io.papermc.paper.util.Holderable.fromBukkitSerializationObject(string, Instrument.CODEC, Registry.INSTRUMENT); // Paper - switch to Holder
+ }
+
+ private final NamespacedKey key;
+ private final Instrument handle;
+
+- public CraftMusicInstrument(NamespacedKey key, Instrument handle) {
+- this.key = key;
+- this.handle = handle;
++ // Paper start - switch to Holder
++ @Override
++ public boolean equals(final Object o) {
++ return this.implEquals(o);
++ }
++
++ @Override
++ public int hashCode() {
++ return this.implHashCode();
++ }
++
++ @Override
++ public String toString() {
++ return this.implToString();
++ }
++
++ private final Holder<Instrument> holder;
++ public CraftMusicInstrument(Holder<Instrument> holder) {
++ this.holder = holder;
++ this.key = holder.unwrapKey().map(io.papermc.paper.util.MCUtil::fromResourceKey).orElse(null);
++ this.handle = holder.value();
++ // Paper end - switch to Holder
+ }
+
+ @Override
+- public Instrument getHandle() {
+- return this.handle;
++ public Holder<Instrument> getHolder() { // Paper - switch to Holder
++ return this.holder; // Paper - switch to Holder
+ }
+
+ @NotNull
+@@ -79,26 +89,5 @@ public class CraftMusicInstrument extends MusicInstrument implements Handleable<
+ }
+ // Paper end - add translationKey methods
+
+- @Override
+- public boolean equals(Object other) {
+- if (this == other) {
+- return true;
+- }
+-
+- if (!(other instanceof CraftMusicInstrument)) {
+- return false;
+- }
+-
+- return this.getKey().equals(((MusicInstrument) other).getKey());
+- }
+-
+- @Override
+- public int hashCode() {
+- return this.getKey().hashCode();
+- }
+-
+- @Override
+- public String toString() {
+- return "CraftMusicInstrument{key=" + this.key + "}";
+- }
++ // Paper - switch to Holder
+ }
+diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java
+index 6532bdaf6cbd10ecc5ace1b89899ad82e7bca206..8f2276fcd20d2ececbda3ad1460e78aeed914707 100644
+--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java
++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java
+@@ -54,21 +54,17 @@ public class CraftMetaArmor extends CraftMetaItem implements ArmorMeta {
+
+ Map<?, ?> trimData = SerializableMeta.getObject(Map.class, map, CraftMetaArmor.TRIM.BUKKIT, true);
+ if (trimData != null) {
+- String materialKeyString = SerializableMeta.getString(trimData, CraftMetaArmor.TRIM_MATERIAL.BUKKIT, true);
+- String patternKeyString = SerializableMeta.getString(trimData, CraftMetaArmor.TRIM_PATTERN.BUKKIT, true);
++ Object materialKeyString = SerializableMeta.getObject(Object.class, trimData, CraftMetaArmor.TRIM_MATERIAL.BUKKIT, true); // Paper - switch to Holder
++ Object patternKeyString = SerializableMeta.getObject(Object.class, trimData, CraftMetaArmor.TRIM_PATTERN.BUKKIT, true); // Paper - switch to Holder
+
+ if (materialKeyString != null && patternKeyString != null) {
+- NamespacedKey materialKey = NamespacedKey.fromString(materialKeyString);
+- NamespacedKey patternKey = NamespacedKey.fromString(patternKeyString);
+-
+- if (materialKey != null && patternKey != null) {
+- TrimMaterial trimMaterial = Registry.TRIM_MATERIAL.get(materialKey);
+- TrimPattern trimPattern = Registry.TRIM_PATTERN.get(patternKey);
+-
+- if (trimMaterial != null && trimPattern != null) {
+- this.trim = new ArmorTrim(trimMaterial, trimPattern);
+- }
++ // Paper start - switch to Holder
++ TrimMaterial trimMaterial = CraftTrimMaterial.objectToBukkit(materialKeyString);
++ TrimPattern trimPattern = CraftTrimPattern.objectToBukkit(patternKeyString);
++ if (trimMaterial != null && trimPattern != null) {
++ this.trim = new ArmorTrim(trimMaterial, trimPattern);
+ }
++ // Paper end - switch to Holder
+ }
+ }
+ }
+@@ -133,9 +129,9 @@ public class CraftMetaArmor extends CraftMetaItem implements ArmorMeta {
+ super.serialize(builder);
+
+ if (this.hasTrim()) {
+- Map<String, String> trimData = new HashMap<>();
+- trimData.put(CraftMetaArmor.TRIM_MATERIAL.BUKKIT, this.trim.getMaterial().getKey().toString());
+- trimData.put(CraftMetaArmor.TRIM_PATTERN.BUKKIT, this.trim.getPattern().getKey().toString());
++ Map<String, Object> trimData = new HashMap<>(); // Paper - switch to Holder
++ trimData.put(CraftMetaArmor.TRIM_MATERIAL.BUKKIT, CraftTrimMaterial.bukkitToObject(this.trim.getMaterial())); // Paper - switch to Holder
++ trimData.put(CraftMetaArmor.TRIM_PATTERN.BUKKIT, CraftTrimPattern.bukkitToObject(this.trim.getPattern())); // Paper - switch to Holder
+ builder.put(CraftMetaArmor.TRIM.BUKKIT, trimData);
+ }
+
+diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java
+index 8423c6b67a83d99ef4356674f64d6e52fda3d36f..e6c4a08c9199c7f45effc33e818ac3d9023ab7bc 100644
+--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java
++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java
+@@ -37,7 +37,7 @@ public class CraftMetaMusicInstrument extends CraftMetaItem implements MusicInst
+ CraftMetaMusicInstrument(Map<String, Object> map) {
+ super(map);
+
+- String instrumentString = SerializableMeta.getString(map, CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT.BUKKIT, true);
++ Object instrumentString = SerializableMeta.getObject(Object.class, map, CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT.BUKKIT, true); // Paper - switch to Holder
+ if (instrumentString != null) {
+ this.instrument = CraftMusicInstrument.stringToBukkit(instrumentString);
+ }
+diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimMaterial.java b/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimMaterial.java
+index 38578ef887227ecc8e8bba281eae17a849b4fbe6..afee459c4d2d0945bdc99c2ab46f9dcf6dac8798 100644
+--- a/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimMaterial.java
++++ b/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimMaterial.java
+@@ -11,14 +11,14 @@ import org.bukkit.craftbukkit.util.Handleable;
+ import org.bukkit.inventory.meta.trim.TrimMaterial;
+ import org.jetbrains.annotations.NotNull;
+
+-public class CraftTrimMaterial implements TrimMaterial, Handleable<net.minecraft.world.item.equipment.trim.TrimMaterial> {
++public class CraftTrimMaterial implements TrimMaterial, io.papermc.paper.util.Holderable<net.minecraft.world.item.equipment.trim.TrimMaterial> { // Paper - switch to Holder
+
+ public static TrimMaterial minecraftToBukkit(net.minecraft.world.item.equipment.trim.TrimMaterial minecraft) {
+ return CraftRegistry.minecraftToBukkit(minecraft, Registries.TRIM_MATERIAL, Registry.TRIM_MATERIAL);
+ }
+
+ public static TrimMaterial minecraftHolderToBukkit(Holder<net.minecraft.world.item.equipment.trim.TrimMaterial> minecraft) {
+- return CraftTrimMaterial.minecraftToBukkit(minecraft.value());
++ return CraftRegistry.minecraftHolderToBukkit(minecraft, Registry.TRIM_MATERIAL); // Paper - switch to Holder
+ }
+
+ public static net.minecraft.world.item.equipment.trim.TrimMaterial bukkitToMinecraft(TrimMaterial bukkit) {
+@@ -26,29 +26,52 @@ public class CraftTrimMaterial implements TrimMaterial, Handleable<net.minecraft
+ }
+
+ public static Holder<net.minecraft.world.item.equipment.trim.TrimMaterial> bukkitToMinecraftHolder(TrimMaterial bukkit) {
++ return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.TRIM_MATERIAL); // Paper - switch to Holder
++ }
++
++ private final NamespacedKey key;
++ private final net.minecraft.world.item.equipment.trim.TrimMaterial handle;
++
++ // Paper start - switch to Holder
++ private final Holder<net.minecraft.world.item.equipment.trim.TrimMaterial> holder;
++
++ public static Object bukkitToObject(TrimMaterial bukkit) {
+ Preconditions.checkArgument(bukkit != null);
+
+- net.minecraft.core.Registry<net.minecraft.world.item.equipment.trim.TrimMaterial> registry = CraftRegistry.getMinecraftRegistry(Registries.TRIM_MATERIAL);
++ return ((CraftTrimMaterial) bukkit).toBukkitSerializationObject(net.minecraft.world.item.equipment.trim.TrimMaterial.CODEC); // Paper - switch to Holder
++ }
+
+- if (registry.wrapAsHolder(CraftTrimMaterial.bukkitToMinecraft(bukkit)) instanceof Holder.Reference<net.minecraft.world.item.equipment.trim.TrimMaterial> holder) {
+- return holder;
+- }
++ public static TrimMaterial objectToBukkit(Object object) {
++ Preconditions.checkArgument(object != null);
+
+- throw new IllegalArgumentException("No Reference holder found for " + bukkit
+- + ", this can happen if a plugin creates its own trim material without properly registering it.");
++ return io.papermc.paper.util.Holderable.fromBukkitSerializationObject(object, net.minecraft.world.item.equipment.trim.TrimMaterial.CODEC, Registry.TRIM_MATERIAL); // Paper - switch to Holder
+ }
+
+- private final NamespacedKey key;
+- private final net.minecraft.world.item.equipment.trim.TrimMaterial handle;
++ @Override
++ public boolean equals(final Object o) {
++ return this.implEquals(o);
++ }
++
++ @Override
++ public int hashCode() {
++ return this.implHashCode();
++ }
++
++ @Override
++ public String toString() {
++ return this.implToString();
++ }
+
+- public CraftTrimMaterial(NamespacedKey key, net.minecraft.world.item.equipment.trim.TrimMaterial handle) {
+- this.key = key;
+- this.handle = handle;
++ public CraftTrimMaterial(final Holder<net.minecraft.world.item.equipment.trim.TrimMaterial> holder) {
++ this.key = holder.unwrapKey().map(io.papermc.paper.util.MCUtil::fromResourceKey).orElse(null);
++ this.handle = holder.value();
++ this.holder = holder;
++ // Paper end - switch to Holder
+ }
+
+ @Override
+- public net.minecraft.world.item.equipment.trim.TrimMaterial getHandle() {
+- return this.handle;
++ public Holder<net.minecraft.world.item.equipment.trim.TrimMaterial> getHolder() { // Paper - switch to Holder
++ return this.holder; // Paper - switch to Holder
+ }
+
+ @Override
+diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimPattern.java b/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimPattern.java
+index 36df80a8be8a2485823f699e45c99674dbe71507..da951bd7e470d8b2bc69eea9b66815fa4fa445aa 100644
+--- a/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimPattern.java
++++ b/src/main/java/org/bukkit/craftbukkit/inventory/trim/CraftTrimPattern.java
+@@ -11,14 +11,14 @@ import org.bukkit.craftbukkit.util.Handleable;
+ import org.bukkit.inventory.meta.trim.TrimPattern;
+ import org.jetbrains.annotations.NotNull;
+
+-public class CraftTrimPattern implements TrimPattern, Handleable<net.minecraft.world.item.equipment.trim.TrimPattern> {
++public class CraftTrimPattern implements TrimPattern, io.papermc.paper.util.Holderable<net.minecraft.world.item.equipment.trim.TrimPattern> { // Paper - switch to Holder
+
+ public static TrimPattern minecraftToBukkit(net.minecraft.world.item.equipment.trim.TrimPattern minecraft) {
+ return CraftRegistry.minecraftToBukkit(minecraft, Registries.TRIM_PATTERN, Registry.TRIM_PATTERN);
+ }
+
+ public static TrimPattern minecraftHolderToBukkit(Holder<net.minecraft.world.item.equipment.trim.TrimPattern> minecraft) {
+- return CraftTrimPattern.minecraftToBukkit(minecraft.value());
++ return CraftRegistry.minecraftHolderToBukkit(minecraft, Registry.TRIM_PATTERN); // Paper - switch to Holder
+ }
+
+ public static net.minecraft.world.item.equipment.trim.TrimPattern bukkitToMinecraft(TrimPattern bukkit) {
+@@ -26,29 +26,52 @@ public class CraftTrimPattern implements TrimPattern, Handleable<net.minecraft.w
+ }
+
+ public static Holder<net.minecraft.world.item.equipment.trim.TrimPattern> bukkitToMinecraftHolder(TrimPattern bukkit) {
++ return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.TRIM_PATTERN); // Paper - switch to Holder
++ }
++
++ private final NamespacedKey key;
++ private final net.minecraft.world.item.equipment.trim.TrimPattern handle;
++
++ // Paper start - switch to Holder
++ private final Holder<net.minecraft.world.item.equipment.trim.TrimPattern> holder; // Paper - switch to Holder
++
++ public static Object bukkitToObject(TrimPattern bukkit) {
+ Preconditions.checkArgument(bukkit != null);
+
+- net.minecraft.core.Registry<net.minecraft.world.item.equipment.trim.TrimPattern> registry = CraftRegistry.getMinecraftRegistry(Registries.TRIM_PATTERN);
++ return ((CraftTrimPattern) bukkit).toBukkitSerializationObject(net.minecraft.world.item.equipment.trim.TrimPattern.CODEC); // Paper - switch to Holder
++ }
+
+- if (registry.wrapAsHolder(CraftTrimPattern.bukkitToMinecraft(bukkit)) instanceof Holder.Reference<net.minecraft.world.item.equipment.trim.TrimPattern> holder) {
+- return holder;
+- }
++ public static TrimPattern objectToBukkit(Object object) {
++ Preconditions.checkArgument(object != null);
+
+- throw new IllegalArgumentException("No Reference holder found for " + bukkit
+- + ", this can happen if a plugin creates its own trim pattern without properly registering it.");
++ return io.papermc.paper.util.Holderable.fromBukkitSerializationObject(object, net.minecraft.world.item.equipment.trim.TrimPattern.CODEC, Registry.TRIM_PATTERN); // Paper - switch to Holder
+ }
+
+- private final NamespacedKey key;
+- private final net.minecraft.world.item.equipment.trim.TrimPattern handle;
++ @Override
++ public boolean equals(final Object o) {
++ return this.implEquals(o);
++ }
++
++ @Override
++ public int hashCode() {
++ return this.implHashCode();
++ }
++
++ @Override
++ public String toString() {
++ return this.implToString();
++ }
+
+- public CraftTrimPattern(NamespacedKey key, net.minecraft.world.item.equipment.trim.TrimPattern handle) {
+- this.key = key;
+- this.handle = handle;
++ public CraftTrimPattern(Holder<net.minecraft.world.item.equipment.trim.TrimPattern> handle) {
++ this.key = handle.unwrapKey().map(io.papermc.paper.util.MCUtil::fromResourceKey).orElse(null);
++ this.handle = handle.value();
++ this.holder = handle;
++ // Paper end - switch to Holder
+ }
+
+ @Override
+- public net.minecraft.world.item.equipment.trim.TrimPattern getHandle() {
+- return this.handle;
++ public Holder<net.minecraft.world.item.equipment.trim.TrimPattern> getHolder() { // Paper - switch to Holder
++ return this.holder; // Paper - switch to Holder
+ }
+
+ @Override
+diff --git a/src/test/java/org/bukkit/registry/RegistryConversionTest.java b/src/test/java/org/bukkit/registry/RegistryConversionTest.java
+index 01e351f4e292efe78fc1a1db0f31b2c0a313b101..092b88e0ac3ba37322fbe86bab98dc6f91a9c866 100644
+--- a/src/test/java/org/bukkit/registry/RegistryConversionTest.java
++++ b/src/test/java/org/bukkit/registry/RegistryConversionTest.java
+@@ -269,6 +269,7 @@ public class RegistryConversionTest {
+ Class<? extends Keyed> craftClazz, Class<?> minecraftClazz) throws IllegalAccessException {
+ this.checkValidMinecraftToBukkit(clazz);
+
++ if (type == io.papermc.paper.registry.RegistryKey.TRIM_MATERIAL || type == io.papermc.paper.registry.RegistryKey.TRIM_PATTERN || type == io.papermc.paper.registry.RegistryKey.INSTRUMENT) return; // Paper - manually skip for now
+ try {
+
+ Object minecraft = mock(minecraftClazz);