Add registry entry and builders

This commit is contained in:
Bjarne Koll 2024-06-13 23:45:32 +02:00
parent a1b891dd88
commit 45d04f9749
8 changed files with 477 additions and 3 deletions

View file

@ -0,0 +1,11 @@
--- a/net/minecraft/world/level/gameevent/GameEvent.java
+++ b/net/minecraft/world/level/gameevent/GameEvent.java
@@ -85,7 +85,7 @@
}
private static Holder.Reference<GameEvent> register(String id, int range) {
- return Registry.registerForHolder(BuiltInRegistries.GAME_EVENT, ResourceLocation.withDefaultNamespace(id), new GameEvent(range));
+ return io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerForHolderWithListeners(BuiltInRegistries.GAME_EVENT, ResourceLocation.withDefaultNamespace(id), new GameEvent(range)); // Paper - run with listeners
}
public static record Context(@Nullable Entity sourceEntity, @Nullable BlockState affectedState) {

View file

@ -2,6 +2,9 @@ package io.papermc.paper.registry;
import com.google.common.base.Preconditions;
import io.papermc.paper.adventure.PaperAdventure;
import io.papermc.paper.registry.data.PaperEnchantmentRegistryEntry;
import io.papermc.paper.registry.data.PaperGameEventRegistryEntry;
import io.papermc.paper.registry.data.PaperPaintingVariantRegistryEntry;
import io.papermc.paper.registry.entry.RegistryEntry;
import io.papermc.paper.registry.tag.TagKey;
import java.util.Collections;
@ -76,7 +79,7 @@ public final class PaperRegistries {
static {
REGISTRY_ENTRIES = List.of(
// built-ins
start(Registries.GAME_EVENT, RegistryKey.GAME_EVENT).craft(GameEvent.class, CraftGameEvent::new).build(),
start(Registries.GAME_EVENT, RegistryKey.GAME_EVENT).craft(GameEvent.class, CraftGameEvent::new).writable(PaperGameEventRegistryEntry.PaperBuilder::new),
start(Registries.STRUCTURE_TYPE, RegistryKey.STRUCTURE_TYPE).craft(StructureType.class, CraftStructureType::new).build(),
start(Registries.MOB_EFFECT, RegistryKey.MOB_EFFECT).craft(PotionEffectType.class, CraftPotionEffectType::new).build(),
start(Registries.BLOCK, RegistryKey.BLOCK).craft(BlockType.class, CraftBlockType::new).build(),
@ -98,10 +101,10 @@ 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).build().withSerializationUpdater(FieldRename.ENCHANTMENT_RENAME).delayed(),
start(Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT).craft(Enchantment.class, CraftEnchantment::new).writable(PaperEnchantmentRegistryEntry.PaperBuilder::new).withSerializationUpdater(FieldRename.ENCHANTMENT_RENAME).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).build().delayed(),
start(Registries.PAINTING_VARIANT, RegistryKey.PAINTING_VARIANT).craft(Art.class, CraftArt::new).writable(PaperPaintingVariantRegistryEntry.PaperBuilder::new).delayed(),
start(Registries.INSTRUMENT, RegistryKey.INSTRUMENT).craft(MusicInstrument.class, CraftMusicInstrument::new).build().delayed(),
// api-only

View file

@ -0,0 +1,229 @@
package io.papermc.paper.registry.data;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import io.papermc.paper.registry.PaperRegistryBuilder;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.TypedKey;
import io.papermc.paper.registry.data.util.Checks;
import io.papermc.paper.registry.data.util.Conversions;
import io.papermc.paper.registry.set.PaperRegistrySets;
import io.papermc.paper.registry.set.RegistryKeySet;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.OptionalInt;
import net.minecraft.core.HolderSet;
import net.minecraft.core.component.DataComponentMap;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.EquipmentSlotGroup;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.enchantment.Enchantment;
import org.bukkit.craftbukkit.CraftEquipmentSlot;
import org.bukkit.inventory.ItemType;
import org.jetbrains.annotations.Range;
import org.jspecify.annotations.Nullable;
import static io.papermc.paper.registry.data.util.Checks.asArgument;
import static io.papermc.paper.registry.data.util.Checks.asArgumentMin;
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
public class PaperEnchantmentRegistryEntry implements EnchantmentRegistryEntry {
// Top level
protected @Nullable Component description;
// Definition
protected @Nullable HolderSet<Item> supportedItems;
protected @Nullable HolderSet<Item> primaryItems;
protected OptionalInt weight = OptionalInt.empty();
protected OptionalInt maxLevel = OptionalInt.empty();
protected Enchantment.@Nullable Cost minimumCost;
protected Enchantment.@Nullable Cost maximumCost;
protected OptionalInt anvilCost = OptionalInt.empty();
protected @Nullable List<EquipmentSlotGroup> activeSlots;
// Exclusive
protected HolderSet<Enchantment> exclusiveWith = HolderSet.empty(); // Paper added default to empty.
// Effects
protected DataComponentMap effects;
protected final Conversions conversions;
public PaperEnchantmentRegistryEntry(
final Conversions conversions,
final @Nullable Enchantment internal
) {
this.conversions = conversions;
if (internal == null) {
this.effects = DataComponentMap.EMPTY;
return;
}
// top level
this.description = internal.description();
// definition
final Enchantment.EnchantmentDefinition definition = internal.definition();
this.supportedItems = definition.supportedItems();
this.primaryItems = definition.primaryItems().orElse(null);
this.weight = OptionalInt.of(definition.weight());
this.maxLevel = OptionalInt.of(definition.maxLevel());
this.minimumCost = definition.minCost();
this.maximumCost = definition.maxCost();
this.anvilCost = OptionalInt.of(definition.anvilCost());
this.activeSlots = definition.slots();
// exclusive
this.exclusiveWith = internal.exclusiveSet();
// effects
this.effects = internal.effects();
}
@Override
public net.kyori.adventure.text.Component description() {
return this.conversions.asAdventure(asConfigured(this.description, "description"));
}
@Override
public RegistryKeySet<ItemType> supportedItems() {
return PaperRegistrySets.convertToApi(RegistryKey.ITEM, asConfigured(this.supportedItems, "supportedItems"));
}
@Override
public @Nullable RegistryKeySet<ItemType> primaryItems() {
return this.primaryItems == null ? null : PaperRegistrySets.convertToApi(RegistryKey.ITEM, this.primaryItems);
}
@Override
public @Range(from = 1, to = 1024) int weight() {
return asConfigured(this.weight, "weight");
}
@Override
public @Range(from = 1, to = 255) int maxLevel() {
return asConfigured(this.maxLevel, "maxLevel");
}
@Override
public EnchantmentCost minimumCost() {
final Enchantment.Cost cost = asConfigured(this.minimumCost, "minimumCost");
return EnchantmentRegistryEntry.EnchantmentCost.of(cost.base(), cost.perLevelAboveFirst());
}
@Override
public EnchantmentCost maximumCost() {
final Enchantment.Cost cost = asConfigured(this.maximumCost, "maximumCost");
return EnchantmentRegistryEntry.EnchantmentCost.of(cost.base(), cost.perLevelAboveFirst());
}
@Override
public @Range(from = 0, to = Integer.MAX_VALUE) int anvilCost() {
return asConfigured(this.anvilCost, "anvilCost");
}
@Override
public List<org.bukkit.inventory.EquipmentSlotGroup> activeSlots() {
return Collections.unmodifiableList(Lists.transform(asConfigured(this.activeSlots, "activeSlots"), CraftEquipmentSlot::getSlot));
}
@Override
public RegistryKeySet<org.bukkit.enchantments.Enchantment> exclusiveWith() {
return PaperRegistrySets.convertToApi(RegistryKey.ENCHANTMENT, this.exclusiveWith);
}
public static final class PaperBuilder extends PaperEnchantmentRegistryEntry implements EnchantmentRegistryEntry.Builder,
PaperRegistryBuilder<Enchantment, org.bukkit.enchantments.Enchantment> {
public PaperBuilder(final Conversions conversions, final @Nullable Enchantment internal) {
super(conversions, internal);
}
@Override
public Builder description(final net.kyori.adventure.text.Component description) {
this.description = this.conversions.asVanilla(asArgument(description, "description"));
return this;
}
@Override
public Builder supportedItems(final RegistryKeySet<ItemType> supportedItems) {
this.supportedItems = PaperRegistrySets.convertToNms(Registries.ITEM, this.conversions.lookup(), asArgument(supportedItems, "supportedItems"));
return this;
}
@Override
public Builder primaryItems(final @Nullable RegistryKeySet<ItemType> primaryItems) {
this.primaryItems = primaryItems == null ? null : PaperRegistrySets.convertToNms(Registries.ITEM, this.conversions.lookup(), primaryItems);
return this;
}
@Override
public Builder weight(final @Range(from = 1, to = 1024) int weight) {
this.weight = OptionalInt.of(Checks.asArgumentRange(weight, "weight", 1, 1024));
return this;
}
@Override
public Builder maxLevel(final @Range(from = 1, to = 255) int maxLevel) {
this.maxLevel = OptionalInt.of(Checks.asArgumentRange(maxLevel, "maxLevel", 1, 255));
return this;
}
@Override
public Builder minimumCost(final EnchantmentCost minimumCost) {
final EnchantmentCost validCost = asArgument(minimumCost, "minimumCost");
this.minimumCost = Enchantment.dynamicCost(validCost.baseCost(), validCost.additionalPerLevelCost());
return this;
}
@Override
public Builder maximumCost(final EnchantmentCost maximumCost) {
final EnchantmentCost validCost = asArgument(maximumCost, "maximumCost");
this.maximumCost = Enchantment.dynamicCost(validCost.baseCost(), validCost.additionalPerLevelCost());
return this;
}
@Override
public Builder anvilCost(final @Range(from = 0, to = Integer.MAX_VALUE) int anvilCost) {
Preconditions.checkArgument(anvilCost >= 0, "anvilCost must be non-negative");
this.anvilCost = OptionalInt.of(asArgumentMin(anvilCost, "anvilCost", 0));
return this;
}
@Override
public Builder activeSlots(final Iterable<org.bukkit.inventory.EquipmentSlotGroup> activeSlots) {
this.activeSlots = Lists.newArrayList(Iterables.transform(asArgument(activeSlots, "activeSlots"), CraftEquipmentSlot::getNMSGroup));
return this;
}
@Override
public Builder exclusiveWith(final RegistryKeySet<org.bukkit.enchantments.Enchantment> exclusiveWith) {
this.exclusiveWith = PaperRegistrySets.convertToNms(Registries.ENCHANTMENT, this.conversions.lookup(), asArgument(exclusiveWith, "exclusiveWith"));
return this;
}
@Override
public Enchantment build() {
final Enchantment.EnchantmentDefinition def = new Enchantment.EnchantmentDefinition(
asConfigured(this.supportedItems, "supportedItems"),
Optional.ofNullable(this.primaryItems),
this.weight(),
this.maxLevel(),
asConfigured(this.minimumCost, "minimumCost"),
asConfigured(this.maximumCost, "maximumCost"),
this.anvilCost(),
Collections.unmodifiableList(asConfigured(this.activeSlots, "activeSlots"))
);
return new Enchantment(
asConfigured(this.description, "description"),
def,
this.exclusiveWith,
this.effects
);
}
}
}

View file

@ -0,0 +1,52 @@
package io.papermc.paper.registry.data;
import io.papermc.paper.registry.PaperRegistryBuilder;
import io.papermc.paper.registry.data.util.Conversions;
import java.util.OptionalInt;
import net.minecraft.world.level.gameevent.GameEvent;
import org.jetbrains.annotations.Range;
import org.jspecify.annotations.Nullable;
import static io.papermc.paper.registry.data.util.Checks.asArgumentMin;
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
public class PaperGameEventRegistryEntry implements GameEventRegistryEntry {
protected OptionalInt range = OptionalInt.empty();
public PaperGameEventRegistryEntry(
final Conversions ignoredConversions,
final @Nullable GameEvent internal
) {
if (internal == null) return;
this.range = OptionalInt.of(internal.notificationRadius());
}
@Override
public @Range(from = 0, to = Integer.MAX_VALUE) int range() {
return asConfigured(this.range, "range");
}
public static final class PaperBuilder extends PaperGameEventRegistryEntry implements GameEventRegistryEntry.Builder,
PaperRegistryBuilder<GameEvent, org.bukkit.GameEvent> {
public PaperBuilder(
final Conversions conversions,
final @Nullable GameEvent internal
) {
super(conversions, internal);
}
@Override
public GameEventRegistryEntry.Builder range(final @Range(from = 0, to = Integer.MAX_VALUE) int range) {
this.range = OptionalInt.of(asArgumentMin(range, "range", 0));
return this;
}
@Override
public GameEvent build() {
return new GameEvent(this.range());
}
}
}

View file

@ -0,0 +1,116 @@
package io.papermc.paper.registry.data;
import io.papermc.paper.adventure.PaperAdventure;
import io.papermc.paper.registry.PaperRegistryBuilder;
import io.papermc.paper.registry.data.util.Conversions;
import java.util.Optional;
import java.util.OptionalInt;
import net.kyori.adventure.key.Key;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.decoration.PaintingVariant;
import org.bukkit.Art;
import org.jetbrains.annotations.Range;
import org.jspecify.annotations.Nullable;
import static io.papermc.paper.registry.data.util.Checks.asArgument;
import static io.papermc.paper.registry.data.util.Checks.asArgumentRange;
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
public class PaperPaintingVariantRegistryEntry implements PaintingVariantRegistryEntry {
protected OptionalInt width = OptionalInt.empty();
protected OptionalInt height = OptionalInt.empty();
protected @Nullable Component title;
protected @Nullable Component author;
protected @Nullable ResourceLocation assetId;
protected final Conversions conversions;
public PaperPaintingVariantRegistryEntry(
final Conversions conversions,
final @Nullable PaintingVariant internal
) {
this.conversions = conversions;
if (internal == null) return;
this.width = OptionalInt.of(internal.width());
this.height = OptionalInt.of(internal.height());
this.title = internal.title().orElse(null);
this.author = internal.author().orElse(null);
this.assetId = internal.assetId();
}
@Override
public @Range(from = 1, to = 16) int width() {
return asConfigured(this.width, "width");
}
@Override
public @Range(from = 1, to = 16) int height() {
return asConfigured(this.height, "height");
}
@Override
public net.kyori.adventure.text.@Nullable Component title() {
return this.title == null ? null : this.conversions.asAdventure(this.title);
}
@Override
public net.kyori.adventure.text.@Nullable Component author() {
return this.author == null ? null : this.conversions.asAdventure(this.author);
}
@Override
public Key assetId() {
return PaperAdventure.asAdventure(asConfigured(this.assetId, "assetId"));
}
public static final class PaperBuilder extends PaperPaintingVariantRegistryEntry implements PaintingVariantRegistryEntry.Builder, PaperRegistryBuilder<PaintingVariant, Art> {
public PaperBuilder(final Conversions conversions, final @Nullable PaintingVariant internal) {
super(conversions, internal);
}
@Override
public Builder width(final @Range(from = 1, to = 16) int width) {
this.width = OptionalInt.of(asArgumentRange(width, "width", 1, 16));
return this;
}
@Override
public Builder height(final @Range(from = 1, to = 16) int height) {
this.height = OptionalInt.of(asArgumentRange(height, "height", 1, 16));
return this;
}
@Override
public Builder title(final net.kyori.adventure.text.@Nullable Component title) {
this.title = this.conversions.asVanilla(title);
return this;
}
@Override
public Builder author(final net.kyori.adventure.text.@Nullable Component author) {
this.author = this.conversions.asVanilla(author);
return this;
}
@Override
public Builder assetId(final Key assetId) {
this.assetId = PaperAdventure.asVanilla(asArgument(assetId, "assetId"));
return this;
}
@Override
public PaintingVariant build() {
return new PaintingVariant(
this.width(),
this.height(),
asConfigured(this.assetId, "assetId"),
Optional.ofNullable(this.title),
Optional.ofNullable(this.author)
);
}
}
}

View file

@ -0,0 +1,4 @@
@NullMarked
package io.papermc.paper.registry.data;
import org.jspecify.annotations.NullMarked;

View file

@ -0,0 +1,45 @@
package io.papermc.paper.registry.data.util;
import java.util.OptionalInt;
import org.jspecify.annotations.Nullable;
public final class Checks {
public static <T> T asConfigured(final @Nullable T value, final String field) {
if (value == null) {
throw new IllegalStateException(field + " has not been configured");
}
return value;
}
public static int asConfigured(final OptionalInt value, final String field) {
if (value.isEmpty()) {
throw new IllegalStateException(field + " has not been configured");
}
return value.getAsInt();
}
public static <T> T asArgument(final @Nullable T value, final String field) {
if (value == null) {
throw new IllegalArgumentException("argument " + field + " cannot be null");
}
return value;
}
public static int asArgumentRange(final int value, final String field, final int min, final int max) {
if (value < min || value > max) {
throw new IllegalArgumentException("argument " + field + " must be [" + min + ", " + max + "]");
}
return value;
}
public static int asArgumentMin(final int value, final String field, final int min) {
if (value < min) {
throw new IllegalArgumentException("argument " + field + " must be [" + min + ",+inf)");
}
return value;
}
private Checks() {
}
}

View file

@ -18,10 +18,12 @@ public class CraftGameEvent extends GameEvent implements Handleable<net.minecraf
}
private final NamespacedKey key;
private final net.minecraft.resources.ResourceKey<net.minecraft.world.level.gameevent.GameEvent> handleKey; // Paper
private final net.minecraft.world.level.gameevent.GameEvent handle;
public CraftGameEvent(NamespacedKey key, net.minecraft.world.level.gameevent.GameEvent handle) {
this.key = key;
this.handleKey = net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.GAME_EVENT, org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(key)); // Paper
this.handle = handle;
}
@ -30,6 +32,18 @@ public class CraftGameEvent extends GameEvent implements Handleable<net.minecraf
return this.handle;
}
// Paper start
@Override
public int getRange() {
return this.handle.notificationRadius();
}
@Override
public int getVibrationLevel() {
return net.minecraft.world.level.gameevent.vibrations.VibrationSystem.getGameEventFrequency(this.handleKey);
}
// Paper end
@NotNull
@Override
public NamespacedKey getKey() {