From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jake Potrebic <jake.m.potrebic@gmail.com> Date: Mon, 27 Feb 2023 18:28:39 -0800 Subject: [PATCH] Registry Modification API == AT == public net.minecraft.core.MappedRegistry validateWrite(Lnet/minecraft/resources/ResourceKey;)V public net.minecraft.resources.RegistryOps lookupProvider public net.minecraft.resources.RegistryOps$HolderLookupAdapter diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java index ea99f30a311512e4450c38e9e1bb7df0b758a93c..875b3e761d83ab3ddfe05fdf978136c7d683bb0c 100644 --- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java +++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java @@ -3,6 +3,7 @@ package io.papermc.paper.registry; import com.google.common.base.Preconditions; import io.papermc.paper.adventure.PaperAdventure; import io.papermc.paper.registry.entry.RegistryEntry; +import io.papermc.paper.registry.tag.TagKey; import java.util.Collections; import java.util.IdentityHashMap; import java.util.List; @@ -148,6 +149,15 @@ public final class PaperRegistries { return ResourceKey.create((ResourceKey<? extends Registry<M>>) PaperRegistries.registryToNms(typedKey.registryKey()), PaperAdventure.asVanilla(typedKey.key())); } + public static <M, T> TagKey<T> fromNms(final net.minecraft.tags.TagKey<M> tagKey) { + return TagKey.create(registryFromNms(tagKey.registry()), CraftNamespacedKey.fromMinecraft(tagKey.location())); + } + + @SuppressWarnings({"unchecked", "RedundantCast"}) + public static <M, T> net.minecraft.tags.TagKey<M> toNms(final TagKey<T> tagKey) { + return net.minecraft.tags.TagKey.create((ResourceKey<? extends Registry<M>>) registryToNms(tagKey.registryKey()), PaperAdventure.asVanilla(tagKey.key())); + } + private PaperRegistries() { } } diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java index 4bf7915867dbe762ef0b070d67d5f7b7d1ee4f03..ed071ed34e16812f133102b0d66a5201a94639f2 100644 --- a/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java +++ b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java @@ -78,6 +78,14 @@ public class PaperRegistryAccess implements RegistryAccess { return possiblyUnwrap(registryHolder.get()); } + public <M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> WritableCraftRegistry<M, T, B> getWritableRegistry(final RegistryKey<T> key) { + final Registry<T> registry = this.getRegistry(key); + if (registry instanceof WritableCraftRegistry<?, T, ?>) { + return (WritableCraftRegistry<M, T, B>) registry; + } + throw new IllegalArgumentException(key + " does not point to a writable registry"); + } + private static <T extends Keyed> Registry<T> possiblyUnwrap(final Registry<T> registry) { if (registry instanceof final DelayedRegistry<T, ?> delayedRegistry) { // if not coming from legacy, unwrap the delayed registry return delayedRegistry.delegate(); diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistryBuilder.java b/src/main/java/io/papermc/paper/registry/PaperRegistryBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..6a60d7b7edeedb150afea41d58855b2d8521f297 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/PaperRegistryBuilder.java @@ -0,0 +1,25 @@ +package io.papermc.paper.registry; + +import io.papermc.paper.registry.data.util.Conversions; +import org.jspecify.annotations.Nullable; + +public interface PaperRegistryBuilder<M, T> extends RegistryBuilder<T> { + + M build(); + + @FunctionalInterface + interface Filler<M, T, B extends PaperRegistryBuilder<M, T>> { + + B fill(Conversions conversions, @Nullable M nms); + + default Factory<M, T, B> asFactory() { + return (lookup) -> this.fill(lookup, null); + } + } + + @FunctionalInterface + interface Factory<M, T, B extends PaperRegistryBuilder<M, T>> { + + B create(Conversions conversions); + } +} diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistryListenerManager.java b/src/main/java/io/papermc/paper/registry/PaperRegistryListenerManager.java new file mode 100644 index 0000000000000000000000000000000000000000..4f98c15d40e95031326d0524c51f2864ce52223e --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/PaperRegistryListenerManager.java @@ -0,0 +1,183 @@ +package io.papermc.paper.registry; + +import com.google.common.base.Preconditions; +import com.mojang.serialization.Lifecycle; +import io.papermc.paper.plugin.bootstrap.BootstrapContext; +import io.papermc.paper.plugin.entrypoint.Entrypoint; +import io.papermc.paper.plugin.entrypoint.LaunchEntryPointHandler; +import io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner; +import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; +import io.papermc.paper.registry.data.util.Conversions; +import io.papermc.paper.registry.entry.RegistryEntry; +import io.papermc.paper.registry.entry.RegistryEntryInfo; +import io.papermc.paper.registry.event.RegistryEntryAddEventImpl; +import io.papermc.paper.registry.event.RegistryEventMap; +import io.papermc.paper.registry.event.RegistryEventProvider; +import io.papermc.paper.registry.event.RegistryFreezeEvent; +import io.papermc.paper.registry.event.RegistryFreezeEventImpl; +import io.papermc.paper.registry.event.type.RegistryEntryAddEventType; +import io.papermc.paper.registry.event.type.RegistryEntryAddEventTypeImpl; +import io.papermc.paper.registry.event.type.RegistryLifecycleEventType; +import java.util.Optional; +import net.kyori.adventure.key.Key; +import net.minecraft.core.Holder; +import net.minecraft.core.MappedRegistry; +import net.minecraft.core.RegistrationInfo; +import net.minecraft.core.Registry; +import net.minecraft.core.WritableRegistry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import org.intellij.lang.annotations.Subst; +import org.jspecify.annotations.Nullable; + +public class PaperRegistryListenerManager { + + public static final PaperRegistryListenerManager INSTANCE = new PaperRegistryListenerManager(); + + public final RegistryEventMap valueAddEventTypes = new RegistryEventMap("value add"); + public final RegistryEventMap freezeEventTypes = new RegistryEventMap("freeze"); + + private PaperRegistryListenerManager() { + } + + /** + * For {@link Registry#register(Registry, String, Object)} + */ + public <M> M registerWithListeners(final Registry<M> registry, final String id, final M nms) { + return this.registerWithListeners(registry, ResourceLocation.withDefaultNamespace(id), nms); + } + + /** + * For {@link Registry#register(Registry, ResourceLocation, Object)} + */ + public <M> M registerWithListeners(final Registry<M> registry, final ResourceLocation loc, final M nms) { + return this.registerWithListeners(registry, ResourceKey.create(registry.key(), loc), nms); + } + + /** + * For {@link Registry#register(Registry, ResourceKey, Object)} + */ + public <M> M registerWithListeners(final Registry<M> registry, final ResourceKey<M> key, final M nms) { + return this.registerWithListeners(registry, key, nms, RegistrationInfo.BUILT_IN, PaperRegistryListenerManager::registerWithInstance, BuiltInRegistries.BUILT_IN_CONVERSIONS); + } + + /** + * For {@link Registry#registerForHolder(Registry, ResourceLocation, Object)} + */ + public <M> Holder.Reference<M> registerForHolderWithListeners(final Registry<M> registry, final ResourceLocation loc, final M nms) { + return this.registerForHolderWithListeners(registry, ResourceKey.create(registry.key(), loc), nms); + } + + /** + * For {@link Registry#registerForHolder(Registry, ResourceKey, Object)} + */ + public <M> Holder.Reference<M> registerForHolderWithListeners(final Registry<M> registry, final ResourceKey<M> key, final M nms) { + return this.registerWithListeners(registry, key, nms, RegistrationInfo.BUILT_IN, WritableRegistry::register, BuiltInRegistries.BUILT_IN_CONVERSIONS); + } + + public <M> void registerWithListeners( + final Registry<M> registry, + final ResourceKey<M> key, + final M nms, + final RegistrationInfo registrationInfo, + final Conversions conversions + ) { + this.registerWithListeners(registry, key, nms, registrationInfo, WritableRegistry::register, conversions); + } + + // TODO remove Keyed + public <M, T extends org.bukkit.Keyed, B extends PaperRegistryBuilder<M, T>, R> R registerWithListeners( + final Registry<M> registry, + final ResourceKey<M> key, + final M nms, + final RegistrationInfo registrationInfo, + final RegisterMethod<M, R> registerMethod, + final Conversions conversions + ) { + Preconditions.checkState(LaunchEntryPointHandler.INSTANCE.hasEntered(Entrypoint.BOOTSTRAPPER), registry.key() + " tried to run modification listeners before bootstrappers have been called"); // verify that bootstrappers have been called + final RegistryEntryInfo<M, T> entry = PaperRegistries.getEntry(registry.key()); + if (!RegistryEntry.Modifiable.isModifiable(entry) || !this.valueAddEventTypes.hasHandlers(entry.apiKey())) { + return registerMethod.register((WritableRegistry<M>) registry, key, nms, registrationInfo); + } + final RegistryEntry.Modifiable<M, T, B> modifiableEntry = RegistryEntry.Modifiable.asModifiable(entry); + @SuppressWarnings("PatternValidation") final TypedKey<T> typedKey = TypedKey.create(entry.apiKey(), Key.key(key.location().getNamespace(), key.location().getPath())); + final B builder = modifiableEntry.fillBuilder(conversions, nms); + return this.registerWithListeners(registry, modifiableEntry, key, nms, builder, registrationInfo, registerMethod, conversions); + } + + <M, T extends org.bukkit.Keyed, B extends PaperRegistryBuilder<M, T>> void registerWithListeners( // TODO remove Keyed + final WritableRegistry<M> registry, + final RegistryEntryInfo<M, T> entry, + final ResourceKey<M> key, + final B builder, + final RegistrationInfo registrationInfo, + final Conversions conversions + ) { + if (!RegistryEntry.Modifiable.isModifiable(entry) || !this.valueAddEventTypes.hasHandlers(entry.apiKey())) { + registry.register(key, builder.build(), registrationInfo); + return; + } + this.registerWithListeners(registry, RegistryEntry.Modifiable.asModifiable(entry), key, null, builder, registrationInfo, WritableRegistry::register, conversions); + } + + public <M, T extends org.bukkit.Keyed, B extends PaperRegistryBuilder<M, T>, R> R registerWithListeners( // TODO remove Keyed + final Registry<M> registry, + final RegistryEntry.Modifiable<M, T, B> entry, + final ResourceKey<M> key, + final @Nullable M oldNms, + final B builder, + RegistrationInfo registrationInfo, + final RegisterMethod<M, R> registerMethod, + final Conversions conversions + ) { + @Subst("namespace:key") final ResourceLocation beingAdded = key.location(); + @SuppressWarnings("PatternValidation") final TypedKey<T> typedKey = TypedKey.create(entry.apiKey(), Key.key(beingAdded.getNamespace(), beingAdded.getPath())); + final RegistryEntryAddEventImpl<T, B> event = entry.createEntryAddEvent(typedKey, builder, conversions); + LifecycleEventRunner.INSTANCE.callEvent(this.valueAddEventTypes.getEventType(entry.apiKey()), event); + if (oldNms != null) { + ((MappedRegistry<M>) registry).clearIntrusiveHolder(oldNms); + } + final M newNms = event.builder().build(); + if (oldNms != null && !newNms.equals(oldNms)) { + registrationInfo = new RegistrationInfo(Optional.empty(), Lifecycle.experimental()); + } + return registerMethod.register((WritableRegistry<M>) registry, key, newNms, registrationInfo); + } + + private static <M> M registerWithInstance(final WritableRegistry<M> writableRegistry, final ResourceKey<M> key, final M value, final RegistrationInfo registrationInfo) { + writableRegistry.register(key, value, registrationInfo); + return value; + } + + @FunctionalInterface + public interface RegisterMethod<M, R> { + + R register(WritableRegistry<M> writableRegistry, ResourceKey<M> key, M value, RegistrationInfo registrationInfo); + } + + public <M, T extends org.bukkit.Keyed, B extends PaperRegistryBuilder<M, T>> void runFreezeListeners(final ResourceKey<? extends Registry<M>> resourceKey, final Conversions conversions) { + final RegistryEntryInfo<M, T> entry = PaperRegistries.getEntry(resourceKey); + if (!RegistryEntry.Addable.isAddable(entry) || !this.freezeEventTypes.hasHandlers(entry.apiKey())) { + return; + } + final RegistryEntry.Addable<M, T, B> writableEntry = RegistryEntry.Addable.asAddable(entry); + final WritableCraftRegistry<M, T, B> writableRegistry = PaperRegistryAccess.instance().getWritableRegistry(entry.apiKey()); + final RegistryFreezeEventImpl<T, B> event = writableEntry.createFreezeEvent(writableRegistry, conversions); + LifecycleEventRunner.INSTANCE.callEvent(this.freezeEventTypes.getEventType(entry.apiKey()), event); + } + + public <T, B extends RegistryBuilder<T>> RegistryEntryAddEventType<T, B> getRegistryValueAddEventType(final RegistryEventProvider<T, B> type) { + if (!RegistryEntry.Modifiable.isModifiable(PaperRegistries.getEntry(type.registryKey()))) { + throw new IllegalArgumentException(type.registryKey() + " does not support RegistryEntryAddEvent"); + } + return this.valueAddEventTypes.getOrCreate(type.registryKey(), RegistryEntryAddEventTypeImpl::new); + } + + public <T, B extends RegistryBuilder<T>> LifecycleEventType.Prioritizable<BootstrapContext, RegistryFreezeEvent<T, B>> getRegistryFreezeEventType(final RegistryEventProvider<T, B> type) { + if (!RegistryEntry.Addable.isAddable(PaperRegistries.getEntry(type.registryKey()))) { + throw new IllegalArgumentException(type.registryKey() + " does not support RegistryFreezeEvent"); + } + return this.freezeEventTypes.getOrCreate(type.registryKey(), RegistryLifecycleEventType::new); + } +} diff --git a/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java b/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java index 6d134ace042758da722960cbcb48e52508dafd61..cc39bc68d29055ef6429f08f975412bd9fe68dbc 100644 --- a/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java +++ b/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java @@ -1,6 +1,10 @@ package io.papermc.paper.registry; +import io.papermc.paper.registry.set.NamedRegistryKeySetImpl; +import io.papermc.paper.registry.tag.Tag; +import io.papermc.paper.registry.tag.TagKey; import java.util.function.Predicate; +import net.minecraft.core.HolderSet; import net.minecraft.core.registries.BuiltInRegistries; import org.bukkit.Keyed; import org.bukkit.Particle; @@ -35,4 +39,16 @@ public class PaperSimpleRegistry<T extends Enum<T> & Keyed, M> extends Registry. super(type, predicate); this.nmsRegistry = nmsRegistry; } + + @Override + public boolean hasTag(final TagKey<T> key) { + final net.minecraft.tags.TagKey<M> nmsKey = PaperRegistries.toNms(key); + return this.nmsRegistry.get(nmsKey).isPresent(); + } + + @Override + public Tag<T> getTag(final TagKey<T> key) { + final HolderSet.Named<M> namedHolderSet = this.nmsRegistry.get(PaperRegistries.toNms(key)).orElseThrow(); + return new NamedRegistryKeySetImpl<>(key, namedHolderSet); + } } diff --git a/src/main/java/io/papermc/paper/registry/WritableCraftRegistry.java b/src/main/java/io/papermc/paper/registry/WritableCraftRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..f201f142505db8f5a87c20346f6e2998263372fd --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/WritableCraftRegistry.java @@ -0,0 +1,77 @@ +package io.papermc.paper.registry; + +import com.mojang.serialization.Lifecycle; +import io.papermc.paper.registry.data.util.Conversions; +import io.papermc.paper.registry.entry.RegistryEntry; +import io.papermc.paper.registry.entry.RegistryTypeMapper; +import io.papermc.paper.registry.event.WritableRegistry; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import net.minecraft.core.MappedRegistry; +import net.minecraft.core.RegistrationInfo; +import net.minecraft.resources.ResourceKey; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.craftbukkit.CraftRegistry; +import org.bukkit.craftbukkit.util.ApiVersion; + +public class WritableCraftRegistry<M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> extends CraftRegistry<T, M> { + + private static final RegistrationInfo FROM_PLUGIN = new RegistrationInfo(Optional.empty(), Lifecycle.experimental()); + + private final RegistryEntry.BuilderHolder<M, T, B> entry; + private final MappedRegistry<M> registry; + private final PaperRegistryBuilder.Factory<M, T, ? extends B> builderFactory; + + public WritableCraftRegistry( + final RegistryEntry.BuilderHolder<M, T, B> entry, + final Class<?> classToPreload, + final MappedRegistry<M> registry, + final BiFunction<NamespacedKey, ApiVersion, NamespacedKey> serializationUpdater, + final PaperRegistryBuilder.Factory<M, T, ? extends B> builderFactory, + final RegistryTypeMapper<M, T> minecraftToBukkit + ) { + super(classToPreload, registry, minecraftToBukkit, serializationUpdater); + this.entry = entry; + this.registry = registry; + this.builderFactory = builderFactory; + } + + public void register(final TypedKey<T> key, final Consumer<? super B> value, final Conversions conversions) { + final ResourceKey<M> resourceKey = PaperRegistries.toNms(key); + this.registry.validateWrite(resourceKey); + final B builder = this.newBuilder(conversions); + value.accept(builder); + PaperRegistryListenerManager.INSTANCE.registerWithListeners( + this.registry, + RegistryEntry.Modifiable.asModifiable(this.entry), + resourceKey, + builder, + FROM_PLUGIN, + conversions + ); + } + + public WritableRegistry<T, B> createApiWritableRegistry(final Conversions conversions) { + return new ApiWritableRegistry(conversions); + } + + protected B newBuilder(final Conversions conversions) { + return this.builderFactory.create(conversions); + } + + public class ApiWritableRegistry implements WritableRegistry<T, B> { + + private final Conversions conversions; + + public ApiWritableRegistry(final Conversions conversions) { + this.conversions = conversions; + } + + @Override + public void register(final TypedKey<T> key, final Consumer<? super B> value) { + WritableCraftRegistry.this.register(key, value, this.conversions); + } + } +} diff --git a/src/main/java/io/papermc/paper/registry/data/util/Conversions.java b/src/main/java/io/papermc/paper/registry/data/util/Conversions.java new file mode 100644 index 0000000000000000000000000000000000000000..b1710da835cee3333bfb1c238b37ec0c4d16ba09 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/data/util/Conversions.java @@ -0,0 +1,58 @@ +package io.papermc.paper.registry.data.util; + +import com.google.common.base.Preconditions; +import com.mojang.serialization.JavaOps; +import io.papermc.paper.adventure.WrapperAwareSerializer; +import java.util.Optional; +import net.kyori.adventure.text.Component; +import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; +import net.minecraft.resources.RegistryOps; +import net.minecraft.resources.ResourceKey; +import org.bukkit.craftbukkit.CraftRegistry; +import org.jetbrains.annotations.Contract; +import org.jspecify.annotations.Nullable; + +public class Conversions { + + private static @Nullable Conversions globalInstance; + public static Conversions global() { + if (globalInstance == null) { + final RegistryAccess globalAccess = CraftRegistry.getMinecraftRegistry(); + Preconditions.checkState(globalAccess != null, "Global registry access is not available"); + globalInstance = new Conversions(new RegistryOps.RegistryInfoLookup() { + @Override + public <T> Optional<RegistryOps.RegistryInfo<T>> lookup(final ResourceKey<? extends Registry<? extends T>> registryRef) { + final Registry<T> registry = globalAccess.lookupOrThrow(registryRef); + return Optional.of( + new RegistryOps.RegistryInfo<>(registry, registry, registry.registryLifecycle()) + ); + } + }); + } + return globalInstance; + } + + + private final RegistryOps.RegistryInfoLookup lookup; + private final WrapperAwareSerializer serializer; + + public Conversions(final RegistryOps.RegistryInfoLookup lookup) { + this.lookup = lookup; + this.serializer = new WrapperAwareSerializer(() -> RegistryOps.create(JavaOps.INSTANCE, lookup)); + } + + public RegistryOps.RegistryInfoLookup lookup() { + return this.lookup; + } + + @Contract("null -> null; !null -> !null") + public net.minecraft.network.chat.@Nullable Component asVanilla(final @Nullable Component adventure) { + if (adventure == null) return null; + return this.serializer.serialize(adventure); + } + + public Component asAdventure(final net.minecraft.network.chat.@Nullable Component vanilla) { + return vanilla == null ? Component.empty() : this.serializer.deserialize(vanilla); + } +} diff --git a/src/main/java/io/papermc/paper/registry/data/util/package-info.java b/src/main/java/io/papermc/paper/registry/data/util/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..5b88be976c7773459ce1b6daf58d7ea7c806f21b --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/data/util/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.papermc.paper.registry.data.util; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/io/papermc/paper/registry/entry/AddableRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/AddableRegistryEntry.java new file mode 100644 index 0000000000000000000000000000000000000000..c44edcf13e853b78c590393a93b88f7f157d4c3d --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/entry/AddableRegistryEntry.java @@ -0,0 +1,41 @@ +package io.papermc.paper.registry.entry; + +import io.papermc.paper.registry.PaperRegistryBuilder; +import io.papermc.paper.registry.RegistryHolder; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.WritableCraftRegistry; +import io.papermc.paper.registry.data.util.Conversions; +import net.minecraft.core.MappedRegistry; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import org.bukkit.Keyed; + +public class AddableRegistryEntry<M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> extends CraftRegistryEntry<M, T> implements RegistryEntry.Addable<M, T, B> { + + private final PaperRegistryBuilder.Filler<M, T, B> builderFiller; + + protected AddableRegistryEntry( + final ResourceKey<? extends Registry<M>> mcKey, + final RegistryKey<T> apiKey, + final Class<?> classToPreload, + final RegistryTypeMapper<M, T> minecraftToBukkit, + final PaperRegistryBuilder.Filler<M, T, B> builderFiller + ) { + super(mcKey, apiKey, classToPreload, minecraftToBukkit); + this.builderFiller = builderFiller; + } + + private WritableCraftRegistry<M, T, B> createRegistry(final Registry<M> registry) { + return new WritableCraftRegistry<>(this, this.classToPreload, (MappedRegistry<M>) registry, this.updater, this.builderFiller.asFactory(), this.minecraftToBukkit); + } + + @Override + public RegistryHolder<T> createRegistryHolder(final Registry<M> nmsRegistry) { + return new RegistryHolder.Memoized<>(() -> this.createRegistry(nmsRegistry)); + } + + @Override + public B fillBuilder(final Conversions conversions, final M nms) { + return this.builderFiller.fill(conversions, nms); + } +} diff --git a/src/main/java/io/papermc/paper/registry/entry/ModifiableRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/ModifiableRegistryEntry.java new file mode 100644 index 0000000000000000000000000000000000000000..4254335e55010086d66a6c7a5afca0f503ebef5b --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/entry/ModifiableRegistryEntry.java @@ -0,0 +1,29 @@ +package io.papermc.paper.registry.entry; + +import io.papermc.paper.registry.PaperRegistryBuilder; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.data.util.Conversions; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import org.bukkit.Keyed; + +public class ModifiableRegistryEntry<M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> extends CraftRegistryEntry<M, T> implements RegistryEntry.Modifiable<M, T, B> { + + protected final PaperRegistryBuilder.Filler<M, T, B> builderFiller; + + protected ModifiableRegistryEntry( + final ResourceKey<? extends Registry<M>> mcKey, + final RegistryKey<T> apiKey, + final Class<?> toPreload, + final RegistryTypeMapper<M, T> minecraftToBukkit, + final PaperRegistryBuilder.Filler<M, T, B> builderFiller + ) { + super(mcKey, apiKey, toPreload, minecraftToBukkit); + this.builderFiller = builderFiller; + } + + @Override + public B fillBuilder(final Conversions conversions, final M nms) { + return this.builderFiller.fill(conversions, nms); + } +} diff --git a/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java index f0a81a8b88d31139390e952a0eb8a526e6851c5f..32089721edfd806d082bd267bba040e249dbf75b 100644 --- a/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java +++ b/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java @@ -1,13 +1,20 @@ package io.papermc.paper.registry.entry; +import io.papermc.paper.registry.PaperRegistryBuilder; import io.papermc.paper.registry.RegistryHolder; import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import io.papermc.paper.registry.WritableCraftRegistry; +import io.papermc.paper.registry.data.util.Conversions; +import io.papermc.paper.registry.event.RegistryEntryAddEventImpl; +import io.papermc.paper.registry.event.RegistryFreezeEventImpl; import io.papermc.paper.registry.legacy.DelayedRegistryEntry; import java.util.function.BiFunction; import net.minecraft.core.Registry; import org.bukkit.Keyed; import org.bukkit.NamespacedKey; import org.bukkit.craftbukkit.util.ApiVersion; +import org.jspecify.annotations.Nullable; public interface RegistryEntry<M, B extends Keyed> extends RegistryEntryInfo<M, B> { // TODO remove Keyed @@ -26,4 +33,63 @@ public interface RegistryEntry<M, B extends Keyed> extends RegistryEntryInfo<M, default RegistryEntry<M, B> delayed() { return new DelayedRegistryEntry<>(this); } + + interface BuilderHolder<M, T, B extends PaperRegistryBuilder<M, T>> extends RegistryEntryInfo<M, T> { + + B fillBuilder(Conversions conversions, M nms); + } + + /** + * Can mutate values being added to the registry + */ + interface Modifiable<M, T, B extends PaperRegistryBuilder<M, T>> extends BuilderHolder<M, T, B> { + + static boolean isModifiable(final @Nullable RegistryEntryInfo<?, ?> entry) { + return entry instanceof RegistryEntry.Modifiable<?, ?, ?> || (entry instanceof final DelayedRegistryEntry<?, ?> delayed && delayed.delegate() instanceof RegistryEntry.Modifiable<?, ?, ?>); + } + + static <M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> Modifiable<M, T, B> asModifiable(final RegistryEntryInfo<M, T> entry) { // TODO remove Keyed + return (Modifiable<M, T, B>) possiblyUnwrap(entry); + } + + default RegistryEntryAddEventImpl<T, B> createEntryAddEvent(final TypedKey<T> key, final B initialBuilder, final Conversions conversions) { + return new RegistryEntryAddEventImpl<>(key, initialBuilder, this.apiKey(), conversions); + } + } + + /** + * Can only add new values to the registry, not modify any values. + */ + interface Addable<M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> extends BuilderHolder<M, T, B> { // TODO remove Keyed + + default RegistryFreezeEventImpl<T, B> createFreezeEvent(final WritableCraftRegistry<M, T, B> writableRegistry, final Conversions conversions) { + return new RegistryFreezeEventImpl<>(this.apiKey(), writableRegistry.createApiWritableRegistry(conversions), conversions); + } + + static boolean isAddable(final @Nullable RegistryEntryInfo<?, ?> entry) { + return entry instanceof RegistryEntry.Addable<?, ?, ?> || (entry instanceof final DelayedRegistryEntry<?, ?> delayed && delayed.delegate() instanceof RegistryEntry.Addable<?, ?, ?>); + } + + static <M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> Addable<M, T, B> asAddable(final RegistryEntryInfo<M, T> entry) { + return (Addable<M, T, B>) possiblyUnwrap(entry); + } + } + + /** + * Can mutate values and add new values. + */ + interface Writable<M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> extends Modifiable<M, T, B>, Addable<M, T, B> { // TODO remove Keyed + + static boolean isWritable(final @Nullable RegistryEntryInfo<?, ?> entry) { + return entry instanceof RegistryEntry.Writable<?, ?, ?> || (entry instanceof final DelayedRegistryEntry<?, ?> delayed && delayed.delegate() instanceof RegistryEntry.Writable<?, ?, ?>); + } + + static <M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> Writable<M, T, B> asWritable(final RegistryEntryInfo<M, T> entry) { // TODO remove Keyed + return (Writable<M, T, B>) possiblyUnwrap(entry); + } + } + + private static <M, B extends Keyed> RegistryEntryInfo<M, B> possiblyUnwrap(final RegistryEntryInfo<M, B> entry) { + return entry instanceof final DelayedRegistryEntry<M, B> delayed ? delayed.delegate() : entry; + } } diff --git a/src/main/java/io/papermc/paper/registry/entry/RegistryEntryBuilder.java b/src/main/java/io/papermc/paper/registry/entry/RegistryEntryBuilder.java index 6d8f08d6113c82cbe4207d4b69fce32a68d79620..5352ec936c7bdd5ca74fca182eafb21e9d190d74 100644 --- a/src/main/java/io/papermc/paper/registry/entry/RegistryEntryBuilder.java +++ b/src/main/java/io/papermc/paper/registry/entry/RegistryEntryBuilder.java @@ -1,6 +1,7 @@ package io.papermc.paper.registry.entry; import com.mojang.datafixers.util.Either; +import io.papermc.paper.registry.PaperRegistryBuilder; import io.papermc.paper.registry.RegistryKey; import java.util.function.BiFunction; import java.util.function.Function; @@ -59,5 +60,17 @@ public class RegistryEntryBuilder<M, A extends Keyed> { // TODO remove Keyed public RegistryEntry<M, A> build() { return new CraftRegistryEntry<>(this.mcKey, this.apiKey, this.classToPreload, this.minecraftToBukkit); } + + public <B extends PaperRegistryBuilder<M, A>> RegistryEntry<M, A> modifiable(final PaperRegistryBuilder.Filler<M, A, B> filler) { + return new ModifiableRegistryEntry<>(this.mcKey, this.apiKey, this.classToPreload, this.minecraftToBukkit, filler); + } + + public <B extends PaperRegistryBuilder<M, A>> RegistryEntry<M, A> addable(final PaperRegistryBuilder.Filler<M, A, B> filler) { + return new AddableRegistryEntry<>(this.mcKey, this.apiKey, this.classToPreload, this.minecraftToBukkit, filler); + } + + public <B extends PaperRegistryBuilder<M, A>> RegistryEntry<M, A> writable(final PaperRegistryBuilder.Filler<M, A, B> filler) { + return new WritableRegistryEntry<>(this.mcKey, this.apiKey, this.classToPreload, this.minecraftToBukkit, filler); + } } } diff --git a/src/main/java/io/papermc/paper/registry/entry/WritableRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/WritableRegistryEntry.java new file mode 100644 index 0000000000000000000000000000000000000000..7ff5dbea3f5953196359223b129a1e968bfb28c3 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/entry/WritableRegistryEntry.java @@ -0,0 +1,25 @@ +package io.papermc.paper.registry.entry; + +import com.mojang.datafixers.util.Either; +import io.papermc.paper.registry.PaperRegistryBuilder; +import io.papermc.paper.registry.RegistryKey; +import java.util.function.BiFunction; +import java.util.function.Function; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; + +public class WritableRegistryEntry<M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> extends AddableRegistryEntry<M, T, B> implements RegistryEntry.Writable<M, T, B> { // TODO remove Keyed + + protected WritableRegistryEntry( + final ResourceKey<? extends Registry<M>> mcKey, + final RegistryKey<T> apiKey, + final Class<?> classToPreload, + final RegistryTypeMapper<M, T> minecraftToBukkit, + final PaperRegistryBuilder.Filler<M, T, B> builderFiller + ) { + super(mcKey, apiKey, classToPreload, minecraftToBukkit, builderFiller); + } +} diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEventImpl.java b/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEventImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..332829c65ef45966dffcf5f1c59422a801179759 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEventImpl.java @@ -0,0 +1,29 @@ +package io.papermc.paper.registry.event; + +import io.papermc.paper.plugin.lifecycle.event.PaperLifecycleEvent; +import io.papermc.paper.registry.PaperRegistries; +import io.papermc.paper.registry.RegistryBuilder; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import io.papermc.paper.registry.data.util.Conversions; +import io.papermc.paper.registry.set.NamedRegistryKeySetImpl; +import io.papermc.paper.registry.tag.Tag; +import io.papermc.paper.registry.tag.TagKey; +import net.minecraft.core.HolderSet; +import net.minecraft.resources.RegistryOps; +import org.bukkit.Keyed; + +public record RegistryEntryAddEventImpl<T, B extends RegistryBuilder<T>>( + TypedKey<T> key, + B builder, + RegistryKey<T> registryKey, + Conversions conversions +) implements RegistryEntryAddEvent<T, B>, PaperLifecycleEvent { + + @Override + public <V extends Keyed> Tag<V> getOrCreateTag(final TagKey<V> tagKey) { + final RegistryOps.RegistryInfo<Object> registryInfo = this.conversions.lookup().lookup(PaperRegistries.registryToNms(tagKey.registryKey())).orElseThrow(); + final HolderSet.Named<?> tagSet = registryInfo.getter().getOrThrow(PaperRegistries.toNms(tagKey)); + return new NamedRegistryKeySetImpl<>(tagKey, tagSet); + } +} diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventMap.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventMap.java new file mode 100644 index 0000000000000000000000000000000000000000..bfcd0884d778ca62817fb1d22f0f2ed1f2abe855 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventMap.java @@ -0,0 +1,45 @@ +package io.papermc.paper.registry.event; + +import io.papermc.paper.plugin.bootstrap.BootstrapContext; +import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; +import io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner; +import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType; +import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; +import io.papermc.paper.registry.RegistryKey; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.BiFunction; + +public final class RegistryEventMap { + + private final Map<RegistryKey<?>, LifecycleEventType<BootstrapContext, ? extends LifecycleEvent, ?>> eventTypes = new HashMap<>(); + private final String name; + + public RegistryEventMap(final String name) { + this.name = name; + } + + @SuppressWarnings("unchecked") + public <T, E extends LifecycleEvent, ET extends LifecycleEventType<BootstrapContext, E, ?>> ET getOrCreate(final RegistryKey<T> registryKey, final BiFunction<? super RegistryKey<T>, ? super String, ET> eventTypeCreator) { + final ET eventType; + if (this.eventTypes.containsKey(registryKey)) { + eventType = (ET) this.eventTypes.get(registryKey); + } else { + eventType = eventTypeCreator.apply(registryKey, this.name); + this.eventTypes.put(registryKey, eventType); + } + return eventType; + } + + @SuppressWarnings("unchecked") + public <T, E extends LifecycleEvent> LifecycleEventType<BootstrapContext, E, ?> getEventType(final RegistryKey<T> registryKey) { + return (LifecycleEventType<BootstrapContext, E, ?>) Objects.requireNonNull(this.eventTypes.get(registryKey), "No hook for " + registryKey); + } + + public boolean hasHandlers(final RegistryKey<?> registryKey) { + final AbstractLifecycleEventType<?, ?, ?> type = ((AbstractLifecycleEventType<?, ?, ?>) this.eventTypes.get(registryKey)); + return type != null && type.hasHandlers(); + } + +} diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProviderImpl.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProviderImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..34c842ffa355e3c8001dd7b8551bcb49229a6391 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProviderImpl.java @@ -0,0 +1,24 @@ +package io.papermc.paper.registry.event; + +import io.papermc.paper.plugin.bootstrap.BootstrapContext; +import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; +import io.papermc.paper.registry.PaperRegistryListenerManager; +import io.papermc.paper.registry.RegistryBuilder; +import io.papermc.paper.registry.event.type.RegistryEntryAddEventType; + +public class RegistryEventTypeProviderImpl implements RegistryEventTypeProvider { + + public static RegistryEventTypeProviderImpl instance() { + return (RegistryEventTypeProviderImpl) RegistryEventTypeProvider.provider(); + } + + @Override + public <T, B extends RegistryBuilder<T>> RegistryEntryAddEventType<T, B> registryEntryAdd(final RegistryEventProvider<T, B> type) { + return PaperRegistryListenerManager.INSTANCE.getRegistryValueAddEventType(type); + } + + @Override + public <T, B extends RegistryBuilder<T>> LifecycleEventType.Prioritizable<BootstrapContext, RegistryFreezeEvent<T, B>> registryFreeze(final RegistryEventProvider<T, B> type) { + return PaperRegistryListenerManager.INSTANCE.getRegistryFreezeEventType(type); + } +} diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEventImpl.java b/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEventImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..1b45802f9afc97fd59c6dc77964dedea1016cd6c --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEventImpl.java @@ -0,0 +1,27 @@ +package io.papermc.paper.registry.event; + +import io.papermc.paper.plugin.lifecycle.event.PaperLifecycleEvent; +import io.papermc.paper.registry.PaperRegistries; +import io.papermc.paper.registry.RegistryBuilder; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.data.util.Conversions; +import io.papermc.paper.registry.set.NamedRegistryKeySetImpl; +import io.papermc.paper.registry.tag.Tag; +import io.papermc.paper.registry.tag.TagKey; +import net.minecraft.core.HolderSet; +import net.minecraft.resources.RegistryOps; +import org.bukkit.Keyed; + +public record RegistryFreezeEventImpl<T, B extends RegistryBuilder<T>>( + RegistryKey<T> registryKey, + WritableRegistry<T, B> registry, + Conversions conversions +) implements RegistryFreezeEvent<T, B>, PaperLifecycleEvent { + + @Override + public <V extends Keyed> Tag<V> getOrCreateTag(final TagKey<V> tagKey) { + final RegistryOps.RegistryInfo<Object> registryInfo = this.conversions.lookup().lookup(PaperRegistries.registryToNms(tagKey.registryKey())).orElseThrow(); + final HolderSet.Named<?> tagSet = registryInfo.getter().getOrThrow(PaperRegistries.toNms(tagKey)); + return new NamedRegistryKeySetImpl<>(tagKey, tagSet); + } +} diff --git a/src/main/java/io/papermc/paper/registry/event/package-info.java b/src/main/java/io/papermc/paper/registry/event/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..1d20e0d940ae498b96fe33f6176c140f816921f1 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/event/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.papermc.paper.registry.event; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddEventTypeImpl.java b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddEventTypeImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..fbf853bf1cbb3c7bbef531afe185818b9454299b --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddEventTypeImpl.java @@ -0,0 +1,37 @@ +package io.papermc.paper.registry.event.type; + +import io.papermc.paper.plugin.bootstrap.BootstrapContext; +import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; +import io.papermc.paper.plugin.lifecycle.event.types.PrioritizableLifecycleEventType; +import io.papermc.paper.registry.RegistryBuilder; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.event.RegistryEntryAddEvent; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public class RegistryEntryAddEventTypeImpl<T, B extends RegistryBuilder<T>> extends PrioritizableLifecycleEventType<BootstrapContext, RegistryEntryAddEvent<T, B>, RegistryEntryAddConfiguration<T>> implements RegistryEntryAddEventType<T, B> { + + public RegistryEntryAddEventTypeImpl(final RegistryKey<T> registryKey, final String eventName) { + super(registryKey + " / " + eventName, BootstrapContext.class); + } + + @Override + public boolean blocksReloading(final BootstrapContext eventOwner) { + return false; // only runs once + } + + @Override + public RegistryEntryAddConfiguration<T> newHandler(final LifecycleEventHandler<? super RegistryEntryAddEvent<T, B>> handler) { + return new RegistryEntryAddHandlerConfiguration<>(handler, this); + } + + @Override + public void forEachHandler(final RegistryEntryAddEvent<T, B> event, final Consumer<RegisteredHandler<BootstrapContext, RegistryEntryAddEvent<T, B>>> consumer, final Predicate<RegisteredHandler<BootstrapContext, RegistryEntryAddEvent<T, B>>> predicate) { + super.forEachHandler(event, consumer, predicate.and(handler -> this.matchesTarget(event, handler))); + } + + private boolean matchesTarget(final RegistryEntryAddEvent<T, B> event, final RegisteredHandler<BootstrapContext, RegistryEntryAddEvent<T, B>> handler) { + final RegistryEntryAddHandlerConfiguration<T, B> config = (RegistryEntryAddHandlerConfiguration<T, B>) handler.config(); + return config.filter() == null || config.filter().test(event.key()); + } +} diff --git a/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddHandlerConfiguration.java b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddHandlerConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..3cc0f7688f61c5fdbd98d0134741c98a8b9748b9 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddHandlerConfiguration.java @@ -0,0 +1,42 @@ +package io.papermc.paper.registry.event.type; + +import io.papermc.paper.plugin.bootstrap.BootstrapContext; +import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; +import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfigurationImpl; +import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType; +import io.papermc.paper.registry.RegistryBuilder; +import io.papermc.paper.registry.TypedKey; +import io.papermc.paper.registry.event.RegistryEntryAddEvent; +import java.util.function.Predicate; +import org.jetbrains.annotations.Contract; +import org.jspecify.annotations.Nullable; + +public class RegistryEntryAddHandlerConfiguration<T, B extends RegistryBuilder<T>> extends PrioritizedLifecycleEventHandlerConfigurationImpl<BootstrapContext, RegistryEntryAddEvent<T, B>> implements RegistryEntryAddConfiguration<T> { + + private @Nullable Predicate<TypedKey<T>> filter; + + public RegistryEntryAddHandlerConfiguration(final LifecycleEventHandler<? super RegistryEntryAddEvent<T, B>> handler, final AbstractLifecycleEventType<BootstrapContext, RegistryEntryAddEvent<T, B>, ?> eventType) { + super(handler, eventType); + } + + @Contract(pure = true) + public @Nullable Predicate<TypedKey<T>> filter() { + return this.filter; + } + + @Override + public RegistryEntryAddConfiguration<T> filter(final Predicate<TypedKey<T>> filter) { + this.filter = filter; + return this; + } + + @Override + public RegistryEntryAddConfiguration<T> priority(final int priority) { + return (RegistryEntryAddConfiguration<T>) super.priority(priority); + } + + @Override + public RegistryEntryAddConfiguration<T> monitor() { + return (RegistryEntryAddConfiguration<T>) super.monitor(); + } +} diff --git a/src/main/java/io/papermc/paper/registry/event/type/RegistryLifecycleEventType.java b/src/main/java/io/papermc/paper/registry/event/type/RegistryLifecycleEventType.java new file mode 100644 index 0000000000000000000000000000000000000000..7ee77022198bf5f9f88c6a1917a1da30b1863883 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/event/type/RegistryLifecycleEventType.java @@ -0,0 +1,18 @@ +package io.papermc.paper.registry.event.type; + +import io.papermc.paper.plugin.bootstrap.BootstrapContext; +import io.papermc.paper.plugin.lifecycle.event.types.PrioritizableLifecycleEventType; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.event.RegistryEvent; + +public final class RegistryLifecycleEventType<T, E extends RegistryEvent<T>> extends PrioritizableLifecycleEventType.Simple<BootstrapContext, E> { + + public RegistryLifecycleEventType(final RegistryKey<T> registryKey, final String eventName) { + super(registryKey + " / " + eventName, BootstrapContext.class); + } + + @Override + public boolean blocksReloading(final BootstrapContext eventOwner) { + return false; // only runs once + } +} diff --git a/src/main/java/io/papermc/paper/registry/event/type/package-info.java b/src/main/java/io/papermc/paper/registry/event/type/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..f9f63926a5aaf84e0d23bac3422c5800683e37f9 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/event/type/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.papermc.paper.registry.event.type; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistry.java b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistry.java index ca829b162d4369f845e59b62bb8779fd83fe2ef3..fdc475f2b112ba88ff1d89cb0c4eaa465b2d034c 100644 --- a/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistry.java +++ b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistry.java @@ -1,11 +1,14 @@ package io.papermc.paper.registry.legacy; +import io.papermc.paper.registry.tag.Tag; +import io.papermc.paper.registry.tag.TagKey; import java.util.Iterator; import java.util.function.Supplier; import java.util.stream.Stream; import org.bukkit.Keyed; import org.bukkit.NamespacedKey; import org.bukkit.Registry; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; /** @@ -54,4 +57,14 @@ public final class DelayedRegistry<T extends Keyed, R extends Registry<T>> imple public @Nullable NamespacedKey getKey(final T value) { return this.delegate().getKey(value); } + + @Override + public boolean hasTag(final TagKey<T> key) { + return this.delegate().hasTag(key); + } + + @Override + public @NonNull Tag<T> getTag(final TagKey<T> key) { + return this.delegate().getTag(key); + } } diff --git a/src/main/java/io/papermc/paper/registry/set/NamedRegistryKeySetImpl.java b/src/main/java/io/papermc/paper/registry/set/NamedRegistryKeySetImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..7b15640c2f10c72f2612ab2270adc5689dfd9e5a --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/set/NamedRegistryKeySetImpl.java @@ -0,0 +1,74 @@ +package io.papermc.paper.registry.set; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import io.papermc.paper.registry.PaperRegistries; +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import io.papermc.paper.registry.tag.Tag; +import io.papermc.paper.registry.tag.TagKey; +import java.util.Collection; +import java.util.Set; +import net.kyori.adventure.key.Key; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.jetbrains.annotations.Unmodifiable; +import org.jspecify.annotations.NullMarked; + +@NullMarked +public record NamedRegistryKeySetImpl<T extends Keyed, M>( // TODO remove Keyed + TagKey<T> tagKey, + HolderSet.Named<M> namedSet +) implements Tag<T>, org.bukkit.Tag<T> { + + @Override + public @Unmodifiable Collection<TypedKey<T>> values() { + final ImmutableList.Builder<TypedKey<T>> builder = ImmutableList.builder(); + for (final Holder<M> holder : this.namedSet) { + builder.add(TypedKey.create(this.tagKey.registryKey(), CraftNamespacedKey.fromMinecraft(((Holder.Reference<?>) holder).key().location()))); + } + return builder.build(); + } + + @Override + public RegistryKey<T> registryKey() { + return this.tagKey.registryKey(); + } + + @Override + public boolean contains(final TypedKey<T> valueKey) { + return Iterables.any(this.namedSet, h -> { + return PaperRegistries.fromNms(((Holder.Reference<?>) h).key()).equals(valueKey); + }); + } + + @Override + public @Unmodifiable Collection<T> resolve(final Registry<T> registry) { + final ImmutableList.Builder<T> builder = ImmutableList.builder(); + for (final Holder<M> holder : this.namedSet) { + builder.add(registry.getOrThrow(CraftNamespacedKey.fromMinecraft(((Holder.Reference<?>) holder).key().location()))); + } + return builder.build(); + } + + @Override + public boolean isTagged(final T item) { + return this.getValues().contains(item); + } + + @Override + public Set<T> getValues() { + return Set.copyOf(this.resolve(RegistryAccess.registryAccess().getRegistry(this.registryKey()))); + } + + @Override + public NamespacedKey getKey() { + final Key key = this.tagKey().key(); + return new NamespacedKey(key.namespace(), key.value()); + } +} diff --git a/src/main/java/io/papermc/paper/registry/set/PaperRegistrySets.java b/src/main/java/io/papermc/paper/registry/set/PaperRegistrySets.java new file mode 100644 index 0000000000000000000000000000000000000000..cb92f53cf9d139828acd016499470212a198b722 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/set/PaperRegistrySets.java @@ -0,0 +1,45 @@ +package io.papermc.paper.registry.set; + +import io.papermc.paper.registry.PaperRegistries; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import java.util.ArrayList; +import java.util.List; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.Registry; +import net.minecraft.resources.RegistryOps; +import net.minecraft.resources.ResourceKey; +import org.bukkit.Keyed; + +public final class PaperRegistrySets { + + public static <A extends Keyed, M> HolderSet<M> convertToNms(final ResourceKey<? extends Registry<M>> resourceKey, final RegistryOps.RegistryInfoLookup lookup, final RegistryKeySet<A> registryKeySet) { // TODO remove Keyed + if (registryKeySet instanceof NamedRegistryKeySetImpl<A, ?>) { + return ((NamedRegistryKeySetImpl<A, M>) registryKeySet).namedSet(); + } else { + final RegistryOps.RegistryInfo<M> registryInfo = lookup.lookup(resourceKey).orElseThrow(); + return HolderSet.direct(key -> { + return registryInfo.getter().getOrThrow(PaperRegistries.toNms(key)); + }, registryKeySet.values()); + } + } + + public static <A extends Keyed, M> RegistryKeySet<A> convertToApi(final RegistryKey<A> registryKey, final HolderSet<M> holders) { // TODO remove Keyed + if (holders instanceof final HolderSet.Named<M> named) { + return new NamedRegistryKeySetImpl<>(PaperRegistries.fromNms(named.key()), named); + } else { + final List<TypedKey<A>> keys = new ArrayList<>(); + for (final Holder<M> holder : holders) { + if (!(holder instanceof final Holder.Reference<M> reference)) { + throw new UnsupportedOperationException("Cannot convert a holder set containing direct holders"); + } + keys.add(PaperRegistries.fromNms(reference.key())); + } + return RegistrySet.keySet(registryKey, keys); + } + } + + private PaperRegistrySets() { + } +} diff --git a/src/main/java/io/papermc/paper/registry/set/package-info.java b/src/main/java/io/papermc/paper/registry/set/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..516b072428dcc8a28d13bcc990493cf4c22ad948 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/set/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.papermc.paper.registry.set; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/net/minecraft/core/MappedRegistry.java b/src/main/java/net/minecraft/core/MappedRegistry.java index 71e04e5c1bc0722abf8ca2e0738bd60b6d7ae21c..063630c1ffcce099139c59d598fc5a210e21f640 100644 --- a/src/main/java/net/minecraft/core/MappedRegistry.java +++ b/src/main/java/net/minecraft/core/MappedRegistry.java @@ -509,4 +509,12 @@ public class MappedRegistry<T> implements WritableRegistry<T> { Stream<HolderSet.Named<T>> getTags(); } + // Paper start + // used to clear intrusive holders from GameEvent, Item, Block, EntityType, and Fluid from unused instances of those types + public void clearIntrusiveHolder(final T instance) { + if (this.unregisteredIntrusiveHolders != null) { + this.unregisteredIntrusiveHolders.remove(instance); + } + } + // Paper end } diff --git a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java index 4638ba98dbbdb0f880337347be85a6e0fbed2191..bc448f8511c629d1f13d4baf717a11e6a6ad24f9 100644 --- a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java +++ b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java @@ -296,6 +296,17 @@ public class BuiltInRegistries { public static final Registry<SlotDisplay.Type<?>> SLOT_DISPLAY = registerSimple(Registries.SLOT_DISPLAY, SlotDisplays::bootstrap); public static final Registry<RecipeBookCategory> RECIPE_BOOK_CATEGORY = registerSimple(Registries.RECIPE_BOOK_CATEGORY, RecipeBookCategories::bootstrap); public static final Registry<? extends Registry<?>> REGISTRY = WRITABLE_REGISTRY; + // Paper start - add built-in registry conversions + public static final io.papermc.paper.registry.data.util.Conversions BUILT_IN_CONVERSIONS = new io.papermc.paper.registry.data.util.Conversions(new net.minecraft.resources.RegistryOps.RegistryInfoLookup() { + @Override + public <T> java.util.Optional<net.minecraft.resources.RegistryOps.RegistryInfo<T>> lookup(final ResourceKey<? extends Registry<? extends T>> registryRef) { + final Registry<T> registry = net.minecraft.server.RegistryLayer.STATIC_ACCESS.lookupOrThrow(registryRef); + return java.util.Optional.of( + new net.minecraft.resources.RegistryOps.RegistryInfo<>(registry, registry, Lifecycle.experimental()) + ); + } + }); + // Paper end - add built-in registry conversions private static <T> Registry<T> registerSimple(ResourceKey<? extends Registry<T>> key, BuiltInRegistries.RegistryBootstrap<T> initializer) { return internalRegister(key, new MappedRegistry<>(key, Lifecycle.stable(), false), initializer); @@ -336,6 +347,7 @@ public class BuiltInRegistries { } public static void bootStrap(Runnable runnable) { // Paper end + REGISTRY.freeze(); // Paper - freeze main registry early createContents(); runnable.run(); // Paper freeze(); @@ -355,6 +367,7 @@ public class BuiltInRegistries { for (Registry<?> registry : REGISTRY) { bindBootstrappedTagsToEmpty(registry); + io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.runFreezeListeners(registry.key(), BUILT_IN_CONVERSIONS); // Paper registry.freeze(); } } diff --git a/src/main/java/net/minecraft/resources/RegistryDataLoader.java b/src/main/java/net/minecraft/resources/RegistryDataLoader.java index b8c1840eeda982c0c6350e49fae2784a599ef3ce..1aaa18b91a13cffac5f3d03fbae207f8ea91d3c7 100644 --- a/src/main/java/net/minecraft/resources/RegistryDataLoader.java +++ b/src/main/java/net/minecraft/resources/RegistryDataLoader.java @@ -238,13 +238,13 @@ public class RegistryDataLoader { } private static <E> void loadElementFromResource( - WritableRegistry<E> registry, Decoder<E> decoder, RegistryOps<JsonElement> ops, ResourceKey<E> key, Resource resource, RegistrationInfo entryInfo + WritableRegistry<E> registry, Decoder<E> decoder, RegistryOps<JsonElement> ops, ResourceKey<E> key, Resource resource, RegistrationInfo entryInfo, io.papermc.paper.registry.data.util.Conversions conversions // Paper - pass conversions ) throws IOException { try (Reader reader = resource.openAsReader()) { JsonElement jsonElement = JsonParser.parseReader(reader); DataResult<E> dataResult = decoder.parse(ops, jsonElement); E object = dataResult.getOrThrow(); - registry.register(key, object, entryInfo); + io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerWithListeners(registry, key, object, entryInfo, conversions); // Paper - register with listeners } } @@ -258,6 +258,7 @@ public class RegistryDataLoader { FileToIdConverter fileToIdConverter = FileToIdConverter.registry(registry.key()); RegistryOps<JsonElement> registryOps = RegistryOps.create(JsonOps.INSTANCE, infoGetter); + final io.papermc.paper.registry.data.util.Conversions conversions = new io.papermc.paper.registry.data.util.Conversions(infoGetter); // Paper - create conversions for (Entry<ResourceLocation, Resource> entry : fileToIdConverter.listMatchingResources(resourceManager).entrySet()) { ResourceLocation resourceLocation = entry.getKey(); ResourceKey<E> resourceKey = ResourceKey.create(registry.key(), fileToIdConverter.fileToId(resourceLocation)); @@ -265,7 +266,7 @@ public class RegistryDataLoader { RegistrationInfo registrationInfo = REGISTRATION_INFO_CACHE.apply(resource.knownPackInfo()); try { - loadElementFromResource(registry, elementDecoder, registryOps, resourceKey, resource, registrationInfo); + loadElementFromResource(registry, elementDecoder, registryOps, resourceKey, resource, registrationInfo, conversions); // Paper - pass conversions } catch (Exception var14) { errors.put( resourceKey, @@ -274,6 +275,7 @@ public class RegistryDataLoader { } } + io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.runFreezeListeners(registry.key(), conversions); // Paper - run pre-freeze listeners TagLoader.loadTagsForRegistry(resourceManager, registry); } @@ -291,6 +293,7 @@ public class RegistryDataLoader { RegistryOps<JsonElement> registryOps2 = RegistryOps.create(JsonOps.INSTANCE, infoGetter); FileToIdConverter fileToIdConverter = FileToIdConverter.registry(registry.key()); + final io.papermc.paper.registry.data.util.Conversions conversions = new io.papermc.paper.registry.data.util.Conversions(infoGetter); // Paper - create conversions for (RegistrySynchronization.PackedRegistryEntry packedRegistryEntry : networkedRegistryData.elements) { ResourceKey<E> resourceKey = ResourceKey.create(registry.key(), packedRegistryEntry.id()); Optional<Tag> optional = packedRegistryEntry.data(); @@ -309,7 +312,7 @@ public class RegistryDataLoader { try { Resource resource = factory.getResourceOrThrow(resourceLocation); - loadElementFromResource(registry, decoder, registryOps2, resourceKey, resource, NETWORK_REGISTRATION_INFO); + loadElementFromResource(registry, decoder, registryOps2, resourceKey, resource, NETWORK_REGISTRATION_INFO, conversions); // Paper - pass conversions } catch (Exception var17) { loadingErrors.put(resourceKey, new IllegalStateException("Failed to parse local data", var17)); } diff --git a/src/main/java/net/minecraft/server/ReloadableServerRegistries.java b/src/main/java/net/minecraft/server/ReloadableServerRegistries.java index 185752185549ebd5f431932b63d8e5fea50a2cb2..f4d25d1aed5bcd3b8119ac7356a9cccc9d4ff54c 100644 --- a/src/main/java/net/minecraft/server/ReloadableServerRegistries.java +++ b/src/main/java/net/minecraft/server/ReloadableServerRegistries.java @@ -50,8 +50,9 @@ public class ReloadableServerRegistries { ); HolderLookup.Provider provider = HolderLookup.Provider.create(list.stream()); RegistryOps<JsonElement> registryOps = provider.createSerializationContext(JsonOps.INSTANCE); + final io.papermc.paper.registry.data.util.Conversions conversions = new io.papermc.paper.registry.data.util.Conversions(registryOps.lookupProvider); // Paper List<CompletableFuture<WritableRegistry<?>>> list2 = LootDataType.values() - .map(type -> scheduleRegistryLoad((LootDataType<?>)type, registryOps, resourceManager, prepareExecutor)) + .map(type -> scheduleRegistryLoad((LootDataType<?>)type, registryOps, resourceManager, prepareExecutor, conversions)) // Paper .toList(); CompletableFuture<List<WritableRegistry<?>>> completableFuture = Util.sequence(list2); return completableFuture.thenApplyAsync( @@ -60,14 +61,14 @@ public class ReloadableServerRegistries { } private static <T> CompletableFuture<WritableRegistry<?>> scheduleRegistryLoad( - LootDataType<T> type, RegistryOps<JsonElement> ops, ResourceManager resourceManager, Executor prepareExecutor + LootDataType<T> type, RegistryOps<JsonElement> ops, ResourceManager resourceManager, Executor prepareExecutor, io.papermc.paper.registry.data.util.Conversions conversions // Paper ) { return CompletableFuture.supplyAsync(() -> { WritableRegistry<T> writableRegistry = new MappedRegistry<>(type.registryKey(), Lifecycle.experimental()); io.papermc.paper.registry.PaperRegistryAccess.instance().registerReloadableRegistry(type.registryKey(), writableRegistry); // Paper - register reloadable registry Map<ResourceLocation, T> map = new HashMap<>(); SimpleJsonResourceReloadListener.scanDirectory(resourceManager, type.registryKey(), ops, type.codec(), map); - map.forEach((id, value) -> writableRegistry.register(ResourceKey.create(type.registryKey(), id), (T)value, DEFAULT_REGISTRATION_INFO)); + map.forEach((id, value) -> io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerWithListeners(writableRegistry, ResourceKey.create(type.registryKey(), id), value, DEFAULT_REGISTRATION_INFO, conversions)); // Paper - register with listeners TagLoader.loadTagsForRegistry(resourceManager, writableRegistry); return writableRegistry; }, prepareExecutor); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java index 061e3f6177c1383d9c5a6d73eb8bfda438bc7c4a..541be680837753df7eaafa105f4d21ec406a7c99 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java @@ -301,4 +301,17 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> { return this.byValue.get(value); } // Paper end - improve Registry + + // Paper start - RegistrySet API + @Override + public boolean hasTag(final io.papermc.paper.registry.tag.TagKey<B> key) { + return this.minecraftRegistry.get(net.minecraft.tags.TagKey.create(this.minecraftRegistry.key(), io.papermc.paper.adventure.PaperAdventure.asVanilla(key.key()))).isPresent(); + } + + @Override + public io.papermc.paper.registry.tag.Tag<B> getTag(final io.papermc.paper.registry.tag.TagKey<B> key) { + final net.minecraft.core.HolderSet.Named<M> namedHolderSet = this.minecraftRegistry.get(io.papermc.paper.registry.PaperRegistries.toNms(key)).orElseThrow(); + return new io.papermc.paper.registry.set.NamedRegistryKeySetImpl<>(key, namedHolderSet); + } + // Paper end - RegistrySet API } diff --git a/src/main/resources/META-INF/services/io.papermc.paper.registry.event.RegistryEventTypeProvider b/src/main/resources/META-INF/services/io.papermc.paper.registry.event.RegistryEventTypeProvider new file mode 100644 index 0000000000000000000000000000000000000000..8bee1a5ed877a04e4d027593df1f42cefdd824e7 --- /dev/null +++ b/src/main/resources/META-INF/services/io.papermc.paper.registry.event.RegistryEventTypeProvider @@ -0,0 +1 @@ +io.papermc.paper.registry.event.RegistryEventTypeProviderImpl diff --git a/src/test/java/io/papermc/paper/registry/RegistryBuilderTest.java b/src/test/java/io/papermc/paper/registry/RegistryBuilderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..55f5fc45cfd5be16b4d8e6d083ff10a744196a5e --- /dev/null +++ b/src/test/java/io/papermc/paper/registry/RegistryBuilderTest.java @@ -0,0 +1,44 @@ +package io.papermc.paper.registry; + +import io.papermc.paper.registry.data.util.Conversions; +import io.papermc.paper.registry.entry.RegistryEntry; +import io.papermc.paper.registry.entry.RegistryEntryInfo; +import io.papermc.paper.registry.legacy.DelayedRegistryEntry; +import java.util.Map; +import java.util.stream.Stream; +import net.minecraft.core.Registry; +import net.minecraft.resources.RegistryOps; +import net.minecraft.resources.ResourceKey; +import org.bukkit.Keyed; +import org.bukkit.support.RegistryHelper; +import org.bukkit.support.environment.AllFeatures; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@AllFeatures +class RegistryBuilderTest { + + static Stream<Arguments> registries() { + return PaperRegistries.REGISTRY_ENTRIES.stream() + .map(RegistryBuilderTest::possiblyUnwrap) + .filter(RegistryEntry.BuilderHolder.class::isInstance) + .map(Arguments::arguments); + } + + private static <M, B extends Keyed> RegistryEntryInfo<M, B> possiblyUnwrap(final RegistryEntryInfo<M, B> entry) { + return entry instanceof final DelayedRegistryEntry<M, B> delayed ? delayed.delegate() : entry; + } + + @ParameterizedTest + @MethodSource("registries") + <M, T> void testEquality(final RegistryEntry.BuilderHolder<M, T, ?> registryEntry) { + final Registry<M> registry = RegistryHelper.getRegistry().lookupOrThrow(registryEntry.mcKey()); + for (final Map.Entry<ResourceKey<M>, M> entry : registry.entrySet()) { + final M built = registryEntry.fillBuilder(new Conversions(new RegistryOps.HolderLookupAdapter(RegistryHelper.getRegistry())), entry.getValue()).build(); + assertEquals(entry.getValue(), built); + } + } +} diff --git a/src/test/java/org/bukkit/registry/RegistryClassTest.java b/src/test/java/org/bukkit/registry/RegistryClassTest.java index ea3d37f387bdb0dd5ae3fba9231ace31d0cebd64..c118c911972fe5a9f0c3e306009306f04ae2e821 100644 --- a/src/test/java/org/bukkit/registry/RegistryClassTest.java +++ b/src/test/java/org/bukkit/registry/RegistryClassTest.java @@ -111,7 +111,7 @@ public class RegistryClassTest { outsideRequest.clear(); MockUtil.resetMock(spyRegistry); doAnswer(invocation -> { - Keyed item = realRegistry.get(invocation.getArgument(0)); + Keyed item = realRegistry.get((NamespacedKey) invocation.getArgument(0)); // Paper - registry modification api - specifically call namespaced key overload if (item == null) { nullValue.add(invocation.getArgument(0)); @@ -120,10 +120,10 @@ public class RegistryClassTest { nullAble.add(invocation.getArgument(0)); return item; - }).when(spyRegistry).get(any()); + }).when(spyRegistry).get((NamespacedKey) any()); // Paper - registry modification api - specifically call namespaced key overload doAnswer(invocation -> { - Keyed item = realRegistry.get(invocation.getArgument(0)); + Keyed item = realRegistry.get((NamespacedKey) invocation.getArgument(0)); // Paper - registry modification api - specifically call namespaced key overload if (item == null) { nullValue.add(invocation.getArgument(0)); @@ -138,7 +138,7 @@ public class RegistryClassTest { notNullAble.add(invocation.getArgument(0)); return item; - }).when(spyRegistry).getOrThrow(any()); + }).when(spyRegistry).getOrThrow((NamespacedKey) any()); // Paper - registry modification api - specifically call namespaced key overload // Load class try { @@ -171,13 +171,13 @@ public class RegistryClassTest { outsideRequest .computeIfAbsent(type, ty -> new ArrayList<>()).add(invocation.getArgument(0)); return mock(type); - }).when(spyRegistry).get(any()); + }).when(spyRegistry).get((NamespacedKey) any()); // Paper - registry modification api - specifically call namespaced key overload doAnswer(invocation -> { outsideRequest .computeIfAbsent(type, ty -> new ArrayList<>()).add(invocation.getArgument(0)); return mock(type); - }).when(spyRegistry).getOrThrow(any()); + }).when(spyRegistry).getOrThrow((NamespacedKey) any()); // Paper - registry modification api - specifically call namespaced key overload } private static void initFieldDataCache() { diff --git a/src/test/java/org/bukkit/support/extension/NormalExtension.java b/src/test/java/org/bukkit/support/extension/NormalExtension.java index 8b5dcc4d0ecf7f9c51f73080c123ca08e31b1898..a809ea2f0d2b477c61857aa02a7e55024b2a7e0d 100644 --- a/src/test/java/org/bukkit/support/extension/NormalExtension.java +++ b/src/test/java/org/bukkit/support/extension/NormalExtension.java @@ -62,7 +62,7 @@ public class NormalExtension extends BaseExtension { doAnswer(invocation -> mocks.computeIfAbsent(invocation.getArgument(0), k -> mock(RegistryHelper.updateClass(keyed, invocation.getArgument(0)), withSettings().stubOnly().defaultAnswer(DEFAULT_ANSWER))) - ).when(registry).get(any()); // Allow static classes to fill there fields, so that it does not error out, just by loading them + ).when(registry).get((NamespacedKey) any()); // Allow static classes to fill there fields, so that it does not error out, just by loading them // Paper - registry modification api - specifically call namespaced key overload return registry; }