refactor registry entry to detach 'delayed' from other meta

Also fixes an issue with direct holders
This commit is contained in:
Jake Potrebic 2024-12-22 21:17:16 -08:00
parent 188124bcc3
commit a0b3326609
No known key found for this signature in database
GPG Key ID: 27CC63F7CBC866C7
19 changed files with 220 additions and 357 deletions

View File

@ -104,7 +104,7 @@ public final class PaperRegistries {
start(Registries.TRIM_PATTERN, RegistryKey.TRIM_PATTERN).craft(TrimPattern.class, CraftTrimPattern::new).build().delayed(),
start(Registries.DAMAGE_TYPE, RegistryKey.DAMAGE_TYPE).craft(DamageType.class, CraftDamageType::new).build().delayed(),
start(Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT).craft(Wolf.Variant.class, CraftWolf.CraftVariant::new).build().delayed(),
start(Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT).craft(Enchantment.class, CraftEnchantment::new).writable(PaperEnchantmentRegistryEntry.PaperBuilder::new).withSerializationUpdater(FieldRename.ENCHANTMENT_RENAME).delayed(),
start(Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT).craft(Enchantment.class, CraftEnchantment::new).serializationUpdater(FieldRename.ENCHANTMENT_RENAME).writable(PaperEnchantmentRegistryEntry.PaperBuilder::new).delayed(),
start(Registries.JUKEBOX_SONG, RegistryKey.JUKEBOX_SONG).craft(JukeboxSong.class, CraftJukeboxSong::new).build().delayed(),
start(Registries.BANNER_PATTERN, RegistryKey.BANNER_PATTERN).craft(PatternType.class, CraftPatternType::new).build().delayed(),
start(Registries.PAINTING_VARIANT, RegistryKey.PAINTING_VARIANT).craft(Art.class, CraftArt::new).writable(PaperPaintingVariantRegistryEntry.PaperBuilder::new).delayed(),

View File

@ -1,7 +1,7 @@
package io.papermc.paper.registry;
import io.papermc.paper.registry.entry.ApiRegistryEntry;
import io.papermc.paper.registry.entry.RegistryEntry;
import io.papermc.paper.registry.entry.RegistryEntryMeta;
import io.papermc.paper.registry.legacy.DelayedRegistry;
import io.papermc.paper.registry.legacy.DelayedRegistryEntry;
import io.papermc.paper.registry.legacy.LegacyRegistryIdentifiers;
@ -31,7 +31,10 @@ public class PaperRegistryAccess implements RegistryAccess {
@VisibleForTesting
public Set<RegistryKey<?>> getLoadedServerBackedRegistries() {
return this.registries.keySet().stream().filter(registryHolder -> !(PaperRegistries.getEntry(registryHolder) instanceof ApiRegistryEntry)).collect(Collectors.toUnmodifiableSet());
return this.registries.keySet().stream().filter(registryHolder -> {
final RegistryEntry<?, ?> entry = PaperRegistries.getEntry(registryHolder);
return entry != null && !(entry.meta() instanceof RegistryEntryMeta.ApiOnly<?,?>);
}).collect(Collectors.toUnmodifiableSet());
}
@SuppressWarnings("unchecked")

View File

@ -12,14 +12,8 @@ public interface PaperRegistryBuilder<M, T> extends RegistryBuilder<T> {
B fill(Conversions conversions, @Nullable M nms);
default Factory<M, T, B> asFactory() {
return (lookup) -> this.fill(lookup, null);
default B create(final Conversions conversions) {
return this.fill(conversions, null);
}
}
@FunctionalInterface
interface Factory<M, T, B extends PaperRegistryBuilder<M, T>> {
B create(Conversions conversions);
}
}

View File

@ -9,7 +9,7 @@ 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.entry.RegistryEntryMeta;
import io.papermc.paper.registry.event.RegistryEntryAddEventImpl;
import io.papermc.paper.registry.event.RegistryEventMap;
import io.papermc.paper.registry.event.RegistryEventProvider;
@ -28,6 +28,7 @@ import net.minecraft.core.WritableRegistry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import org.bukkit.Keyed;
import org.intellij.lang.annotations.Subst;
import org.jspecify.annotations.Nullable;
@ -86,8 +87,7 @@ public class PaperRegistryListenerManager {
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(
public <M, T extends Keyed, B extends PaperRegistryBuilder<M, T>, R> R registerWithListeners( // TODO remove Keyed
final Registry<M> registry,
final ResourceKey<M> key,
final M nms,
@ -96,34 +96,33 @@ public class PaperRegistryListenerManager {
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())) {
final RegistryEntry<M, T> entry = PaperRegistries.getEntry(registry.key());
if (entry == null || !entry.meta().modificationApiSupport().canModify() || !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);
final RegistryEntryMeta.Buildable<M, T, B> modifiableEntry = (RegistryEntryMeta.Buildable<M, T, B>) entry.meta();
final B builder = modifiableEntry.builderFiller().fill(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
<M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> void registerWithListeners( // TODO remove Keyed
final WritableRegistry<M> registry,
final RegistryEntryInfo<M, T> entry,
final RegistryEntryMeta.Buildable<M, T, B> entry,
final ResourceKey<M> key,
final B builder,
final RegistrationInfo registrationInfo,
final Conversions conversions
) {
if (!RegistryEntry.Modifiable.isModifiable(entry) || !this.valueAddEventTypes.hasHandlers(entry.apiKey())) {
if (!entry.modificationApiSupport().canModify() || !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);
this.registerWithListeners(registry, 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
public <M, T extends Keyed, B extends PaperRegistryBuilder<M, T>, R> R registerWithListeners( // TODO remove Keyed
final Registry<M> registry,
final RegistryEntry.Modifiable<M, T, B> entry,
final RegistryEntryMeta.Buildable<M, T, B> entry,
final ResourceKey<M> key,
final @Nullable M oldNms,
final B builder,
@ -156,26 +155,28 @@ public class PaperRegistryListenerManager {
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())) {
public <M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> void runFreezeListeners(final ResourceKey<? extends Registry<M>> resourceKey, final Conversions conversions) {
final RegistryEntry<M, T> entry = PaperRegistries.getEntry(resourceKey);
if (entry == null || !entry.meta().modificationApiSupport().canAdd() || !this.freezeEventTypes.hasHandlers(entry.apiKey())) {
return;
}
final RegistryEntry.Addable<M, T, B> writableEntry = RegistryEntry.Addable.asAddable(entry);
final RegistryEntryMeta.Buildable<M, T, B> writableEntry = (RegistryEntryMeta.Buildable<M, T, B>) entry.meta();
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()))) {
final RegistryEntry<?, ?> entry = PaperRegistries.getEntry(type.registryKey());
if (entry == null || !entry.meta().modificationApiSupport().canModify()) {
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()))) {
final RegistryEntry<?, ?> entry = PaperRegistries.getEntry(type.registryKey());
if (entry == null || !entry.meta().modificationApiSupport().canAdd()) {
throw new IllegalArgumentException(type.registryKey() + " does not support RegistryFreezeEvent");
}
return this.freezeEventTypes.getOrCreate(type.registryKey(), RegistryLifecycleEventType::new);

View File

@ -3,6 +3,7 @@ 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.RegistryEntryMeta;
import io.papermc.paper.registry.entry.RegistryTypeMapper;
import io.papermc.paper.registry.event.WritableRegistry;
import java.util.Optional;
@ -20,22 +21,16 @@ public class WritableCraftRegistry<M, T extends Keyed, B extends PaperRegistryBu
private static final RegistrationInfo FROM_PLUGIN = new RegistrationInfo(Optional.empty(), Lifecycle.experimental());
private final RegistryEntry.BuilderHolder<M, T, B> entry;
private final RegistryEntryMeta.Buildable<M, T, B> meta;
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
final RegistryEntryMeta.Buildable<M, T, B> meta
) {
super(classToPreload, registry, minecraftToBukkit, serializationUpdater);
this.entry = entry;
super(meta, registry);
this.registry = registry;
this.builderFactory = builderFactory;
this.meta = meta;
}
public void register(final TypedKey<T> key, final Consumer<? super B> value, final Conversions conversions) {
@ -45,7 +40,7 @@ public class WritableCraftRegistry<M, T extends Keyed, B extends PaperRegistryBu
value.accept(builder);
PaperRegistryListenerManager.INSTANCE.registerWithListeners(
this.registry,
RegistryEntry.Modifiable.asModifiable(this.entry),
this.meta,
resourceKey,
builder,
FROM_PLUGIN,
@ -58,7 +53,7 @@ public class WritableCraftRegistry<M, T extends Keyed, B extends PaperRegistryBu
}
protected B newBuilder(final Conversions conversions) {
return this.builderFactory.create(conversions);
return this.meta.builderFiller().create(conversions);
}
public class ApiWritableRegistry implements WritableRegistry<T, B> {

View File

@ -1,41 +0,0 @@
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);
}
}

View File

@ -1,27 +0,0 @@
package io.papermc.paper.registry.entry;
import io.papermc.paper.registry.RegistryHolder;
import io.papermc.paper.registry.RegistryKey;
import java.util.function.Supplier;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import org.bukkit.Keyed;
public class ApiRegistryEntry<M, B extends Keyed> extends BaseRegistryEntry<M, B> {
private final Supplier<org.bukkit.Registry<B>> registrySupplier;
protected ApiRegistryEntry(
final ResourceKey<? extends Registry<M>> mcKey,
final RegistryKey<B> apiKey,
final Supplier<org.bukkit.Registry<B>> registrySupplier
) {
super(mcKey, apiKey);
this.registrySupplier = registrySupplier;
}
@Override
public RegistryHolder<B> createRegistryHolder(final Registry<M> nmsRegistry) {
return new RegistryHolder.Memoized<>(this.registrySupplier);
}
}

View File

@ -1,27 +0,0 @@
package io.papermc.paper.registry.entry;
import io.papermc.paper.registry.RegistryKey;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import org.bukkit.Keyed;
public abstract class BaseRegistryEntry<M, B extends Keyed> implements RegistryEntry<M, B> { // TODO remove Keyed
private final ResourceKey<? extends Registry<M>> minecraftRegistryKey;
private final RegistryKey<B> apiRegistryKey;
protected BaseRegistryEntry(final ResourceKey<? extends Registry<M>> minecraftRegistryKey, final RegistryKey<B> apiRegistryKey) {
this.minecraftRegistryKey = minecraftRegistryKey;
this.apiRegistryKey = apiRegistryKey;
}
@Override
public final ResourceKey<? extends Registry<M>> mcKey() {
return this.minecraftRegistryKey;
}
@Override
public final RegistryKey<B> apiKey() {
return this.apiRegistryKey;
}
}

View File

@ -1,51 +0,0 @@
package io.papermc.paper.registry.entry;
import com.google.common.base.Preconditions;
import com.mojang.datafixers.util.Either;
import io.papermc.paper.registry.RegistryHolder;
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;
import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.util.ApiVersion;
public class CraftRegistryEntry<M, B extends Keyed> extends BaseRegistryEntry<M, B> { // TODO remove Keyed
private static final BiFunction<NamespacedKey, ApiVersion, NamespacedKey> EMPTY = (namespacedKey, apiVersion) -> namespacedKey;
protected final Class<?> classToPreload;
protected final RegistryTypeMapper<M, B> minecraftToBukkit;
protected BiFunction<NamespacedKey, ApiVersion, NamespacedKey> updater = EMPTY;
protected CraftRegistryEntry(
final ResourceKey<? extends Registry<M>> mcKey,
final RegistryKey<B> apiKey,
final Class<?> classToPreload,
final RegistryTypeMapper<M, B> minecraftToBukkit
) {
super(mcKey, apiKey);
Preconditions.checkArgument(!classToPreload.getPackageName().startsWith("net.minecraft"), classToPreload + " should not be in the net.minecraft package as the class-to-preload");
this.classToPreload = classToPreload;
this.minecraftToBukkit = minecraftToBukkit;
}
@Override
public RegistryEntry<M, B> withSerializationUpdater(final BiFunction<NamespacedKey, ApiVersion, NamespacedKey> updater) {
this.updater = updater;
return this;
}
@Override
public RegistryHolder<B> createRegistryHolder(final Registry<M> nmsRegistry) {
return new RegistryHolder.Memoized<>(() -> this.createApiRegistry(nmsRegistry));
}
private CraftRegistry<B, M> createApiRegistry(final Registry<M> nmsRegistry) {
return new CraftRegistry<>(this.classToPreload, nmsRegistry, this.minecraftToBukkit, this.updater);
}
}

View File

@ -1,29 +0,0 @@
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);
}
}

View File

@ -1,27 +1,24 @@
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 net.minecraft.resources.ResourceKey;
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
public interface RegistryEntry<M, A extends Keyed> { // TODO remove Keyed
RegistryHolder<B> createRegistryHolder(Registry<M> nmsRegistry);
RegistryHolder<A> createRegistryHolder(Registry<M> nmsRegistry);
default RegistryEntry<M, B> withSerializationUpdater(final BiFunction<NamespacedKey, ApiVersion, NamespacedKey> updater) {
return this;
RegistryEntryMeta<M, A> meta();
default RegistryKey<A> apiKey() {
return this.meta().apiKey();
}
default ResourceKey<? extends Registry<M>> mcKey() {
return this.meta().mcKey();
}
/**
@ -30,66 +27,7 @@ public interface RegistryEntry<M, B extends Keyed> extends RegistryEntryInfo<M,
* as fields, but instead be obtained via {@link io.papermc.paper.registry.RegistryAccess#getRegistry(RegistryKey)}
*/
@Deprecated
default RegistryEntry<M, B> delayed() {
default RegistryEntry<M, A> 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;
}
}

View File

@ -1,6 +1,5 @@
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;
@ -11,6 +10,11 @@ import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import org.bukkit.Keyed;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.util.ApiVersion;
import static io.papermc.paper.registry.entry.RegistryEntryMeta.RegistryModificationApiSupport.ADDABLE;
import static io.papermc.paper.registry.entry.RegistryEntryMeta.RegistryModificationApiSupport.MODIFIABLE;
import static io.papermc.paper.registry.entry.RegistryEntryMeta.RegistryModificationApiSupport.WRITABLE;
public class RegistryEntryBuilder<M, A extends Keyed> { // TODO remove Keyed
@ -30,7 +34,7 @@ public class RegistryEntryBuilder<M, A extends Keyed> { // TODO remove Keyed
}
public RegistryEntry<M, A> apiOnly(final Supplier<org.bukkit.Registry<A>> apiRegistrySupplier) {
return new ApiRegistryEntry<>(this.mcKey, this.apiKey, apiRegistrySupplier);
return new RegistryEntryImpl<>(new RegistryEntryMeta.ApiOnly<>(this.mcKey, this.apiKey, apiRegistrySupplier));
}
public CraftStage<M, A> craft(final Class<?> classToPreload, final BiFunction<? super NamespacedKey, M, ? extends A> minecraftToBukkit) {
@ -43,8 +47,11 @@ public class RegistryEntryBuilder<M, A extends Keyed> { // TODO remove Keyed
public static final class CraftStage<M, A extends Keyed> extends RegistryEntryBuilder<M, A> { // TODO remove Keyed
private static final BiFunction<NamespacedKey, ApiVersion, NamespacedKey> EMPTY = (namespacedKey, apiVersion) -> namespacedKey;
private final Class<?> classToPreload;
private final RegistryTypeMapper<M, A> minecraftToBukkit;
private BiFunction<NamespacedKey, ApiVersion, NamespacedKey> serializationUpdater = EMPTY;
private CraftStage(
final ResourceKey<? extends Registry<M>> mcKey,
@ -57,20 +64,29 @@ public class RegistryEntryBuilder<M, A extends Keyed> { // TODO remove Keyed
this.minecraftToBukkit = minecraftToBukkit;
}
public CraftStage<M, A> serializationUpdater(final BiFunction<NamespacedKey, ApiVersion, NamespacedKey> serializationUpdater) {
this.serializationUpdater = serializationUpdater;
return this;
}
public RegistryEntry<M, A> build() {
return new CraftRegistryEntry<>(this.mcKey, this.apiKey, this.classToPreload, this.minecraftToBukkit);
return new RegistryEntryImpl<>(new RegistryEntryMeta.Craft<>(this.mcKey, this.apiKey, this.classToPreload, this.minecraftToBukkit, this.serializationUpdater));
}
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);
return this.create(filler, MODIFIABLE);
}
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);
return this.create(filler, ADDABLE);
}
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);
return this.create(filler, WRITABLE);
}
private <B extends PaperRegistryBuilder<M, A>> RegistryEntry<M, A> create(final PaperRegistryBuilder.Filler<M, A, B> filler, final RegistryEntryMeta.RegistryModificationApiSupport support) {
return new RegistryEntryImpl<>(new RegistryEntryMeta.Buildable<>(this.mcKey, this.apiKey, this.classToPreload, this.minecraftToBukkit, this.serializationUpdater, filler, support));
}
}
}

View File

@ -0,0 +1,13 @@
package io.papermc.paper.registry.entry;
import io.papermc.paper.registry.RegistryHolder;
import net.minecraft.core.Registry;
import org.bukkit.Keyed;
record RegistryEntryImpl<M, A extends Keyed>(RegistryEntryMeta<M, A> meta) implements RegistryEntry<M, A> {
@Override
public RegistryHolder<A> createRegistryHolder(final Registry<M> nmsRegistry) {
return new RegistryHolder.Memoized<>(() -> this.meta().createApiRegistry(nmsRegistry));
}
}

View File

@ -1,12 +0,0 @@
package io.papermc.paper.registry.entry;
import io.papermc.paper.registry.RegistryKey;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
public interface RegistryEntryInfo<M, B> {
ResourceKey<? extends Registry<M>> mcKey();
RegistryKey<B> apiKey();
}

View File

@ -0,0 +1,122 @@
package io.papermc.paper.registry.entry;
import com.google.common.base.Preconditions;
import io.papermc.paper.registry.PaperRegistryBuilder;
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 java.util.function.BiFunction;
import java.util.function.Supplier;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.Registry;
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 sealed interface RegistryEntryMeta<M, A extends Keyed> permits RegistryEntryMeta.ApiOnly, RegistryEntryMeta.ServerSide { // TODO remove Keyed
ResourceKey<? extends Registry<M>> mcKey();
RegistryKey<A> apiKey();
org.bukkit.Registry<A> createApiRegistry(final Registry<M> nmsRegistry);
default RegistryModificationApiSupport modificationApiSupport() {
return RegistryModificationApiSupport.NONE;
}
record ApiOnly<M, A extends Keyed>(ResourceKey<? extends Registry<M>> mcKey, RegistryKey<A> apiKey, Supplier<org.bukkit.Registry<A>> registrySupplier) implements RegistryEntryMeta<M, A> { // TODO remove Keyed
@Override
public org.bukkit.Registry<A> createApiRegistry(final Registry<M> nmsRegistry) {
return this.registrySupplier.get();
}
}
sealed interface ServerSide<M, A extends Keyed> extends RegistryEntryMeta<M, A> permits RegistryEntryMeta.Craft, RegistryEntryMeta.Buildable { // TODO remove Keyed
Class<?> classToPreload();
RegistryTypeMapper<M, A> registryTypeMapper();
BiFunction<NamespacedKey, ApiVersion, NamespacedKey> serializationUpdater();
default org.bukkit.Registry<A> createApiRegistry(final Registry<M> nmsRegistry) {
return new CraftRegistry<>(this, nmsRegistry);
}
}
record Craft<M, A extends Keyed>(
ResourceKey<? extends Registry<M>> mcKey,
RegistryKey<A> apiKey,
Class<?> classToPreload,
RegistryTypeMapper<M, A> registryTypeMapper,
BiFunction<NamespacedKey, ApiVersion, NamespacedKey> serializationUpdater
) implements ServerSide<M, A> { // TODO remove Keyed
public Craft {
Preconditions.checkArgument(!classToPreload.getPackageName().startsWith("net.minecraft"), classToPreload + " should not be in the net.minecraft package as the class-to-preload");
}
}
enum RegistryModificationApiSupport {
/**
* Cannot add or modify values in the registry.
*/
NONE,
/**
* Can only add new values to the registry, not modify any values.
*/
ADDABLE,
/**
* Can mutate values being added to the registry
*/
MODIFIABLE,
/**
* Can mutate values and add new values.
*/
WRITABLE,
;
public boolean canAdd() {
return this != MODIFIABLE && this != NONE;
}
public boolean canModify() {
return this != ADDABLE && this != NONE;
}
}
record Buildable<M, A extends Keyed, B extends PaperRegistryBuilder<M, A>>( // TODO remove Keyed
ResourceKey<? extends Registry<M>> mcKey,
RegistryKey<A> apiKey,
Class<?> classToPreload,
RegistryTypeMapper<M, A> registryTypeMapper,
BiFunction<NamespacedKey, ApiVersion, NamespacedKey> serializationUpdater,
PaperRegistryBuilder.Filler<M, A, B> builderFiller,
RegistryModificationApiSupport modificationApiSupport
) implements ServerSide<M, A> {
public RegistryEntryAddEventImpl<A, B> createEntryAddEvent(final TypedKey<A> key, final B initialBuilder, final Conversions conversions) {
return new RegistryEntryAddEventImpl<>(key, initialBuilder, this.apiKey(), conversions);
}
public RegistryFreezeEventImpl<A, B> createFreezeEvent(final WritableCraftRegistry<M, A, B> writableRegistry, final Conversions conversions) {
return new RegistryFreezeEventImpl<>(this.apiKey(), writableRegistry.createApiWritableRegistry(conversions), conversions);
}
@Override
public org.bukkit.Registry<A> createApiRegistry(final Registry<M> nmsRegistry) {
if (this.modificationApiSupport.canAdd()) {
return new WritableCraftRegistry<>((MappedRegistry<M>) nmsRegistry, this);
} else {
return ServerSide.super.createApiRegistry(nmsRegistry);
}
}
}
}

View File

@ -1,25 +0,0 @@
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);
}
}

View File

@ -1,26 +1,20 @@
package io.papermc.paper.registry.legacy;
import io.papermc.paper.registry.RegistryHolder;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.entry.RegistryEntry;
import io.papermc.paper.registry.entry.RegistryEntryMeta;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import org.bukkit.Keyed;
public record DelayedRegistryEntry<M, T extends Keyed>(RegistryEntry<M, T> delegate) implements RegistryEntry<M, T> {
public record DelayedRegistryEntry<M, A extends Keyed>(RegistryEntry<M, A> delegate) implements RegistryEntry<M, A> {
@Override
public ResourceKey<? extends Registry<M>> mcKey() {
return this.delegate.mcKey();
public RegistryEntryMeta<M, A> meta() {
return this.delegate.meta();
}
@Override
public RegistryKey<T> apiKey() {
return this.delegate.apiKey();
}
@Override
public RegistryHolder<T> createRegistryHolder(final Registry<M> nmsRegistry) {
public RegistryHolder<A> createRegistryHolder(final Registry<M> nmsRegistry) {
return this.delegate.createRegistryHolder(nmsRegistry);
}
}

View File

@ -1,6 +1,7 @@
package org.bukkit.craftbukkit;
import com.google.common.base.Preconditions;
import io.papermc.paper.registry.entry.RegistryEntryMeta;
import io.papermc.paper.util.Holderable;
import java.util.HashMap;
import java.util.Iterator;
@ -97,7 +98,7 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
// Paper start - support direct Holders
final java.util.Optional<ResourceKey<M>> resourceKey = registry.getResourceKey(minecraft);
if (resourceKey.isEmpty() && bukkitRegistry instanceof final CraftRegistry<?, ?> craftRegistry && craftRegistry.supportsDirectHolders()) {
return ((CraftRegistry<B, M>) registry).convertDirectHolder(Holder.direct(minecraft));
return ((CraftRegistry<B, M>) bukkitRegistry).convertDirectHolder(Holder.direct(minecraft));
} else if (resourceKey.isEmpty()) {
throw new IllegalStateException(String.format("Cannot convert '%s' to bukkit representation, since it is not registered.", minecraft));
}
@ -207,6 +208,9 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
// Paper start - switch to Holder
this(bukkitClass, minecraftRegistry, new io.papermc.paper.registry.entry.RegistryTypeMapper<>(minecraftToBukkit), serializationUpdater);
}
public CraftRegistry(final RegistryEntryMeta.ServerSide<M, B> meta, final net.minecraft.core.Registry<M> minecraftRegistry) {
this(meta.classToPreload(), minecraftRegistry, meta.registryTypeMapper(), meta.serializationUpdater());
}
public CraftRegistry(Class<?> bukkitClass, net.minecraft.core.Registry<M> minecraftRegistry, io.papermc.paper.registry.entry.RegistryTypeMapper<M, B> minecraftToBukkit, BiFunction<NamespacedKey, ApiVersion, NamespacedKey> serializationUpdater) { // Paper - relax preload class
// Paper end - support Holders
this.bukkitClass = bukkitClass;

View File

@ -2,8 +2,7 @@ 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 io.papermc.paper.registry.entry.RegistryEntryMeta;
import java.util.Map;
import java.util.stream.Stream;
import net.minecraft.core.Registry;
@ -23,21 +22,17 @@ class RegistryBuilderTest {
static Stream<Arguments> registries() {
return PaperRegistries.REGISTRY_ENTRIES.stream()
.map(RegistryBuilderTest::possiblyUnwrap)
.filter(RegistryEntry.BuilderHolder.class::isInstance)
.map(RegistryEntry::meta)
.filter(RegistryEntryMeta.Buildable.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) {
<M, T extends Keyed> void testEquality(final RegistryEntryMeta.Buildable<M, T, ?> registryEntry) { // TODO remove Keyed
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();
final M built = registryEntry.builderFiller().fill(new Conversions(new RegistryOps.HolderLookupAdapter(RegistryHelper.getRegistry())), entry.getValue()).build();
assertEquals(entry.getValue(), built);
}
}