mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-28 15:30:19 +01:00
For new registry values, allow copying from existing (#11796)
Co-authored-by: Bjarne Koll <git@lynxplay.dev>
This commit is contained in:
parent
f51aa3e3e1
commit
af2812fb0f
8 changed files with 177 additions and 20 deletions
|
@ -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 #copyFrom(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 #copyFrom(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 copyFrom(TypedKey<T> key);
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
package io.papermc.paper.registry;
|
package io.papermc.paper.registry;
|
||||||
|
|
||||||
import io.papermc.paper.datacomponent.DataComponentType;
|
import io.papermc.paper.datacomponent.DataComponentType;
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import net.kyori.adventure.key.KeyPattern;
|
||||||
import net.kyori.adventure.key.Keyed;
|
import net.kyori.adventure.key.Keyed;
|
||||||
import org.bukkit.Art;
|
import org.bukkit.Art;
|
||||||
import org.bukkit.Fluid;
|
import org.bukkit.Fluid;
|
||||||
|
@ -200,4 +202,26 @@ public sealed interface RegistryKey<T> extends Keyed permits RegistryKeyImpl {
|
||||||
RegistryKey<Particle> PARTICLE_TYPE = create("particle_type");
|
RegistryKey<Particle> PARTICLE_TYPE = create("particle_type");
|
||||||
RegistryKey<PotionType> POTION = create("potion");
|
RegistryKey<PotionType> POTION = create("potion");
|
||||||
RegistryKey<MemoryKey<?>> MEMORY_MODULE_TYPE = create("memory_module_type");
|
RegistryKey<MemoryKey<?>> MEMORY_MODULE_TYPE = create("memory_module_type");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link TypedKey} for this registry given the typed key's key.
|
||||||
|
*
|
||||||
|
* @param key the key of the typed key.
|
||||||
|
* @return the constructed typed key.
|
||||||
|
*/
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
default TypedKey<T> typedKey(final Key key) {
|
||||||
|
return TypedKey.create(this, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link TypedKey} for this registry given the typed key's key.
|
||||||
|
*
|
||||||
|
* @param key the string representation of the key that will be passed to {@link Key#key(String)}.
|
||||||
|
* @return the constructed typed key.
|
||||||
|
*/
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
default TypedKey<T> typedKey(final @KeyPattern String key) {
|
||||||
|
return TypedKey.create(this, key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package io.papermc.paper.registry;
|
package io.papermc.paper.registry;
|
||||||
|
|
||||||
import net.kyori.adventure.key.Key;
|
import net.kyori.adventure.key.Key;
|
||||||
|
import net.kyori.adventure.key.KeyPattern;
|
||||||
import net.kyori.adventure.key.Keyed;
|
import net.kyori.adventure.key.Keyed;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jspecify.annotations.NullMarked;
|
import org.jspecify.annotations.NullMarked;
|
||||||
|
@ -42,4 +43,18 @@ public sealed interface TypedKey<T> extends Key permits TypedKeyImpl {
|
||||||
static <T> TypedKey<T> create(final RegistryKey<T> registryKey, final Key key) {
|
static <T> TypedKey<T> create(final RegistryKey<T> registryKey, final Key key) {
|
||||||
return new TypedKeyImpl<>(key, registryKey);
|
return new TypedKeyImpl<>(key, registryKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a typed key from a string and a registry key.
|
||||||
|
*
|
||||||
|
* @param registryKey the registry this key is for
|
||||||
|
* @param key the string version of a {@link Key} that will be passed to {@link Key#key(String)} for parsing.
|
||||||
|
* @param <T> value type
|
||||||
|
* @return a new key for the value key and registry key
|
||||||
|
* @see Key#key(String)
|
||||||
|
*/
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
static <T> TypedKey<T> create(final RegistryKey<T> registryKey, final @KeyPattern String key) {
|
||||||
|
return create(registryKey, Key.key(key));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,5 +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.registerWith(key, factory -> value.accept(factory.empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new value with the specified key. This will
|
||||||
|
* fire a {@link RegistryEntryAddEvent} for the new entry. The
|
||||||
|
* {@link RegistryBuilderFactory} lets you pre-fill a builder with
|
||||||
|
* an already-existing entry's properties.
|
||||||
|
*
|
||||||
|
* @param key the entry's key (must be unique from others)
|
||||||
|
* @param value a consumer of a builder factory
|
||||||
|
*/
|
||||||
|
void registerWith(TypedKey<T> key, Consumer<RegistryBuilderFactory<T, B>> value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23508,10 +23508,10 @@ index 3d3eec1db91cb47395f40c4f47aa77164ad42175..216f97207dac88cc1dc3df59c6ee8a62
|
||||||
+ // Paper end - optimise collisions
|
+ // Paper end - optimise collisions
|
||||||
}
|
}
|
||||||
diff --git a/net/minecraft/core/MappedRegistry.java b/net/minecraft/core/MappedRegistry.java
|
diff --git a/net/minecraft/core/MappedRegistry.java b/net/minecraft/core/MappedRegistry.java
|
||||||
index 47b1fafd91b39e73c4e9134b0b8048000fba108a..76994c1491221c06cca5405ba239e6ff642b19ed 100644
|
index 452c358c2cfa0c39e0b09853cd4a9a12c6ced65d..5f752603aa5611ce9d3dd44cc5b70c27ac46a86e 100644
|
||||||
--- a/net/minecraft/core/MappedRegistry.java
|
--- a/net/minecraft/core/MappedRegistry.java
|
||||||
+++ b/net/minecraft/core/MappedRegistry.java
|
+++ b/net/minecraft/core/MappedRegistry.java
|
||||||
@@ -50,6 +50,19 @@ public class MappedRegistry<T> implements WritableRegistry<T> {
|
@@ -51,6 +51,19 @@ public class MappedRegistry<T> implements WritableRegistry<T> {
|
||||||
return this.getTags();
|
return this.getTags();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23531,10 +23531,10 @@ index 47b1fafd91b39e73c4e9134b0b8048000fba108a..76994c1491221c06cca5405ba239e6ff
|
||||||
public MappedRegistry(ResourceKey<? extends Registry<T>> key, Lifecycle registryLifecycle) {
|
public MappedRegistry(ResourceKey<? extends Registry<T>> key, Lifecycle registryLifecycle) {
|
||||||
this(key, registryLifecycle, false);
|
this(key, registryLifecycle, false);
|
||||||
}
|
}
|
||||||
@@ -114,6 +127,7 @@ public class MappedRegistry<T> implements WritableRegistry<T> {
|
@@ -116,6 +129,7 @@ public class MappedRegistry<T> implements WritableRegistry<T> {
|
||||||
this.toId.put(value, size);
|
|
||||||
this.registrationInfos.put(key, registrationInfo);
|
this.registrationInfos.put(key, registrationInfo);
|
||||||
this.registryLifecycle = this.registryLifecycle.add(registrationInfo.lifecycle());
|
this.registryLifecycle = this.registryLifecycle.add(registrationInfo.lifecycle());
|
||||||
|
this.temporaryUnfrozenMap.put(key.location(), value); // Paper - support pre-filling in registry mod API
|
||||||
+ this.injectFluidRegister(key, value); // Paper - fluid method optimisations
|
+ this.injectFluidRegister(key, value); // Paper - fluid method optimisations
|
||||||
return reference;
|
return reference;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
--- a/net/minecraft/core/MappedRegistry.java
|
--- a/net/minecraft/core/MappedRegistry.java
|
||||||
+++ b/net/minecraft/core/MappedRegistry.java
|
+++ b/net/minecraft/core/MappedRegistry.java
|
||||||
@@ -33,11 +_,11 @@
|
@@ -33,17 +_,18 @@
|
||||||
public class MappedRegistry<T> implements WritableRegistry<T> {
|
public class MappedRegistry<T> implements WritableRegistry<T> {
|
||||||
private final ResourceKey<? extends Registry<T>> key;
|
private final ResourceKey<? extends Registry<T>> key;
|
||||||
private final ObjectList<Holder.Reference<T>> byId = new ObjectArrayList<>(256);
|
private final ObjectList<Holder.Reference<T>> byId = new ObjectArrayList<>(256);
|
||||||
|
@ -17,6 +17,29 @@
|
||||||
private Lifecycle registryLifecycle;
|
private Lifecycle registryLifecycle;
|
||||||
private final Map<TagKey<T>, HolderSet.Named<T>> frozenTags = new IdentityHashMap<>();
|
private final Map<TagKey<T>, HolderSet.Named<T>> frozenTags = new IdentityHashMap<>();
|
||||||
MappedRegistry.TagSet<T> allTags = MappedRegistry.TagSet.unbound();
|
MappedRegistry.TagSet<T> allTags = MappedRegistry.TagSet.unbound();
|
||||||
|
private boolean frozen;
|
||||||
|
@Nullable
|
||||||
|
private Map<T, Holder.Reference<T>> unregisteredIntrusiveHolders;
|
||||||
|
+ public final Map<ResourceLocation, T> temporaryUnfrozenMap = new HashMap<>(); // Paper - support pre-filling in registry mod API
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<HolderSet.Named<T>> listTags() {
|
||||||
|
@@ -114,6 +_,7 @@
|
||||||
|
this.toId.put(value, size);
|
||||||
|
this.registrationInfos.put(key, registrationInfo);
|
||||||
|
this.registryLifecycle = this.registryLifecycle.add(registrationInfo.lifecycle());
|
||||||
|
+ this.temporaryUnfrozenMap.put(key.location(), value); // Paper - support pre-filling in registry mod API
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -275,6 +_,7 @@
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
this.frozen = true;
|
||||||
|
+ this.temporaryUnfrozenMap.clear(); // Paper - support pre-filling in registry mod API
|
||||||
|
this.byValue.forEach((object, reference) -> reference.bindValue((T)object));
|
||||||
|
List<ResourceLocation> list = this.byKey
|
||||||
|
.entrySet()
|
||||||
@@ -509,4 +_,13 @@
|
@@ -509,4 +_,13 @@
|
||||||
|
|
||||||
Stream<HolderSet.Named<T>> getTags();
|
Stream<HolderSet.Named<T>> getTags();
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package io.papermc.paper.registry;
|
||||||
|
|
||||||
|
import io.papermc.paper.adventure.PaperAdventure;
|
||||||
|
import io.papermc.paper.registry.data.util.Conversions;
|
||||||
|
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 PaperRegistryBuilder.Filler<M, A, B> builderFiller;
|
||||||
|
private final Function<? super ResourceLocation, ? extends @Nullable M> existingValueGetter;
|
||||||
|
private @Nullable B builder;
|
||||||
|
|
||||||
|
public PaperRegistryBuilderFactory(final Conversions conversions, final PaperRegistryBuilder.Filler<M, A, B> builderFiller, final Function<? super ResourceLocation, ? extends @Nullable M> existingValueGetter) {
|
||||||
|
this.conversions = conversions;
|
||||||
|
this.builderFiller = builderFiller;
|
||||||
|
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.builderFiller.create(this.conversions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public B copyFrom(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.builderFiller.fill(this.conversions, existing);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,20 +2,15 @@ package io.papermc.paper.registry;
|
||||||
|
|
||||||
import com.mojang.serialization.Lifecycle;
|
import com.mojang.serialization.Lifecycle;
|
||||||
import io.papermc.paper.registry.data.util.Conversions;
|
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.RegistryEntryMeta;
|
||||||
import io.papermc.paper.registry.entry.RegistryTypeMapper;
|
|
||||||
import io.papermc.paper.registry.event.WritableRegistry;
|
import io.papermc.paper.registry.event.WritableRegistry;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.BiFunction;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import net.minecraft.core.MappedRegistry;
|
import net.minecraft.core.MappedRegistry;
|
||||||
import net.minecraft.core.RegistrationInfo;
|
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.NamespacedKey;
|
|
||||||
import org.bukkit.craftbukkit.CraftRegistry;
|
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> {
|
public class WritableCraftRegistry<M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> extends CraftRegistry<T, M> {
|
||||||
|
|
||||||
|
@ -33,16 +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 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 = this.newBuilder(conversions);
|
final PaperRegistryBuilderFactory<M, T, B> builderFactory = new PaperRegistryBuilderFactory<>(conversions, this.meta.builderFiller(), this.registry.temporaryUnfrozenMap::get);
|
||||||
value.accept(builder);
|
value.accept(builderFactory);
|
||||||
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
|
||||||
);
|
);
|
||||||
|
@ -52,10 +47,6 @@ public class WritableCraftRegistry<M, T extends Keyed, B extends PaperRegistryBu
|
||||||
return new ApiWritableRegistry(conversions);
|
return new ApiWritableRegistry(conversions);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected B newBuilder(final Conversions conversions) {
|
|
||||||
return this.meta.builderFiller().create(conversions);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ApiWritableRegistry implements WritableRegistry<T, B> {
|
public class ApiWritableRegistry implements WritableRegistry<T, B> {
|
||||||
|
|
||||||
private final Conversions conversions;
|
private final Conversions conversions;
|
||||||
|
@ -65,7 +56,7 @@ 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 registerWith(final TypedKey<T> key, final Consumer<RegistryBuilderFactory<T, B>> value) {
|
||||||
WritableCraftRegistry.this.register(key, value, this.conversions);
|
WritableCraftRegistry.this.register(key, value, this.conversions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue