use a RegistryBuilderFactory to standarize creating registry builders

This commit is contained in:
Jake Potrebic 2024-12-24 15:55:14 -08:00
parent 8551cb23b0
commit c7d0436d2b
No known key found for this signature in database
GPG key ID: 27CC63F7CBC866C7
4 changed files with 105 additions and 28 deletions

View file

@ -0,0 +1,39 @@
package io.papermc.paper.registry;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jspecify.annotations.NullMarked;
/**
* A factory to create a {@link RegistryBuilder} for a given {@link TypedKey}. For
* each instance of this class, once either {@link #empty()} or {@link #copyOf(TypedKey)}
* is called once, any future calls to either method will throw an {@link IllegalStateException}.
*
* @param <T> The type of the registry
* @param <B> The type of the registry builder
*/
@NullMarked
@ApiStatus.Experimental
@ApiStatus.NonExtendable
public interface RegistryBuilderFactory<T, B extends RegistryBuilder<T>> {
/**
* Creates a new empty {@link RegistryBuilder}.
*
* @return A new empty {@link RegistryBuilder}
* @throws IllegalStateException if this method or {@link #copyOf(TypedKey)}) has already been called once
*/
@Contract("-> new")
B empty();
/**
* Creates a new {@link RegistryBuilder} with the same properties as the given {@link TypedKey}.
*
* @param key The key to copy properties from
* @return A new {@link RegistryBuilder} with the same properties as the given key
* @throws IllegalStateException if this method or {@link #empty()} has already been called once
* @throws IllegalArgumentException if key doesn't exist
*/
@Contract("_ -> new")
B copyOf(TypedKey<T> key);
}

View file

@ -1,6 +1,7 @@
package io.papermc.paper.registry.event; package io.papermc.paper.registry.event;
import io.papermc.paper.registry.RegistryBuilder; import io.papermc.paper.registry.RegistryBuilder;
import io.papermc.paper.registry.RegistryBuilderFactory;
import io.papermc.paper.registry.TypedKey; import io.papermc.paper.registry.TypedKey;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
@ -24,18 +25,18 @@ public interface WritableRegistry<T, B extends RegistryBuilder<T>> {
* @param key the entry's key (must be unique from others) * @param key the entry's key (must be unique from others)
* @param value a consumer for the entry's builder * @param value a consumer for the entry's builder
*/ */
void register(TypedKey<T> key, Consumer<? super B> value); default void register(final TypedKey<T> key, final Consumer<? super B> value) {
this.factoryRegister(key, factory -> value.accept(factory.empty()));
}
/** /**
* Register a new value with the specified key. This will * Register a new value with the specified key. This will
* fire a {@link RegistryEntryAddEvent} for the new entry. The * fire a {@link RegistryEntryAddEvent} for the new entry. The
* builder in the consumer will be pre-filled with the values * {@link RegistryBuilderFactory} lets you pre-fill a builder with
* from the copyFrom key. * an already-existing entry's properties.
* *
* @param key the entry's key (must be unique from others) * @param key the entry's key (must be unique from others)
* @param copyFrom the key to copy values from (must already be registered) * @param value a consumer of a builder factory
* @param value a consumer for the entry's builder
* @throws IllegalArgumentException if copyFrom doesn't exist
*/ */
void register(TypedKey<T> key, TypedKey<T> copyFrom, Consumer<? super B> value); void factoryRegister(TypedKey<T> key, Consumer<RegistryBuilderFactory<T, B>> value);
} }

View file

@ -0,0 +1,52 @@
package io.papermc.paper.registry;
import io.papermc.paper.adventure.PaperAdventure;
import io.papermc.paper.registry.data.util.Conversions;
import io.papermc.paper.registry.entry.RegistryEntryMeta;
import java.util.function.Function;
import net.minecraft.resources.ResourceLocation;
import org.bukkit.Keyed;
import org.jspecify.annotations.Nullable;
public class PaperRegistryBuilderFactory<M, A extends Keyed, B extends PaperRegistryBuilder<M, A>> implements RegistryBuilderFactory<A, B> { // TODO remove Keyed
private final Conversions conversions;
private final RegistryEntryMeta.Buildable<M, A, B> meta;
private final Function<? super ResourceLocation, ? extends @Nullable M> existingValueGetter;
private @Nullable B builder;
public PaperRegistryBuilderFactory(final Conversions conversions, final RegistryEntryMeta.Buildable<M, A, B> meta, final Function<? super ResourceLocation, ? extends @Nullable M> existingValueGetter) {
this.conversions = conversions;
this.meta = meta;
this.existingValueGetter = existingValueGetter;
}
private void validate() {
if (this.builder != null) {
throw new IllegalStateException("Already created a builder");
}
}
public B requireBuilder() {
if (this.builder == null) {
throw new IllegalStateException("Builder not created yet");
}
return this.builder;
}
@Override
public B empty() {
this.validate();
return this.builder = this.meta.builderFiller().create(this.conversions);
}
@Override
public B copyOf(final TypedKey<A> key) {
this.validate();
final M existing = this.existingValueGetter.apply(PaperAdventure.asVanilla(key));
if (existing == null) {
throw new IllegalArgumentException("Key " + key + " doesn't exist");
}
return this.builder = this.meta.builderFiller().fill(this.conversions, existing);
}
}

View file

@ -1,8 +1,6 @@
package io.papermc.paper.registry; package io.papermc.paper.registry;
import com.google.common.base.Preconditions;
import com.mojang.serialization.Lifecycle; import com.mojang.serialization.Lifecycle;
import io.papermc.paper.adventure.PaperAdventure;
import io.papermc.paper.registry.data.util.Conversions; import io.papermc.paper.registry.data.util.Conversions;
import io.papermc.paper.registry.entry.RegistryEntryMeta; import io.papermc.paper.registry.entry.RegistryEntryMeta;
import io.papermc.paper.registry.event.WritableRegistry; import io.papermc.paper.registry.event.WritableRegistry;
@ -13,7 +11,6 @@ import net.minecraft.core.RegistrationInfo;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import org.bukkit.Keyed; import org.bukkit.Keyed;
import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftRegistry;
import org.jspecify.annotations.Nullable;
public class WritableCraftRegistry<M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> extends CraftRegistry<T, M> { public class WritableCraftRegistry<M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> extends CraftRegistry<T, M> {
@ -31,23 +28,16 @@ public class WritableCraftRegistry<M, T extends Keyed, B extends PaperRegistryBu
this.meta = meta; this.meta = meta;
} }
public void register(final TypedKey<T> key, final @Nullable TypedKey<T> copyFrom, final Consumer<? super B> value, final Conversions conversions) { public void register(final TypedKey<T> key, final Consumer<RegistryBuilderFactory<T, B>> value, final Conversions conversions) {
final ResourceKey<M> resourceKey = PaperRegistries.toNms(key); final ResourceKey<M> resourceKey = PaperRegistries.toNms(key);
this.registry.validateWrite(resourceKey); this.registry.validateWrite(resourceKey);
final B builder; final PaperRegistryBuilderFactory<M, T, B> builderFactory = new PaperRegistryBuilderFactory<>(conversions, this.meta, this.registry.temporaryUnfrozenMap::get);
if (copyFrom != null) { value.accept(builderFactory);
final M existing = this.registry.temporaryUnfrozenMap.get(PaperAdventure.asVanilla(copyFrom));
Preconditions.checkArgument(existing != null, "Cannot copy from unregistered key: %s", copyFrom);
builder = this.meta.builderFiller().fill(conversions, existing);
} else {
builder = this.meta.builderFiller().create(conversions);
}
value.accept(builder);
PaperRegistryListenerManager.INSTANCE.registerWithListeners( PaperRegistryListenerManager.INSTANCE.registerWithListeners(
this.registry, this.registry,
this.meta, this.meta,
resourceKey, resourceKey,
builder, builderFactory.requireBuilder(),
FROM_PLUGIN, FROM_PLUGIN,
conversions conversions
); );
@ -66,13 +56,8 @@ public class WritableCraftRegistry<M, T extends Keyed, B extends PaperRegistryBu
} }
@Override @Override
public void register(final TypedKey<T> key, final Consumer<? super B> value) { public void factoryRegister(final TypedKey<T> key, final Consumer<RegistryBuilderFactory<T, B>> value) {
WritableCraftRegistry.this.register(key, null, value, this.conversions); WritableCraftRegistry.this.register(key, value, this.conversions);
}
@Override
public void register(final TypedKey<T> key, final TypedKey<T> copyFrom, final Consumer<? super B> value) {
WritableCraftRegistry.this.register(key, copyFrom, value, this.conversions);
} }
} }
} }