Registry API for supported Mob Variants (#12417)

---------

Co-authored-by: Bjarne Koll <git@lynxplay.dev>
This commit is contained in:
Bert Towne
2025-05-06 16:13:00 -05:00
committed by GitHub
parent 753cff7c8a
commit e2da5d2f0a
20 changed files with 1027 additions and 14 deletions

View File

@ -0,0 +1,10 @@
--- a/net/minecraft/core/ClientAsset.java
+++ b/net/minecraft/core/ClientAsset.java
@@ -12,6 +_,6 @@
public static final StreamCodec<ByteBuf, ClientAsset> STREAM_CODEC = StreamCodec.composite(ResourceLocation.STREAM_CODEC, ClientAsset::id, ClientAsset::new);
public ClientAsset(ResourceLocation id) {
- this(id, id.withPath(string -> "textures/" + string + ".png"));
+ this(id, id.withPath(string -> "textures/" + string + ".png")); // Paper - diff on change - io.papermc.paper.registry.data.client.ClientAssetImpl#pathFromIdentifier
}
}

View File

@ -5,10 +5,16 @@ import io.papermc.paper.adventure.PaperAdventure;
import io.papermc.paper.datacomponent.DataComponentTypes;
import io.papermc.paper.datacomponent.PaperDataComponentType;
import io.papermc.paper.registry.data.PaperBannerPatternRegistryEntry;
import io.papermc.paper.registry.data.PaperCatTypeRegistryEntry;
import io.papermc.paper.registry.data.PaperChickenVariantRegistryEntry;
import io.papermc.paper.registry.data.PaperCowVariantRegistryEntry;
import io.papermc.paper.registry.data.PaperDamageTypeRegistryEntry;
import io.papermc.paper.registry.data.PaperEnchantmentRegistryEntry;
import io.papermc.paper.registry.data.PaperFrogVariantRegistryEntry;
import io.papermc.paper.registry.data.PaperGameEventRegistryEntry;
import io.papermc.paper.registry.data.PaperPaintingVariantRegistryEntry;
import io.papermc.paper.registry.data.PaperPigVariantRegistryEntry;
import io.papermc.paper.registry.data.PaperWolfVariantRegistryEntry;
import io.papermc.paper.registry.entry.RegistryEntry;
import io.papermc.paper.registry.entry.RegistryEntryMeta;
import io.papermc.paper.registry.tag.TagKey;
@ -111,18 +117,18 @@ public final class PaperRegistries {
start(Registries.TRIM_MATERIAL, RegistryKey.TRIM_MATERIAL).craft(TrimMaterial.class, CraftTrimMaterial::new, true).build().delayed(),
start(Registries.TRIM_PATTERN, RegistryKey.TRIM_PATTERN).craft(TrimPattern.class, CraftTrimPattern::new, true).build().delayed(),
start(Registries.DAMAGE_TYPE, RegistryKey.DAMAGE_TYPE).craft(DamageType.class, CraftDamageType::new).writable(PaperDamageTypeRegistryEntry.PaperBuilder::new).delayed(),
start(Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT).craft(Wolf.Variant.class, CraftWolf.CraftVariant::new).build().delayed(),
start(Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT).craft(Wolf.Variant.class, CraftWolf.CraftVariant::new).writable(PaperWolfVariantRegistryEntry.PaperBuilder::new).delayed(),
start(Registries.WOLF_SOUND_VARIANT, RegistryKey.WOLF_SOUND_VARIANT).craft(Wolf.SoundVariant.class, CraftWolf.CraftSoundVariant::new).build(),
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, true).writable(PaperBannerPatternRegistryEntry.PaperBuilder::new).delayed(),
start(Registries.PAINTING_VARIANT, RegistryKey.PAINTING_VARIANT).craft(Art.class, CraftArt::new, true).writable(PaperPaintingVariantRegistryEntry.PaperBuilder::new).delayed(),
start(Registries.INSTRUMENT, RegistryKey.INSTRUMENT).craft(MusicInstrument.class, CraftMusicInstrument::new, true).build().delayed(),
start(Registries.CAT_VARIANT, RegistryKey.CAT_VARIANT).craft(Cat.Type.class, CraftCat.CraftType::new).build().delayed(),
start(Registries.FROG_VARIANT, RegistryKey.FROG_VARIANT).craft(Frog.Variant.class, CraftFrog.CraftVariant::new).build().delayed(),
start(Registries.CHICKEN_VARIANT, RegistryKey.CHICKEN_VARIANT).craft(Chicken.Variant.class, CraftChicken.CraftVariant::new).build(),
start(Registries.COW_VARIANT, RegistryKey.COW_VARIANT).craft(Cow.Variant.class, CraftCow.CraftVariant::new).build(),
start(Registries.PIG_VARIANT, RegistryKey.PIG_VARIANT).craft(Pig.Variant.class, CraftPig.CraftVariant::new).build(),
start(Registries.CAT_VARIANT, RegistryKey.CAT_VARIANT).craft(Cat.Type.class, CraftCat.CraftType::new).writable(PaperCatTypeRegistryEntry.PaperBuilder::new).delayed(),
start(Registries.FROG_VARIANT, RegistryKey.FROG_VARIANT).craft(Frog.Variant.class, CraftFrog.CraftVariant::new).writable(PaperFrogVariantRegistryEntry.PaperBuilder::new).delayed(),
start(Registries.CHICKEN_VARIANT, RegistryKey.CHICKEN_VARIANT).craft(Chicken.Variant.class, CraftChicken.CraftVariant::new).writable(PaperChickenVariantRegistryEntry.PaperBuilder::new),
start(Registries.COW_VARIANT, RegistryKey.COW_VARIANT).craft(Cow.Variant.class, CraftCow.CraftVariant::new).writable(PaperCowVariantRegistryEntry.PaperBuilder::new),
start(Registries.PIG_VARIANT, RegistryKey.PIG_VARIANT).craft(Pig.Variant.class, CraftPig.CraftVariant::new).writable(PaperPigVariantRegistryEntry.PaperBuilder::new),
// api-only
start(Registries.ENTITY_TYPE, RegistryKey.ENTITY_TYPE).apiOnly(PaperSimpleRegistry::entityType),

View File

@ -0,0 +1,60 @@
package io.papermc.paper.registry.data;
import io.papermc.paper.registry.PaperRegistryBuilder;
import io.papermc.paper.registry.data.client.ClientTextureAsset;
import io.papermc.paper.registry.data.util.Conversions;
import net.minecraft.world.entity.animal.CatVariant;
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
import org.bukkit.entity.Cat;
import org.jspecify.annotations.Nullable;
import static io.papermc.paper.registry.data.util.Checks.asArgument;
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
public class PaperCatTypeRegistryEntry implements CatTypeRegistryEntry {
protected net.minecraft.core.@Nullable ClientAsset clientTextureAsset;
protected SpawnPrioritySelectors spawnConditions;
protected final Conversions conversions;
public PaperCatTypeRegistryEntry(
final Conversions conversions,
final @Nullable CatVariant internal
) {
this.conversions = conversions;
if (internal == null) {
this.spawnConditions = SpawnPrioritySelectors.EMPTY;
return;
}
this.clientTextureAsset = internal.assetInfo();
this.spawnConditions = internal.spawnConditions();
}
@Override
public ClientTextureAsset clientTextureAsset() {
return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset"));
}
public static final class PaperBuilder extends PaperCatTypeRegistryEntry implements Builder, PaperRegistryBuilder<CatVariant, Cat.Type> {
public PaperBuilder(final Conversions conversions, final @Nullable CatVariant internal) {
super(conversions, internal);
}
@Override
public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) {
this.clientTextureAsset = this.conversions.asVanilla(asArgument(clientTextureAsset, "clientTextureAsset"));
return this;
}
@Override
public CatVariant build() {
return new CatVariant(
asConfigured(this.clientTextureAsset, "clientTextureAsset"),
asConfigured(this.spawnConditions, "spawnConditions")
);
}
}
}

View File

@ -0,0 +1,80 @@
package io.papermc.paper.registry.data;
import io.papermc.paper.registry.PaperRegistryBuilder;
import io.papermc.paper.registry.data.client.ClientTextureAsset;
import io.papermc.paper.registry.data.util.Conversions;
import net.minecraft.world.entity.animal.ChickenVariant;
import net.minecraft.world.entity.variant.ModelAndTexture;
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
import org.bukkit.entity.Chicken;
import org.jspecify.annotations.Nullable;
import static io.papermc.paper.registry.data.util.Checks.asArgument;
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
public class PaperChickenVariantRegistryEntry implements ChickenVariantRegistryEntry {
protected ChickenVariant.@Nullable ModelType model;
protected net.minecraft.core.@Nullable ClientAsset clientTextureAsset;
protected SpawnPrioritySelectors spawnConditions;
protected final Conversions conversions;
public PaperChickenVariantRegistryEntry(
final Conversions conversions,
final @Nullable ChickenVariant internal
) {
this.conversions = conversions;
if (internal == null) {
this.spawnConditions = SpawnPrioritySelectors.EMPTY;
return;
}
this.clientTextureAsset = internal.modelAndTexture().asset();
this.model = internal.modelAndTexture().model();
this.spawnConditions = internal.spawnConditions();
}
@Override
public ClientTextureAsset clientTextureAsset() {
return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset"));
}
@Override
public Model model() {
return switch (asConfigured(this.model, "model")) {
case NORMAL -> Model.NORMAL;
case COLD -> Model.COLD;
};
}
public static final class PaperBuilder extends PaperChickenVariantRegistryEntry implements Builder, PaperRegistryBuilder<ChickenVariant, Chicken.Variant> {
public PaperBuilder(final Conversions conversions, final @Nullable ChickenVariant internal) {
super(conversions, internal);
}
@Override
public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) {
this.clientTextureAsset = this.conversions.asVanilla(asArgument(clientTextureAsset, "clientTextureAsset"));
return this;
}
@Override
public Builder model(final Model model) {
this.model = switch (asArgument(model, "model")) {
case NORMAL -> ChickenVariant.ModelType.NORMAL;
case COLD -> ChickenVariant.ModelType.COLD;
};
return this;
}
@Override
public ChickenVariant build() {
return new ChickenVariant(
new ModelAndTexture<>(asConfigured(this.model, "model"), asConfigured(this.clientTextureAsset, "clientTextureAsset")),
asConfigured(this.spawnConditions, "spawnConditions")
);
}
}
}

View File

@ -0,0 +1,82 @@
package io.papermc.paper.registry.data;
import io.papermc.paper.registry.PaperRegistryBuilder;
import io.papermc.paper.registry.data.client.ClientTextureAsset;
import io.papermc.paper.registry.data.util.Conversions;
import net.minecraft.world.entity.animal.CowVariant;
import net.minecraft.world.entity.variant.ModelAndTexture;
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
import org.bukkit.entity.Cow;
import org.jspecify.annotations.Nullable;
import static io.papermc.paper.registry.data.util.Checks.asArgument;
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
public class PaperCowVariantRegistryEntry implements CowVariantRegistryEntry {
protected CowVariant.@Nullable ModelType model = null;
protected net.minecraft.core.@Nullable ClientAsset clientTextureAsset = null;
protected SpawnPrioritySelectors spawnConditions;
protected final Conversions conversions;
public PaperCowVariantRegistryEntry(
final Conversions conversions,
final @Nullable CowVariant internal
) {
this.conversions = conversions;
if (internal == null) {
this.spawnConditions = SpawnPrioritySelectors.EMPTY;
return;
}
this.clientTextureAsset = internal.modelAndTexture().asset();
this.model = internal.modelAndTexture().model();
this.spawnConditions = internal.spawnConditions();
}
@Override
public ClientTextureAsset clientTextureAsset() {
return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset"));
}
@Override
public Model model() {
return switch (asConfigured(this.model, "model")) {
case NORMAL -> Model.NORMAL;
case COLD -> Model.COLD;
case WARM -> Model.WARM;
};
}
public static final class PaperBuilder extends PaperCowVariantRegistryEntry implements Builder, PaperRegistryBuilder<CowVariant, Cow.Variant> {
public PaperBuilder(final Conversions conversions, final @Nullable CowVariant internal) {
super(conversions, internal);
}
@Override
public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) {
this.clientTextureAsset = this.conversions.asVanilla(asArgument(clientTextureAsset, "clientTextureAsset"));
return this;
}
@Override
public Builder model(final Model model) {
this.model = switch (asArgument(model, "model")) {
case NORMAL -> CowVariant.ModelType.NORMAL;
case COLD -> CowVariant.ModelType.COLD;
case WARM -> CowVariant.ModelType.WARM;
};
return this;
}
@Override
public CowVariant build() {
return new CowVariant(
new ModelAndTexture<>(asConfigured(this.model, "model"), asConfigured(this.clientTextureAsset, "clientTextureAsset")),
this.spawnConditions
);
}
}
}

View File

@ -0,0 +1,60 @@
package io.papermc.paper.registry.data;
import io.papermc.paper.registry.PaperRegistryBuilder;
import io.papermc.paper.registry.data.client.ClientTextureAsset;
import io.papermc.paper.registry.data.util.Conversions;
import net.minecraft.world.entity.animal.frog.FrogVariant;
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
import org.bukkit.entity.Frog;
import org.jspecify.annotations.Nullable;
import static io.papermc.paper.registry.data.util.Checks.asArgument;
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
public class PaperFrogVariantRegistryEntry implements FrogVariantRegistryEntry {
protected net.minecraft.core.@Nullable ClientAsset clientTextureAsset;
protected SpawnPrioritySelectors spawnConditions;
protected final Conversions conversions;
public PaperFrogVariantRegistryEntry(
final Conversions conversions,
final @Nullable FrogVariant internal
) {
this.conversions = conversions;
if (internal == null) {
spawnConditions = SpawnPrioritySelectors.EMPTY;
return;
}
this.clientTextureAsset = internal.assetInfo();
this.spawnConditions = internal.spawnConditions();
}
@Override
public ClientTextureAsset clientTextureAsset() {
return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset"));
}
public static final class PaperBuilder extends PaperFrogVariantRegistryEntry implements Builder, PaperRegistryBuilder<FrogVariant, Frog.Variant> {
public PaperBuilder(final Conversions conversions, final @Nullable FrogVariant internal) {
super(conversions, internal);
}
@Override
public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) {
this.clientTextureAsset = this.conversions.asVanilla(asArgument(clientTextureAsset, "clientTextureAsset"));
return this;
}
@Override
public FrogVariant build() {
return new FrogVariant(
asConfigured(this.clientTextureAsset, "clientTextureAsset"),
asConfigured(this.spawnConditions, "spawnConditions")
);
}
}
}

View File

@ -0,0 +1,80 @@
package io.papermc.paper.registry.data;
import io.papermc.paper.registry.PaperRegistryBuilder;
import io.papermc.paper.registry.data.client.ClientTextureAsset;
import io.papermc.paper.registry.data.util.Conversions;
import net.minecraft.world.entity.animal.PigVariant;
import net.minecraft.world.entity.variant.ModelAndTexture;
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
import org.bukkit.entity.Pig;
import org.jspecify.annotations.Nullable;
import static io.papermc.paper.registry.data.util.Checks.asArgument;
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
public class PaperPigVariantRegistryEntry implements PigVariantRegistryEntry {
protected PigVariant.@Nullable ModelType model;
protected net.minecraft.core.@Nullable ClientAsset clientTextureAsset;
protected SpawnPrioritySelectors spawnConditions;
protected final Conversions conversions;
public PaperPigVariantRegistryEntry(
final Conversions conversions,
final @Nullable PigVariant internal
) {
this.conversions = conversions;
if (internal == null) {
spawnConditions = SpawnPrioritySelectors.EMPTY;
return;
}
this.clientTextureAsset = internal.modelAndTexture().asset();
this.model = internal.modelAndTexture().model();
this.spawnConditions = internal.spawnConditions();
}
@Override
public ClientTextureAsset clientTextureAsset() {
return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset"));
}
@Override
public Model model() {
return switch (asConfigured(this.model, "model")) {
case NORMAL -> Model.NORMAL;
case COLD -> Model.COLD;
};
}
public static final class PaperBuilder extends PaperPigVariantRegistryEntry implements Builder, PaperRegistryBuilder<PigVariant, Pig.Variant> {
public PaperBuilder(final Conversions conversions, final @Nullable PigVariant internal) {
super(conversions, internal);
}
@Override
public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) {
this.clientTextureAsset = this.conversions.asVanilla(asArgument(clientTextureAsset, "clientTextureAsset"));
return this;
}
@Override
public Builder model(final Model model) {
this.model = switch (asArgument(model, "model")) {
case NORMAL -> PigVariant.ModelType.NORMAL;
case COLD -> PigVariant.ModelType.COLD;
};
return this;
}
@Override
public PigVariant build() {
return new PigVariant(
new ModelAndTexture<>(asConfigured(this.model, "model"), asConfigured(this.clientTextureAsset, "clientTextureAsset")),
asConfigured(this.spawnConditions, "spawnConditions")
);
}
}
}

View File

@ -0,0 +1,90 @@
package io.papermc.paper.registry.data;
import io.papermc.paper.registry.PaperRegistryBuilder;
import io.papermc.paper.registry.data.client.ClientTextureAsset;
import io.papermc.paper.registry.data.util.Conversions;
import net.minecraft.world.entity.animal.wolf.WolfVariant;
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
import org.bukkit.entity.Wolf;
import org.jspecify.annotations.Nullable;
import static io.papermc.paper.registry.data.util.Checks.asArgument;
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
public class PaperWolfVariantRegistryEntry implements WolfVariantRegistryEntry {
protected net.minecraft.core.@Nullable ClientAsset angryClientTextureAsset;
protected net.minecraft.core.@Nullable ClientAsset wildClientTextureAsset;
protected net.minecraft.core.@Nullable ClientAsset tameClientTextureAsset;
protected SpawnPrioritySelectors spawnConditions;
protected final Conversions conversions;
public PaperWolfVariantRegistryEntry(
final Conversions conversions,
final @Nullable WolfVariant internal
) {
this.conversions = conversions;
if (internal == null) {
this.spawnConditions = SpawnPrioritySelectors.EMPTY;
return;
}
this.angryClientTextureAsset = internal.assetInfo().angry();
this.wildClientTextureAsset = internal.assetInfo().wild();
this.tameClientTextureAsset = internal.assetInfo().tame();
this.spawnConditions = internal.spawnConditions();
}
@Override
public ClientTextureAsset angryClientTextureAsset() {
return this.conversions.asBukkit(asConfigured(this.angryClientTextureAsset, "angryClientTextureAsset"));
}
@Override
public ClientTextureAsset wildClientTextureAsset() {
return this.conversions.asBukkit(asConfigured(this.wildClientTextureAsset, "wildClientTextureAsset"));
}
@Override
public ClientTextureAsset tameClientTextureAsset() {
return this.conversions.asBukkit(asConfigured(this.tameClientTextureAsset, "tameClientTextureAsset"));
}
public static final class PaperBuilder extends PaperWolfVariantRegistryEntry implements Builder, PaperRegistryBuilder<WolfVariant, Wolf.Variant> {
public PaperBuilder(final Conversions conversions, final @Nullable WolfVariant internal) {
super(conversions, internal);
}
@Override
public Builder angryClientTextureAsset(final ClientTextureAsset angryClientTextureAsset) {
this.angryClientTextureAsset = this.conversions.asVanilla(asArgument(angryClientTextureAsset, "angryClientTextureAsset"));
return this;
}
@Override
public Builder wildClientTextureAsset(final ClientTextureAsset wildClientTextureAsset) {
this.wildClientTextureAsset = this.conversions.asVanilla(asArgument(wildClientTextureAsset, "wildClientTextureAsset"));
return this;
}
@Override
public Builder tameClientTextureAsset(final ClientTextureAsset tameClientTextureAsset) {
this.tameClientTextureAsset = this.conversions.asVanilla(asArgument(tameClientTextureAsset, "tameClientTextureAsset"));
return this;
}
@Override
public WolfVariant build() {
return new WolfVariant(
new WolfVariant.AssetInfo(
asConfigured(this.wildClientTextureAsset, "wildClientTextureAsset"),
asConfigured(this.tameClientTextureAsset, "tameClientTextureAsset"),
asConfigured(this.angryClientTextureAsset, "angryClientTextureAsset")
),
asConfigured(this.spawnConditions, "spawnConditions")
);
}
}
}

View File

@ -2,8 +2,10 @@ package io.papermc.paper.registry.data.util;
import com.google.common.base.Preconditions;
import com.mojang.serialization.JavaOps;
import io.papermc.paper.adventure.PaperAdventure;
import io.papermc.paper.adventure.WrapperAwareSerializer;
import java.util.Optional;
import io.papermc.paper.registry.data.client.ClientTextureAsset;
import net.kyori.adventure.text.Component;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
@ -33,7 +35,6 @@ public class Conversions {
return globalInstance;
}
private final RegistryOps.RegistryInfoLookup lookup;
private final WrapperAwareSerializer serializer;
@ -55,4 +56,18 @@ public class Conversions {
public Component asAdventure(final net.minecraft.network.chat.@Nullable Component vanilla) {
return vanilla == null ? Component.empty() : this.serializer.deserialize(vanilla);
}
public ClientTextureAsset asBukkit(final net.minecraft.core.@Nullable ClientAsset clientTextureAsset) {
return clientTextureAsset == null ? null : ClientTextureAsset.clientTextureAsset(
PaperAdventure.asAdventure(clientTextureAsset.id()),
PaperAdventure.asAdventure(clientTextureAsset.texturePath())
);
}
public net.minecraft.core.ClientAsset asVanilla(final @Nullable ClientTextureAsset clientTextureAsset) {
return clientTextureAsset == null ? null : new net.minecraft.core.ClientAsset(
PaperAdventure.asVanilla(clientTextureAsset.identifier()),
PaperAdventure.asVanilla(clientTextureAsset.texturePath())
);
}
}