From ceefdf7bfbddb76ce5e8bb6b744e4343395ad1a7 Mon Sep 17 00:00:00 2001 From: roro1506HD Date: Fri, 28 Nov 2025 23:39:57 +0100 Subject: [PATCH 01/15] wip: reworked DataComponentAdapters to be more generic and usable in multiple places --- .../datacomponent/DataComponentAdapters.java | 250 ------------------ .../datacomponent/PaperDataComponentType.java | 212 ++++++++++++++- .../PaperDataComponentTypeCollector.java | 27 ++ .../typed/AbstractTypedDataCollector.java | 75 ++++++ .../data/typed/PaperTypedDataAdapter.java} | 15 +- .../data/typed/PaperTypedDataAdapters.java | 49 ++++ .../data/typed/PaperTypedDataCollector.java | 26 ++ .../registry/data/typed/package-info.java | 4 + 8 files changed, 390 insertions(+), 268 deletions(-) delete mode 100644 paper-server/src/main/java/io/papermc/paper/datacomponent/DataComponentAdapters.java create mode 100644 paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentTypeCollector.java create mode 100644 paper-server/src/main/java/io/papermc/paper/registry/data/typed/AbstractTypedDataCollector.java rename paper-server/src/main/java/io/papermc/paper/{datacomponent/DataComponentAdapter.java => registry/data/typed/PaperTypedDataAdapter.java} (69%) create mode 100644 paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapters.java create mode 100644 paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataCollector.java create mode 100644 paper-server/src/main/java/io/papermc/paper/registry/data/typed/package-info.java diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/DataComponentAdapters.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/DataComponentAdapters.java deleted file mode 100644 index f6783d5f9279..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/DataComponentAdapters.java +++ /dev/null @@ -1,250 +0,0 @@ -package io.papermc.paper.datacomponent; - -import io.papermc.paper.adventure.PaperAdventure; -import io.papermc.paper.datacomponent.item.PaperAttackRange; -import io.papermc.paper.datacomponent.item.PaperBannerPatternLayers; -import io.papermc.paper.datacomponent.item.PaperBlockItemDataProperties; -import io.papermc.paper.datacomponent.item.PaperBlocksAttacks; -import io.papermc.paper.datacomponent.item.PaperBundleContents; -import io.papermc.paper.datacomponent.item.PaperChargedProjectiles; -import io.papermc.paper.datacomponent.item.PaperConsumable; -import io.papermc.paper.datacomponent.item.PaperCustomModelData; -import io.papermc.paper.datacomponent.item.PaperDamageResistant; -import io.papermc.paper.datacomponent.item.PaperDeathProtection; -import io.papermc.paper.datacomponent.item.PaperDyedItemColor; -import io.papermc.paper.datacomponent.item.PaperEnchantable; -import io.papermc.paper.datacomponent.item.PaperEquippable; -import io.papermc.paper.datacomponent.item.PaperFireworks; -import io.papermc.paper.datacomponent.item.PaperFoodProperties; -import io.papermc.paper.datacomponent.item.PaperItemAdventurePredicate; -import io.papermc.paper.datacomponent.item.PaperItemArmorTrim; -import io.papermc.paper.datacomponent.item.PaperItemAttributeModifiers; -import io.papermc.paper.datacomponent.item.PaperItemContainerContents; -import io.papermc.paper.datacomponent.item.PaperItemEnchantments; -import io.papermc.paper.datacomponent.item.PaperItemLore; -import io.papermc.paper.datacomponent.item.PaperItemTool; -import io.papermc.paper.datacomponent.item.PaperJukeboxPlayable; -import io.papermc.paper.datacomponent.item.PaperKineticWeapon; -import io.papermc.paper.datacomponent.item.PaperLodestoneTracker; -import io.papermc.paper.datacomponent.item.PaperMapDecorations; -import io.papermc.paper.datacomponent.item.PaperMapId; -import io.papermc.paper.datacomponent.item.PaperMapItemColor; -import io.papermc.paper.datacomponent.item.PaperOminousBottleAmplifier; -import io.papermc.paper.datacomponent.item.PaperPiercingWeapon; -import io.papermc.paper.datacomponent.item.PaperPotDecorations; -import io.papermc.paper.datacomponent.item.PaperPotionContents; -import io.papermc.paper.datacomponent.item.PaperRepairable; -import io.papermc.paper.datacomponent.item.PaperResolvableProfile; -import io.papermc.paper.datacomponent.item.PaperSeededContainerLoot; -import io.papermc.paper.datacomponent.item.PaperSuspiciousStewEffects; -import io.papermc.paper.datacomponent.item.PaperSwingAnimation; -import io.papermc.paper.datacomponent.item.PaperTooltipDisplay; -import io.papermc.paper.datacomponent.item.PaperUseCooldown; -import io.papermc.paper.datacomponent.item.PaperUseEffects; -import io.papermc.paper.datacomponent.item.PaperUseRemainder; -import io.papermc.paper.datacomponent.item.PaperWeapon; -import io.papermc.paper.datacomponent.item.PaperWritableBookContent; -import io.papermc.paper.datacomponent.item.PaperWrittenBookContent; -import io.papermc.paper.registry.PaperRegistries; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; -import net.minecraft.core.component.DataComponentType; -import net.minecraft.core.component.DataComponents; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.core.registries.Registries; -import net.minecraft.resources.ResourceKey; -import net.minecraft.util.Unit; -import net.minecraft.world.item.EitherHolder; -import net.minecraft.world.item.Rarity; -import net.minecraft.world.item.component.InstrumentComponent; -import net.minecraft.world.item.component.MapPostProcessing; -import net.minecraft.world.item.component.ProvidesTrimMaterial; -import org.bukkit.DyeColor; -import org.bukkit.craftbukkit.CraftArt; -import org.bukkit.craftbukkit.CraftMusicInstrument; -import org.bukkit.craftbukkit.CraftRegistry; -import org.bukkit.craftbukkit.damage.CraftDamageType; -import org.bukkit.craftbukkit.entity.CraftCat; -import org.bukkit.craftbukkit.entity.CraftChicken; -import org.bukkit.craftbukkit.entity.CraftCow; -import org.bukkit.craftbukkit.entity.CraftFrog; -import org.bukkit.craftbukkit.entity.CraftPig; -import org.bukkit.craftbukkit.entity.CraftVillager; -import org.bukkit.craftbukkit.entity.CraftWolf; -import org.bukkit.craftbukkit.entity.CraftZombieNautilus; -import org.bukkit.craftbukkit.inventory.CraftMetaFirework; -import org.bukkit.craftbukkit.inventory.trim.CraftTrimMaterial; -import org.bukkit.craftbukkit.util.Handleable; -import org.bukkit.entity.Axolotl; -import org.bukkit.entity.Horse; -import org.bukkit.entity.Llama; -import org.bukkit.entity.MushroomCow; -import org.bukkit.entity.Parrot; -import org.bukkit.entity.Rabbit; -import org.bukkit.entity.Salmon; -import org.bukkit.entity.TropicalFish; -import org.bukkit.inventory.ItemRarity; - -import static io.papermc.paper.util.MCUtil.transformUnmodifiable; - -public final class DataComponentAdapters { - - static final Function UNIT_TO_API_CONVERTER = $ -> { - throw new UnsupportedOperationException("Cannot convert the Unit type to an API value"); - }; - - static final Function UNIMPLEMENTED_TO_API_CONVERTER = $ -> { - throw new UnsupportedOperationException("Cannot convert the an unimplemented type to an API value"); - }; - - static final Map>, DataComponentAdapter> ADAPTERS = new HashMap<>(); - - public static void bootstrap() { - registerIdentity(DataComponents.MAX_STACK_SIZE); - registerIdentity(DataComponents.MAX_DAMAGE); - registerIdentity(DataComponents.DAMAGE); - registerUntyped(DataComponents.UNBREAKABLE); - register(DataComponents.USE_EFFECTS, PaperUseEffects::new); - registerIdentity(DataComponents.POTION_DURATION_SCALE); - register(DataComponents.CUSTOM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla); - registerIdentity(DataComponents.MINIMUM_ATTACK_CHARGE); - register(DataComponents.DAMAGE_TYPE, nms -> CraftDamageType.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftDamageType.bukkitToMinecraftHolder(api))); - register(DataComponents.ITEM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla); - register(DataComponents.ITEM_MODEL, PaperAdventure::asAdventure, PaperAdventure::asVanilla); - register(DataComponents.LORE, PaperItemLore::new); - register(DataComponents.RARITY, nms -> ItemRarity.valueOf(nms.name()), api -> Rarity.valueOf(api.name())); - register(DataComponents.ENCHANTMENTS, PaperItemEnchantments::new); - register(DataComponents.CAN_PLACE_ON, PaperItemAdventurePredicate::new); - register(DataComponents.CAN_BREAK, PaperItemAdventurePredicate::new); - register(DataComponents.ATTRIBUTE_MODIFIERS, PaperItemAttributeModifiers::new); - register(DataComponents.CUSTOM_MODEL_DATA, PaperCustomModelData::new); - registerIdentity(DataComponents.REPAIR_COST); - // registerUntyped(DataComponents.CREATIVE_SLOT_LOCK); - registerIdentity(DataComponents.ENCHANTMENT_GLINT_OVERRIDE); - registerUntyped(DataComponents.INTANGIBLE_PROJECTILE); - register(DataComponents.FOOD, PaperFoodProperties::new); - register(DataComponents.CONSUMABLE, PaperConsumable::new); - register(DataComponents.USE_REMAINDER, PaperUseRemainder::new); - register(DataComponents.USE_COOLDOWN, PaperUseCooldown::new); - register(DataComponents.DAMAGE_RESISTANT, PaperDamageResistant::new); - register(DataComponents.TOOL, PaperItemTool::new); - register(DataComponents.ENCHANTABLE, PaperEnchantable::new); - register(DataComponents.EQUIPPABLE, PaperEquippable::new); - register(DataComponents.REPAIRABLE, PaperRepairable::new); - registerUntyped(DataComponents.GLIDER); - register(DataComponents.TOOLTIP_STYLE, PaperAdventure::asAdventure, PaperAdventure::asVanilla); - register(DataComponents.DEATH_PROTECTION, PaperDeathProtection::new); - register(DataComponents.STORED_ENCHANTMENTS, PaperItemEnchantments::new); - register(DataComponents.DYED_COLOR, PaperDyedItemColor::new); - register(DataComponents.MAP_COLOR, PaperMapItemColor::new); - register(DataComponents.MAP_ID, PaperMapId::new); - register(DataComponents.MAP_DECORATIONS, PaperMapDecorations::new); - register(DataComponents.MAP_POST_PROCESSING, nms -> io.papermc.paper.item.MapPostProcessing.valueOf(nms.name()), api -> MapPostProcessing.valueOf(api.name())); - register(DataComponents.CHARGED_PROJECTILES, PaperChargedProjectiles::new); - register(DataComponents.BUNDLE_CONTENTS, PaperBundleContents::new); - register(DataComponents.POTION_CONTENTS, PaperPotionContents::new); - register(DataComponents.SUSPICIOUS_STEW_EFFECTS, PaperSuspiciousStewEffects::new); - register(DataComponents.WRITTEN_BOOK_CONTENT, PaperWrittenBookContent::new); - register(DataComponents.WRITABLE_BOOK_CONTENT, PaperWritableBookContent::new); - register(DataComponents.TRIM, PaperItemArmorTrim::new); - // debug stick state - // entity data - // bucket entity data - // block entity data - register(DataComponents.INSTRUMENT, nms -> CraftMusicInstrument.minecraftHolderToBukkit(nms.instrument().unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new InstrumentComponent(CraftMusicInstrument.bukkitToMinecraftHolder(api))); - register(DataComponents.PROVIDES_TRIM_MATERIAL, nms -> CraftTrimMaterial.minecraftHolderToBukkit(nms.material().unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new ProvidesTrimMaterial(CraftTrimMaterial.bukkitToMinecraftHolder(api))); - register(DataComponents.OMINOUS_BOTTLE_AMPLIFIER, PaperOminousBottleAmplifier::new); - register(DataComponents.JUKEBOX_PLAYABLE, PaperJukeboxPlayable::new); - register(DataComponents.PROVIDES_BANNER_PATTERNS, PaperRegistries::fromNms, PaperRegistries::toNms); - register( - DataComponents.RECIPES, - nms -> transformUnmodifiable(nms, PaperAdventure::asAdventureKey), - api -> transformUnmodifiable(api, key -> PaperAdventure.asVanilla(Registries.RECIPE, key)) - ); - register(DataComponents.LODESTONE_TRACKER, PaperLodestoneTracker::new); - register(DataComponents.FIREWORK_EXPLOSION, CraftMetaFirework::getEffect, CraftMetaFirework::getExplosion); - register(DataComponents.FIREWORKS, PaperFireworks::new); - register(DataComponents.PROFILE, PaperResolvableProfile::new); - register(DataComponents.NOTE_BLOCK_SOUND, PaperAdventure::asAdventure, PaperAdventure::asVanilla); - register(DataComponents.BANNER_PATTERNS, PaperBannerPatternLayers::new); - register(DataComponents.BASE_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); - register(DataComponents.POT_DECORATIONS, PaperPotDecorations::new); - register(DataComponents.CONTAINER, PaperItemContainerContents::new); - register(DataComponents.BLOCK_STATE, PaperBlockItemDataProperties::new); - // bees - // register(DataComponents.LOCK, PaperLockCode::new); - register(DataComponents.CONTAINER_LOOT, PaperSeededContainerLoot::new); - register(DataComponents.BREAK_SOUND, nms -> PaperAdventure.asAdventure(nms.value().location()), PaperAdventure::resolveSound); - register(DataComponents.TOOLTIP_DISPLAY, PaperTooltipDisplay::new); - register(DataComponents.WEAPON, PaperWeapon::new); - register(DataComponents.BLOCKS_ATTACKS, PaperBlocksAttacks::new); - register(DataComponents.PIERCING_WEAPON, PaperPiercingWeapon::new); - register(DataComponents.KINETIC_WEAPON, PaperKineticWeapon::new); - register(DataComponents.ATTACK_RANGE, PaperAttackRange::new); - register(DataComponents.SWING_ANIMATION, PaperSwingAnimation::new); - register(DataComponents.VILLAGER_VARIANT, CraftVillager.CraftType::minecraftHolderToBukkit, CraftVillager.CraftType::bukkitToMinecraftHolder); - register(DataComponents.WOLF_VARIANT, CraftWolf.CraftVariant::minecraftHolderToBukkit, CraftWolf.CraftVariant::bukkitToMinecraftHolder); - register(DataComponents.WOLF_COLLAR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); - register(DataComponents.WOLF_SOUND_VARIANT, CraftWolf.CraftSoundVariant::minecraftHolderToBukkit, CraftWolf.CraftSoundVariant::bukkitToMinecraftHolder); - register(DataComponents.FOX_VARIANT, nms -> org.bukkit.entity.Fox.Type.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.fox.Fox.Variant.byId(api.ordinal())); - register(DataComponents.SALMON_SIZE, nms -> Salmon.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.fish.Salmon.Variant.values()[api.ordinal()]); - register(DataComponents.PARROT_VARIANT, nms -> Parrot.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.parrot.Parrot.Variant.byId(api.ordinal())); - register(DataComponents.TROPICAL_FISH_PATTERN, nms -> TropicalFish.Pattern.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.fish.TropicalFish.Pattern.values()[api.ordinal()]); - register(DataComponents.TROPICAL_FISH_BASE_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); - register(DataComponents.TROPICAL_FISH_PATTERN_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); - register(DataComponents.MOOSHROOM_VARIANT, nms -> MushroomCow.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.cow.MushroomCow.Variant.values()[api.ordinal()]); - register(DataComponents.RABBIT_VARIANT, nms -> Rabbit.Type.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.rabbit.Rabbit.Variant.byId(api.ordinal())); - register(DataComponents.PIG_VARIANT, CraftPig.CraftVariant::minecraftHolderToBukkit, CraftPig.CraftVariant::bukkitToMinecraftHolder); - register(DataComponents.COW_VARIANT, CraftCow.CraftVariant::minecraftHolderToBukkit, CraftCow.CraftVariant::bukkitToMinecraftHolder); - register(DataComponents.CHICKEN_VARIANT, nms -> CraftChicken.CraftVariant.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftChicken.CraftVariant.bukkitToMinecraftHolder(api))); - register(DataComponents.FROG_VARIANT, CraftFrog.CraftVariant::minecraftHolderToBukkit, CraftFrog.CraftVariant::bukkitToMinecraftHolder); - register(DataComponents.ZOMBIE_NAUTILUS_VARIANT, nms -> CraftZombieNautilus.CraftVariant.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftZombieNautilus.CraftVariant.bukkitToMinecraftHolder(api))); - register(DataComponents.HORSE_VARIANT, nms -> Horse.Color.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.equine.Variant.byId(api.ordinal())); - register(DataComponents.PAINTING_VARIANT, CraftArt::minecraftHolderToBukkit, CraftArt::bukkitToMinecraftHolder); - register(DataComponents.LLAMA_VARIANT, nms -> Llama.Color.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.equine.Llama.Variant.byId(api.ordinal())); - register(DataComponents.AXOLOTL_VARIANT, nms -> Axolotl.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.axolotl.Axolotl.Variant.byId(api.ordinal())); - register(DataComponents.CAT_VARIANT, CraftCat.CraftType::minecraftHolderToBukkit, CraftCat.CraftType::bukkitToMinecraftHolder); - register(DataComponents.CAT_COLLAR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); - register(DataComponents.SHEEP_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); - register(DataComponents.SHULKER_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); - - for (final ResourceKey> key : BuiltInRegistries.DATA_COMPONENT_TYPE.registryKeySet()) { - if (!ADAPTERS.containsKey(key)) { - registerUnimplemented(key); - } - } - } - - private static ResourceKey> getKey(final DataComponentType type) { - return BuiltInRegistries.DATA_COMPONENT_TYPE.getResourceKey(type).orElseThrow(); - } - - public static void registerUntyped(final DataComponentType type) { - registerInternal(getKey(type), UNIT_TO_API_CONVERTER, DataComponentAdapter.API_TO_UNIT_CONVERTER, false); - } - - private static void registerIdentity(final DataComponentType type) { - registerInternal(getKey(type), Function.identity(), Function.identity(), true); - } - - @SuppressWarnings("unchecked") - public static void registerUnimplemented(final ResourceKey> key) { - registerInternal(key, UNIMPLEMENTED_TO_API_CONVERTER, DataComponentAdapter.API_TO_UNIMPLEMENTED_CONVERTER, false); - } - - private static > void register(final DataComponentType type, final Function vanillaToApi) { - registerInternal(getKey(type), vanillaToApi, Handleable::getHandle, false); - } - - private static void register(final DataComponentType type, final Function vanillaToApi, final Function apiToVanilla) { - registerInternal(getKey(type), vanillaToApi, apiToVanilla, false); - } - - private static void registerInternal(final ResourceKey> key, final Function vanillaToApi, final Function apiToVanilla, final boolean codecValidation) { - if (ADAPTERS.containsKey(key)) { - throw new IllegalStateException("Duplicate adapter registration for " + key); - } - ADAPTERS.put(key, new DataComponentAdapter<>(apiToVanilla, vanillaToApi, codecValidation)); - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java index f2a31526c56c..31eed72cbaca 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java @@ -1,20 +1,210 @@ package io.papermc.paper.datacomponent; +import io.papermc.paper.adventure.PaperAdventure; +import io.papermc.paper.datacomponent.item.PaperAttackRange; +import io.papermc.paper.datacomponent.item.PaperBannerPatternLayers; +import io.papermc.paper.datacomponent.item.PaperBlockItemDataProperties; +import io.papermc.paper.datacomponent.item.PaperBlocksAttacks; +import io.papermc.paper.datacomponent.item.PaperBundleContents; +import io.papermc.paper.datacomponent.item.PaperChargedProjectiles; +import io.papermc.paper.datacomponent.item.PaperConsumable; +import io.papermc.paper.datacomponent.item.PaperCustomModelData; +import io.papermc.paper.datacomponent.item.PaperDamageResistant; +import io.papermc.paper.datacomponent.item.PaperDeathProtection; +import io.papermc.paper.datacomponent.item.PaperDyedItemColor; +import io.papermc.paper.datacomponent.item.PaperEnchantable; +import io.papermc.paper.datacomponent.item.PaperEquippable; +import io.papermc.paper.datacomponent.item.PaperFireworks; +import io.papermc.paper.datacomponent.item.PaperFoodProperties; +import io.papermc.paper.datacomponent.item.PaperItemAdventurePredicate; +import io.papermc.paper.datacomponent.item.PaperItemArmorTrim; +import io.papermc.paper.datacomponent.item.PaperItemAttributeModifiers; +import io.papermc.paper.datacomponent.item.PaperItemContainerContents; +import io.papermc.paper.datacomponent.item.PaperItemEnchantments; +import io.papermc.paper.datacomponent.item.PaperItemLore; +import io.papermc.paper.datacomponent.item.PaperItemTool; +import io.papermc.paper.datacomponent.item.PaperJukeboxPlayable; +import io.papermc.paper.datacomponent.item.PaperKineticWeapon; +import io.papermc.paper.datacomponent.item.PaperLodestoneTracker; +import io.papermc.paper.datacomponent.item.PaperMapDecorations; +import io.papermc.paper.datacomponent.item.PaperMapId; +import io.papermc.paper.datacomponent.item.PaperMapItemColor; +import io.papermc.paper.datacomponent.item.PaperOminousBottleAmplifier; +import io.papermc.paper.datacomponent.item.PaperPiercingWeapon; +import io.papermc.paper.datacomponent.item.PaperPotDecorations; +import io.papermc.paper.datacomponent.item.PaperPotionContents; +import io.papermc.paper.datacomponent.item.PaperRepairable; +import io.papermc.paper.datacomponent.item.PaperResolvableProfile; +import io.papermc.paper.datacomponent.item.PaperSeededContainerLoot; +import io.papermc.paper.datacomponent.item.PaperSuspiciousStewEffects; +import io.papermc.paper.datacomponent.item.PaperSwingAnimation; +import io.papermc.paper.datacomponent.item.PaperTooltipDisplay; +import io.papermc.paper.datacomponent.item.PaperUseCooldown; +import io.papermc.paper.datacomponent.item.PaperUseEffects; +import io.papermc.paper.datacomponent.item.PaperUseRemainder; +import io.papermc.paper.datacomponent.item.PaperWeapon; +import io.papermc.paper.datacomponent.item.PaperWritableBookContent; +import io.papermc.paper.datacomponent.item.PaperWrittenBookContent; import io.papermc.paper.registry.HolderableBase; +import io.papermc.paper.registry.PaperRegistries; +import io.papermc.paper.registry.data.typed.PaperTypedDataAdapter; +import io.papermc.paper.registry.data.typed.PaperTypedDataAdapters; import java.util.Collections; import java.util.HashSet; import java.util.Set; import net.minecraft.core.Holder; import net.minecraft.core.component.DataComponentMap; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; +import net.minecraft.world.item.EitherHolder; +import net.minecraft.world.item.Rarity; +import net.minecraft.world.item.component.InstrumentComponent; +import net.minecraft.world.item.component.MapPostProcessing; +import net.minecraft.world.item.component.ProvidesTrimMaterial; +import org.bukkit.DyeColor; +import org.bukkit.craftbukkit.CraftArt; +import org.bukkit.craftbukkit.CraftMusicInstrument; import org.bukkit.craftbukkit.CraftRegistry; +import org.bukkit.craftbukkit.damage.CraftDamageType; +import org.bukkit.craftbukkit.entity.CraftCat; +import org.bukkit.craftbukkit.entity.CraftChicken; +import org.bukkit.craftbukkit.entity.CraftCow; +import org.bukkit.craftbukkit.entity.CraftFrog; +import org.bukkit.craftbukkit.entity.CraftPig; +import org.bukkit.craftbukkit.entity.CraftVillager; +import org.bukkit.craftbukkit.entity.CraftWolf; +import org.bukkit.craftbukkit.entity.CraftZombieNautilus; +import org.bukkit.craftbukkit.inventory.CraftMetaFirework; +import org.bukkit.craftbukkit.inventory.trim.CraftTrimMaterial; +import org.bukkit.entity.Axolotl; +import org.bukkit.entity.Horse; +import org.bukkit.entity.Llama; +import org.bukkit.entity.MushroomCow; +import org.bukkit.entity.Parrot; +import org.bukkit.entity.Rabbit; +import org.bukkit.entity.Salmon; +import org.bukkit.entity.TropicalFish; +import org.bukkit.inventory.ItemRarity; import org.jspecify.annotations.Nullable; +import static io.papermc.paper.util.MCUtil.transformUnmodifiable; + public abstract class PaperDataComponentType extends HolderableBase> implements DataComponentType { - static { - DataComponentAdapters.bootstrap(); - } + private static final PaperTypedDataAdapters ADAPTERS = PaperTypedDataAdapters.create( + BuiltInRegistries.DATA_COMPONENT_TYPE, + PaperDataComponentTypeCollector::new, + collector -> { + collector.registerIdentity(DataComponents.MAX_STACK_SIZE, net.minecraft.core.component.DataComponentType::codec); + collector.registerIdentity(DataComponents.MAX_DAMAGE, net.minecraft.core.component.DataComponentType::codec); + collector.registerIdentity(DataComponents.DAMAGE, net.minecraft.core.component.DataComponentType::codec); + collector.registerUntyped(DataComponents.UNBREAKABLE); + collector.register(DataComponents.USE_EFFECTS, PaperUseEffects::new); + collector.registerIdentity(DataComponents.POTION_DURATION_SCALE, net.minecraft.core.component.DataComponentType::codec); + collector.register(DataComponents.CUSTOM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla); + collector.registerIdentity(DataComponents.MINIMUM_ATTACK_CHARGE, net.minecraft.core.component.DataComponentType::codec); + collector.register(DataComponents.DAMAGE_TYPE, nms -> CraftDamageType.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftDamageType.bukkitToMinecraftHolder(api))); + collector.register(DataComponents.ITEM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla); + collector.register(DataComponents.ITEM_MODEL, PaperAdventure::asAdventure, PaperAdventure::asVanilla); + collector.register(DataComponents.LORE, PaperItemLore::new); + collector.register(DataComponents.RARITY, nms -> ItemRarity.valueOf(nms.name()), api -> Rarity.valueOf(api.name())); + collector.register(DataComponents.ENCHANTMENTS, PaperItemEnchantments::new); + collector.register(DataComponents.CAN_PLACE_ON, PaperItemAdventurePredicate::new); + collector.register(DataComponents.CAN_BREAK, PaperItemAdventurePredicate::new); + collector.register(DataComponents.ATTRIBUTE_MODIFIERS, PaperItemAttributeModifiers::new); + collector.register(DataComponents.CUSTOM_MODEL_DATA, PaperCustomModelData::new); + collector.registerIdentity(DataComponents.REPAIR_COST, net.minecraft.core.component.DataComponentType::codec); + // registerUntyped(DataComponents.CREATIVE_SLOT_LOCK); + collector.registerIdentity(DataComponents.ENCHANTMENT_GLINT_OVERRIDE, net.minecraft.core.component.DataComponentType::codec); + collector.registerUntyped(DataComponents.INTANGIBLE_PROJECTILE); + collector.register(DataComponents.FOOD, PaperFoodProperties::new); + collector.register(DataComponents.CONSUMABLE, PaperConsumable::new); + collector.register(DataComponents.USE_REMAINDER, PaperUseRemainder::new); + collector.register(DataComponents.USE_COOLDOWN, PaperUseCooldown::new); + collector.register(DataComponents.DAMAGE_RESISTANT, PaperDamageResistant::new); + collector.register(DataComponents.TOOL, PaperItemTool::new); + collector.register(DataComponents.ENCHANTABLE, PaperEnchantable::new); + collector.register(DataComponents.EQUIPPABLE, PaperEquippable::new); + collector.register(DataComponents.REPAIRABLE, PaperRepairable::new); + collector.registerUntyped(DataComponents.GLIDER); + collector.register(DataComponents.TOOLTIP_STYLE, PaperAdventure::asAdventure, PaperAdventure::asVanilla); + collector.register(DataComponents.DEATH_PROTECTION, PaperDeathProtection::new); + collector.register(DataComponents.STORED_ENCHANTMENTS, PaperItemEnchantments::new); + collector.register(DataComponents.DYED_COLOR, PaperDyedItemColor::new); + collector.register(DataComponents.MAP_COLOR, PaperMapItemColor::new); + collector.register(DataComponents.MAP_ID, PaperMapId::new); + collector.register(DataComponents.MAP_DECORATIONS, PaperMapDecorations::new); + collector.register(DataComponents.MAP_POST_PROCESSING, nms -> io.papermc.paper.item.MapPostProcessing.valueOf(nms.name()), api -> MapPostProcessing.valueOf(api.name())); + collector.register(DataComponents.CHARGED_PROJECTILES, PaperChargedProjectiles::new); + collector.register(DataComponents.BUNDLE_CONTENTS, PaperBundleContents::new); + collector.register(DataComponents.POTION_CONTENTS, PaperPotionContents::new); + collector.register(DataComponents.SUSPICIOUS_STEW_EFFECTS, PaperSuspiciousStewEffects::new); + collector.register(DataComponents.WRITTEN_BOOK_CONTENT, PaperWrittenBookContent::new); + collector.register(DataComponents.WRITABLE_BOOK_CONTENT, PaperWritableBookContent::new); + collector.register(DataComponents.TRIM, PaperItemArmorTrim::new); + // debug stick state + // entity data + // bucket entity data + // block entity data + collector.register(DataComponents.INSTRUMENT, nms -> CraftMusicInstrument.minecraftHolderToBukkit(nms.instrument().unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new InstrumentComponent(CraftMusicInstrument.bukkitToMinecraftHolder(api))); + collector.register(DataComponents.PROVIDES_TRIM_MATERIAL, nms -> CraftTrimMaterial.minecraftHolderToBukkit(nms.material().unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new ProvidesTrimMaterial(CraftTrimMaterial.bukkitToMinecraftHolder(api))); + collector.register(DataComponents.OMINOUS_BOTTLE_AMPLIFIER, PaperOminousBottleAmplifier::new); + collector.register(DataComponents.JUKEBOX_PLAYABLE, PaperJukeboxPlayable::new); + collector.register(DataComponents.PROVIDES_BANNER_PATTERNS, PaperRegistries::fromNms, PaperRegistries::toNms); + collector.register( + DataComponents.RECIPES, + nms -> transformUnmodifiable(nms, PaperAdventure::asAdventureKey), + api -> transformUnmodifiable(api, key -> PaperAdventure.asVanilla(Registries.RECIPE, key)) + ); + collector.register(DataComponents.LODESTONE_TRACKER, PaperLodestoneTracker::new); + collector.register(DataComponents.FIREWORK_EXPLOSION, CraftMetaFirework::getEffect, CraftMetaFirework::getExplosion); + collector.register(DataComponents.FIREWORKS, PaperFireworks::new); + collector.register(DataComponents.PROFILE, PaperResolvableProfile::new); + collector.register(DataComponents.NOTE_BLOCK_SOUND, PaperAdventure::asAdventure, PaperAdventure::asVanilla); + collector.register(DataComponents.BANNER_PATTERNS, PaperBannerPatternLayers::new); + collector.register(DataComponents.BASE_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); + collector.register(DataComponents.POT_DECORATIONS, PaperPotDecorations::new); + collector.register(DataComponents.CONTAINER, PaperItemContainerContents::new); + collector.register(DataComponents.BLOCK_STATE, PaperBlockItemDataProperties::new); + // bees + // register(DataComponents.LOCK, PaperLockCode::new); + collector.register(DataComponents.CONTAINER_LOOT, PaperSeededContainerLoot::new); + collector.register(DataComponents.BREAK_SOUND, nms -> PaperAdventure.asAdventure(nms.value().location()), PaperAdventure::resolveSound); + collector.register(DataComponents.TOOLTIP_DISPLAY, PaperTooltipDisplay::new); + collector.register(DataComponents.WEAPON, PaperWeapon::new); + collector.register(DataComponents.BLOCKS_ATTACKS, PaperBlocksAttacks::new); + collector.register(DataComponents.PIERCING_WEAPON, PaperPiercingWeapon::new); + collector.register(DataComponents.KINETIC_WEAPON, PaperKineticWeapon::new); + collector.register(DataComponents.ATTACK_RANGE, PaperAttackRange::new); + collector.register(DataComponents.SWING_ANIMATION, PaperSwingAnimation::new); + collector.register(DataComponents.VILLAGER_VARIANT, CraftVillager.CraftType::minecraftHolderToBukkit, CraftVillager.CraftType::bukkitToMinecraftHolder); + collector.register(DataComponents.WOLF_VARIANT, CraftWolf.CraftVariant::minecraftHolderToBukkit, CraftWolf.CraftVariant::bukkitToMinecraftHolder); + collector.register(DataComponents.WOLF_COLLAR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); + collector.register(DataComponents.WOLF_SOUND_VARIANT, CraftWolf.CraftSoundVariant::minecraftHolderToBukkit, CraftWolf.CraftSoundVariant::bukkitToMinecraftHolder); + collector.register(DataComponents.FOX_VARIANT, nms -> org.bukkit.entity.Fox.Type.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.fox.Fox.Variant.byId(api.ordinal())); + collector.register(DataComponents.SALMON_SIZE, nms -> Salmon.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.fish.Salmon.Variant.values()[api.ordinal()]); + collector.register(DataComponents.PARROT_VARIANT, nms -> Parrot.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.parrot.Parrot.Variant.byId(api.ordinal())); + collector.register(DataComponents.TROPICAL_FISH_PATTERN, nms -> TropicalFish.Pattern.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.fish.TropicalFish.Pattern.values()[api.ordinal()]); + collector.register(DataComponents.TROPICAL_FISH_BASE_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); + collector.register(DataComponents.TROPICAL_FISH_PATTERN_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); + collector.register(DataComponents.MOOSHROOM_VARIANT, nms -> MushroomCow.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.cow.MushroomCow.Variant.values()[api.ordinal()]); + collector.register(DataComponents.RABBIT_VARIANT, nms -> Rabbit.Type.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.rabbit.Rabbit.Variant.byId(api.ordinal())); + collector.register(DataComponents.PIG_VARIANT, CraftPig.CraftVariant::minecraftHolderToBukkit, CraftPig.CraftVariant::bukkitToMinecraftHolder); + collector.register(DataComponents.COW_VARIANT, CraftCow.CraftVariant::minecraftHolderToBukkit, CraftCow.CraftVariant::bukkitToMinecraftHolder); + collector.register(DataComponents.CHICKEN_VARIANT, nms -> CraftChicken.CraftVariant.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftChicken.CraftVariant.bukkitToMinecraftHolder(api))); + collector.register(DataComponents.FROG_VARIANT, CraftFrog.CraftVariant::minecraftHolderToBukkit, CraftFrog.CraftVariant::bukkitToMinecraftHolder); + collector.register(DataComponents.ZOMBIE_NAUTILUS_VARIANT, nms -> CraftZombieNautilus.CraftVariant.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftZombieNautilus.CraftVariant.bukkitToMinecraftHolder(api))); + collector.register(DataComponents.HORSE_VARIANT, nms -> Horse.Color.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.equine.Variant.byId(api.ordinal())); + collector.register(DataComponents.PAINTING_VARIANT, CraftArt::minecraftHolderToBukkit, CraftArt::bukkitToMinecraftHolder); + collector.register(DataComponents.LLAMA_VARIANT, nms -> Llama.Color.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.equine.Llama.Variant.byId(api.ordinal())); + collector.register(DataComponents.AXOLOTL_VARIANT, nms -> Axolotl.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.axolotl.Axolotl.Variant.byId(api.ordinal())); + collector.register(DataComponents.CAT_VARIANT, CraftCat.CraftType::minecraftHolderToBukkit, CraftCat.CraftType::bukkitToMinecraftHolder); + collector.register(DataComponents.CAT_COLLAR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); + collector.register(DataComponents.SHEEP_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); + collector.register(DataComponents.SHULKER_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); + } + ); public static net.minecraft.core.component.DataComponentType bukkitToMinecraft(final DataComponentType type) { return CraftRegistry.bukkitToMinecraft(type); @@ -41,9 +231,9 @@ public static Set minecraftToBukkit(final Set adapter; + private final PaperTypedDataAdapter adapter; - private PaperDataComponentType(final Holder> holder, final DataComponentAdapter adapter) { + private PaperDataComponentType(final Holder> holder, final PaperTypedDataAdapter adapter) { super(holder); this.adapter = adapter; } @@ -53,13 +243,13 @@ public boolean isPersistent() { return !this.getHandle().isTransient(); } - public DataComponentAdapter getAdapter() { + public PaperTypedDataAdapter getAdapter() { return this.adapter; } - @SuppressWarnings({"unchecked"}) + @SuppressWarnings("unchecked") public static DataComponentType of(final Holder holder) { - final DataComponentAdapter adapter = (DataComponentAdapter) DataComponentAdapters.ADAPTERS.get(holder.unwrapKey().orElseThrow()); + final PaperTypedDataAdapter< NMS, ?> adapter = PaperDataComponentType.ADAPTERS.getAdapter(holder.unwrapKey().orElseThrow()); if (adapter == null) { throw new IllegalArgumentException("No adapter found for " + holder); } @@ -76,7 +266,7 @@ public static final class NonValuedImpl extends PaperDataComponentType> holder, - final DataComponentAdapter adapter + final PaperTypedDataAdapter adapter ) { super(holder, adapter); } @@ -86,7 +276,7 @@ public static final class ValuedImpl extends PaperDataComponentType> holder, - final DataComponentAdapter adapter + final PaperTypedDataAdapter adapter ) { super(holder, adapter); } @@ -96,7 +286,7 @@ public static final class Unimplemented extends PaperDataComponentType> holder, - final DataComponentAdapter adapter + final PaperTypedDataAdapter adapter ) { super(holder, adapter); } diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentTypeCollector.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentTypeCollector.java new file mode 100644 index 000000000000..435231edc5ec --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentTypeCollector.java @@ -0,0 +1,27 @@ +package io.papermc.paper.datacomponent; + +import io.papermc.paper.registry.data.typed.AbstractTypedDataCollector; +import io.papermc.paper.registry.data.typed.PaperTypedDataAdapter; +import net.minecraft.core.Registry; +import net.minecraft.core.component.DataComponentType; +import net.minecraft.resources.ResourceKey; +import org.bukkit.craftbukkit.util.Handleable; +import java.util.Map; +import java.util.function.Function; + +class PaperDataComponentTypeCollector extends AbstractTypedDataCollector> { + + public PaperDataComponentTypeCollector(final Registry> registry, final Map, PaperTypedDataAdapter> adapters) { + super(registry, adapters); + } + + // Not using @Override because of generic types + public > void register(final DataComponentType dataComponentType, final Function vanillaToApi) { + super.register(dataComponentType, vanillaToApi); + } + + // Not using @Override because of generic types + public void register(final DataComponentType dataComponentType, final Function vanillaToApi, final Function apiToVanilla) { + super.register(dataComponentType, vanillaToApi, apiToVanilla); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/AbstractTypedDataCollector.java b/paper-server/src/main/java/io/papermc/paper/registry/data/typed/AbstractTypedDataCollector.java new file mode 100644 index 000000000000..e8bf7ad49b86 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/data/typed/AbstractTypedDataCollector.java @@ -0,0 +1,75 @@ +package io.papermc.paper.registry.data.typed; + +import com.mojang.serialization.Codec; +import java.util.Map; +import java.util.function.Function; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import org.bukkit.craftbukkit.util.Handleable; +import org.jspecify.annotations.Nullable; + +// This class exists only to be implemented, implementations must override the following register method: +// void register(final TYPE type, final Function vanillaToApi, final Function apiToVanilla) +// BUT should NOT use the @Override annotation, this is a hack around generics limitations to prevent +// having to define generics on each register call as seen below, making collectors easier to read: +// collector.register(...) +public abstract class AbstractTypedDataCollector implements PaperTypedDataCollector { + + private final Registry registry; + private final Map, PaperTypedDataAdapter> adapters; + + public AbstractTypedDataCollector(final Registry registry, final Map, PaperTypedDataAdapter> adapters) { + this.registry = registry; + this.adapters = adapters; + } + + @Override + public void registerUntyped(final TYPE type) { + this.registerInternal(this.getKey(type), PaperTypedDataAdapters.UNIT_TO_API_CONVERTER, PaperTypedDataAdapter.API_TO_UNIT_CONVERTER, null); + } + + @Override + public void registerIdentity(final TYPE type, final Function> codecGetter) { + this.registerInternal(this.getKey(type), Function.identity(), Function.identity(), codecGetter.apply(type)); + } + + @Override + public > void register(final TYPE type, final Function vanillaToApi) { + this.registerInternal(this.getKey(type), vanillaToApi, Handleable::getHandle, null); + } + + @Override + public void register(final TYPE type, final Function vanillaToApi, final Function apiToVanilla) { + this.registerInternal(this.getKey(type), vanillaToApi, apiToVanilla, null); + } + + private ResourceKey getKey(final TYPE type) { + return this.registry.getResourceKey(type).orElseThrow(); + } + + void registerUnimplemented() { + for (final ResourceKey key : this.registry.registryKeySet()) { + if (!this.adapters.containsKey(key)) { + this.registerUnimplemented(key); + } + } + } + + @SuppressWarnings("unchecked") + private void registerUnimplemented(final ResourceKey key) { + this.registerInternal(key, PaperTypedDataAdapters.UNIMPLEMENTED_TO_API_CONVERTER, PaperTypedDataAdapter.API_TO_UNIMPLEMENTED_CONVERTER, null); + } + + private void registerInternal( + final ResourceKey key, + final Function vanillaToApi, + final Function apiToVanilla, + final @Nullable Codec codec + ) { + if (this.adapters.containsKey(key)) { + throw new IllegalStateException("Duplicate adapter registration for " + key); + } + + this.adapters.put(key, new PaperTypedDataAdapter<>(apiToVanilla, vanillaToApi, codec)); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/DataComponentAdapter.java b/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapter.java similarity index 69% rename from paper-server/src/main/java/io/papermc/paper/datacomponent/DataComponentAdapter.java rename to paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapter.java index 15a96abb2ac7..eb978dfaa5cd 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/DataComponentAdapter.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapter.java @@ -1,16 +1,17 @@ -package io.papermc.paper.datacomponent; +package io.papermc.paper.registry.data.typed; +import com.mojang.serialization.Codec; import java.util.function.Function; import net.minecraft.core.Holder; -import net.minecraft.core.component.DataComponentType; import net.minecraft.util.NullOps; import net.minecraft.util.Unit; import org.bukkit.craftbukkit.CraftRegistry; +import org.jspecify.annotations.Nullable; -public record DataComponentAdapter( +public record PaperTypedDataAdapter( Function apiToVanilla, Function vanillaToApi, - boolean codecValidation + @Nullable Codec codec ) { static final Function API_TO_UNIT_CONVERTER = $ -> Unit.INSTANCE; @@ -26,10 +27,10 @@ public boolean isUnimplemented() { return this.apiToVanilla == API_TO_UNIMPLEMENTED_CONVERTER; } - public NMS toVanilla(final API value, final Holder> type) { + public NMS toVanilla(final API value, final Holder type) { final NMS nms = this.apiToVanilla.apply(value); - if (this.codecValidation && !type.value().isTransient()) { - type.value().codecOrThrow().encodeStart(CraftRegistry.getMinecraftRegistry().createSerializationContext(NullOps.INSTANCE), nms).ifError(error -> { + if (this.codec != null) { + this.codec.encodeStart(CraftRegistry.getMinecraftRegistry().createSerializationContext(NullOps.INSTANCE), nms).ifError(error -> { throw new IllegalArgumentException("Failed to encode data component %s (%s)".formatted(type.unwrapKey().orElseThrow(), error.message())); }); } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapters.java b/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapters.java new file mode 100644 index 000000000000..bc2f442981c0 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapters.java @@ -0,0 +1,49 @@ +package io.papermc.paper.registry.data.typed; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import net.minecraft.util.Unit; +import org.jspecify.annotations.Nullable; + +public final class PaperTypedDataAdapters { + + static final Function UNIT_TO_API_CONVERTER = $ -> { + throw new UnsupportedOperationException("Cannot convert the Unit type to an API value"); + }; + + static final Function UNIMPLEMENTED_TO_API_CONVERTER = $ -> { + throw new UnsupportedOperationException("Cannot convert the an unimplemented type to an API value"); + }; + + private final Map, PaperTypedDataAdapter> adapters; + + private PaperTypedDataAdapters(Map, PaperTypedDataAdapter> adapters) { + this.adapters = adapters; + } + + public static > PaperTypedDataAdapters create( + Registry registry, + PaperTypedDataCollector.Factory collectorFactory, + Consumer consumer + ) { + Map, PaperTypedDataAdapter> adapters = new HashMap<>(); + COLLECTOR collector = collectorFactory.create(registry, adapters); + + consumer.accept(collector); + + // Loop through every entry in the registry and register any entry + // not already registered as unimplemented + collector.registerUnimplemented(); + + return new PaperTypedDataAdapters(adapters); + } + + @SuppressWarnings("unchecked") + public @Nullable RETURN getAdapter(ResourceKey key) { + return (RETURN) this.adapters.get(key); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataCollector.java b/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataCollector.java new file mode 100644 index 000000000000..ed24fc910f58 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataCollector.java @@ -0,0 +1,26 @@ +package io.papermc.paper.registry.data.typed; + +import com.mojang.serialization.Codec; +import java.util.Map; +import java.util.function.Function; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import org.bukkit.craftbukkit.util.Handleable; +import org.jspecify.annotations.Nullable; + +public interface PaperTypedDataCollector { + + void registerUntyped(final TYPE type); + + void registerIdentity(final TYPE type, final Function> codecGetter); + + > void register(final TYPE type, final Function vanillaToApi); + + void register(final TYPE type, final Function vanillaToApi, final Function apiToVanilla); + + interface Factory { + + COLLECTOR create(Registry registry, Map, PaperTypedDataAdapter> adapters); + + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/package-info.java b/paper-server/src/main/java/io/papermc/paper/registry/data/typed/package-info.java new file mode 100644 index 000000000000..535e3cb038cd --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/data/typed/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.papermc.paper.registry.data.typed; + +import org.jspecify.annotations.NullMarked; From 9098d704a522e60db3466e463a46ec47ac40106b Mon Sep 17 00:00:00 2001 From: roro1506HD Date: Sat, 29 Nov 2025 17:36:18 +0100 Subject: [PATCH 02/15] wip: environmental attributes api --- .../keys/EnvironmentAttributeKeys.java | 349 ++++++++++++++++++ .../papermc/paper/registry/RegistryKey.java | 6 + .../attribute/EnvironmentalAttributeType.java | 14 + .../EnvironmentalAttributeTypes.java | 122 ++++++ .../generator/registry/RegistryEntries.java | 5 +- .../paper/adventure/PaperAdventure.java | 18 + .../paper/registry/PaperRegistries.java | 3 + .../PaperEnvironmentalAttributeType.java | 100 +++++ ...erEnvironmentalAttributeTypeCollector.java | 27 ++ 9 files changed, 643 insertions(+), 1 deletion(-) create mode 100644 paper-api/src/generated/java/io/papermc/paper/registry/keys/EnvironmentAttributeKeys.java create mode 100644 paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeType.java create mode 100644 paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeTypes.java create mode 100644 paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java create mode 100644 paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeTypeCollector.java diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/EnvironmentAttributeKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/EnvironmentAttributeKeys.java new file mode 100644 index 000000000000..f3c10d82ae0f --- /dev/null +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/EnvironmentAttributeKeys.java @@ -0,0 +1,349 @@ +package io.papermc.paper.registry.keys; + +import static net.kyori.adventure.key.Key.key; + +import io.papermc.paper.annotation.GeneratedClass; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import io.papermc.paper.world.attribute.EnvironmentalAttributeType; +import net.kyori.adventure.key.Key; +import org.jspecify.annotations.NullMarked; + +/** + * Vanilla keys for {@link RegistryKey#ENVIRONMENT_ATTRIBUTE}. + * + * @apiNote The fields provided here are a direct representation of + * what is available from the vanilla game source. They may be + * changed (including removals) on any Minecraft version + * bump, so cross-version compatibility is not provided on the + * same level as it is on most of the other API. + */ +@SuppressWarnings({ + "unused", + "SpellCheckingInspection" +}) +@NullMarked +@GeneratedClass +public final class EnvironmentAttributeKeys { + /** + * {@code minecraft:audio/ambient_sounds} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> AUDIO_AMBIENT_SOUNDS = create(key("audio/ambient_sounds")); + + /** + * {@code minecraft:audio/background_music} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> AUDIO_BACKGROUND_MUSIC = create(key("audio/background_music")); + + /** + * {@code minecraft:audio/firefly_bush_sounds} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> AUDIO_FIREFLY_BUSH_SOUNDS = create(key("audio/firefly_bush_sounds")); + + /** + * {@code minecraft:audio/music_volume} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> AUDIO_MUSIC_VOLUME = create(key("audio/music_volume")); + + /** + * {@code minecraft:gameplay/baby_villager_activity} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_BABY_VILLAGER_ACTIVITY = create(key("gameplay/baby_villager_activity")); + + /** + * {@code minecraft:gameplay/bed_rule} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_BED_RULE = create(key("gameplay/bed_rule")); + + /** + * {@code minecraft:gameplay/bees_stay_in_hive} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_BEES_STAY_IN_HIVE = create(key("gameplay/bees_stay_in_hive")); + + /** + * {@code minecraft:gameplay/can_pillager_patrol_spawn} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_CAN_PILLAGER_PATROL_SPAWN = create(key("gameplay/can_pillager_patrol_spawn")); + + /** + * {@code minecraft:gameplay/can_start_raid} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_CAN_START_RAID = create(key("gameplay/can_start_raid")); + + /** + * {@code minecraft:gameplay/cat_waking_up_gift_chance} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_CAT_WAKING_UP_GIFT_CHANCE = create(key("gameplay/cat_waking_up_gift_chance")); + + /** + * {@code minecraft:gameplay/creaking_active} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_CREAKING_ACTIVE = create(key("gameplay/creaking_active")); + + /** + * {@code minecraft:gameplay/eyeblossom_open} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_EYEBLOSSOM_OPEN = create(key("gameplay/eyeblossom_open")); + + /** + * {@code minecraft:gameplay/fast_lava} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_FAST_LAVA = create(key("gameplay/fast_lava")); + + /** + * {@code minecraft:gameplay/increased_fire_burnout} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_INCREASED_FIRE_BURNOUT = create(key("gameplay/increased_fire_burnout")); + + /** + * {@code minecraft:gameplay/monsters_burn} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_MONSTERS_BURN = create(key("gameplay/monsters_burn")); + + /** + * {@code minecraft:gameplay/nether_portal_spawns_piglin} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_NETHER_PORTAL_SPAWNS_PIGLIN = create(key("gameplay/nether_portal_spawns_piglin")); + + /** + * {@code minecraft:gameplay/piglins_zombify} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_PIGLINS_ZOMBIFY = create(key("gameplay/piglins_zombify")); + + /** + * {@code minecraft:gameplay/respawn_anchor_works} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_RESPAWN_ANCHOR_WORKS = create(key("gameplay/respawn_anchor_works")); + + /** + * {@code minecraft:gameplay/sky_light_level} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_SKY_LIGHT_LEVEL = create(key("gameplay/sky_light_level")); + + /** + * {@code minecraft:gameplay/snow_golem_melts} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_SNOW_GOLEM_MELTS = create(key("gameplay/snow_golem_melts")); + + /** + * {@code minecraft:gameplay/surface_slime_spawn_chance} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_SURFACE_SLIME_SPAWN_CHANCE = create(key("gameplay/surface_slime_spawn_chance")); + + /** + * {@code minecraft:gameplay/turtle_egg_hatch_chance} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_TURTLE_EGG_HATCH_CHANCE = create(key("gameplay/turtle_egg_hatch_chance")); + + /** + * {@code minecraft:gameplay/villager_activity} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_VILLAGER_ACTIVITY = create(key("gameplay/villager_activity")); + + /** + * {@code minecraft:gameplay/water_evaporates} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> GAMEPLAY_WATER_EVAPORATES = create(key("gameplay/water_evaporates")); + + /** + * {@code minecraft:visual/ambient_particles} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_AMBIENT_PARTICLES = create(key("visual/ambient_particles")); + + /** + * {@code minecraft:visual/cloud_color} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_CLOUD_COLOR = create(key("visual/cloud_color")); + + /** + * {@code minecraft:visual/cloud_fog_end_distance} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_CLOUD_FOG_END_DISTANCE = create(key("visual/cloud_fog_end_distance")); + + /** + * {@code minecraft:visual/cloud_height} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_CLOUD_HEIGHT = create(key("visual/cloud_height")); + + /** + * {@code minecraft:visual/default_dripstone_particle} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_DEFAULT_DRIPSTONE_PARTICLE = create(key("visual/default_dripstone_particle")); + + /** + * {@code minecraft:visual/fog_color} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_FOG_COLOR = create(key("visual/fog_color")); + + /** + * {@code minecraft:visual/fog_end_distance} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_FOG_END_DISTANCE = create(key("visual/fog_end_distance")); + + /** + * {@code minecraft:visual/fog_start_distance} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_FOG_START_DISTANCE = create(key("visual/fog_start_distance")); + + /** + * {@code minecraft:visual/moon_angle} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_MOON_ANGLE = create(key("visual/moon_angle")); + + /** + * {@code minecraft:visual/moon_phase} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_MOON_PHASE = create(key("visual/moon_phase")); + + /** + * {@code minecraft:visual/sky_color} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_SKY_COLOR = create(key("visual/sky_color")); + + /** + * {@code minecraft:visual/sky_fog_end_distance} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_SKY_FOG_END_DISTANCE = create(key("visual/sky_fog_end_distance")); + + /** + * {@code minecraft:visual/sky_light_color} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_SKY_LIGHT_COLOR = create(key("visual/sky_light_color")); + + /** + * {@code minecraft:visual/sky_light_factor} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_SKY_LIGHT_FACTOR = create(key("visual/sky_light_factor")); + + /** + * {@code minecraft:visual/star_angle} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_STAR_ANGLE = create(key("visual/star_angle")); + + /** + * {@code minecraft:visual/star_brightness} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_STAR_BRIGHTNESS = create(key("visual/star_brightness")); + + /** + * {@code minecraft:visual/sun_angle} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_SUN_ANGLE = create(key("visual/sun_angle")); + + /** + * {@code minecraft:visual/sunrise_sunset_color} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_SUNRISE_SUNSET_COLOR = create(key("visual/sunrise_sunset_color")); + + /** + * {@code minecraft:visual/water_fog_color} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_WATER_FOG_COLOR = create(key("visual/water_fog_color")); + + /** + * {@code minecraft:visual/water_fog_end_distance} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_WATER_FOG_END_DISTANCE = create(key("visual/water_fog_end_distance")); + + /** + * {@code minecraft:visual/water_fog_start_distance} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey> VISUAL_WATER_FOG_START_DISTANCE = create(key("visual/water_fog_start_distance")); + + private EnvironmentAttributeKeys() { + } + + private static TypedKey> create(final Key key) { + return TypedKey.create(RegistryKey.ENVIRONMENT_ATTRIBUTE, key); + } +} diff --git a/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java b/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java index dcee3d88f5b7..5371ebebbf6f 100644 --- a/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java +++ b/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java @@ -3,6 +3,7 @@ import io.papermc.paper.datacomponent.DataComponentType; import io.papermc.paper.dialog.Dialog; import io.papermc.paper.registry.tag.TagKey; +import io.papermc.paper.world.attribute.EnvironmentalAttributeType; import net.kyori.adventure.key.Key; import net.kyori.adventure.key.KeyPattern; import net.kyori.adventure.key.Keyed; @@ -132,6 +133,11 @@ public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { * @see io.papermc.paper.registry.keys.GameRuleKeys */ RegistryKey> GAME_RULE = create("game_rule"); + /** + * Built-in registry for environmental attribute types. + * @see io.papermc.paper.registry.keys.EnvironmentAttributeKeys + */ + RegistryKey> ENVIRONMENT_ATTRIBUTE = create("environment_attribute"); /* ********************** * * Data-driven Registries * diff --git a/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeType.java b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeType.java new file mode 100644 index 000000000000..c8f0cf5155fc --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeType.java @@ -0,0 +1,14 @@ +package io.papermc.paper.world.attribute; + +import org.bukkit.Keyed; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +@NullMarked +@ApiStatus.Experimental +@ApiStatus.NonExtendable +public interface EnvironmentalAttributeType extends Keyed { + + T getDefaultValue(); + +} diff --git a/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeTypes.java b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeTypes.java new file mode 100644 index 000000000000..6dbddffc57d5 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeTypes.java @@ -0,0 +1,122 @@ +package io.papermc.paper.world.attribute; + +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.world.MoonPhase; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.util.TriState; +import org.jspecify.annotations.NullMarked; + +@NullMarked +public final class EnvironmentalAttributeTypes { + + // ================ + // AUDIO + // ================ + + // public static final EnvironmentalAttributeType AMBIENT_SOUNDS = get("audio/ambient_sounds"); + + // public static final EnvironmentalAttributeType BACKGROUND_MUSIC = get("audio/background_music"); + + public static final EnvironmentalAttributeType FIREFLY_BUSH_SOUNDS = get("audio/firefly_bush_sounds"); + + public static final EnvironmentalAttributeType MUSIC_VOLUME = get("audio/music_volume"); + + // ================ + // GAMEPLAY + // ================ + + // public static final EnvironmentalAttributeType BABY_VILLAGER_ACTIVITY = get("gameplay/baby_villager_activity"); + + // public static final EnvironmentalAttributeType BED_RULE = get("gameplay/bed_rule"); + + public static final EnvironmentalAttributeType BEES_STAY_IN_HIVE = get("gameplay/bees_stay_in_hive"); + + public static final EnvironmentalAttributeType CAN_PILLAGER_PATROL_SPAWN = get("gameplay/can_pillager_patrol_spawn"); + + public static final EnvironmentalAttributeType CAN_START_RAID = get("gameplay/can_start_raid"); + + public static final EnvironmentalAttributeType CAT_WAKING_UP_GIFT_CHANCE = get("gameplay/cat_waking_up_gift_chance"); + + public static final EnvironmentalAttributeType CREAKING_ACTIVE = get("gameplay/creaking_active"); + + public static final EnvironmentalAttributeType EYEBLOSSOM_OPEN = get("gameplay/eyeblossom_open"); + + public static final EnvironmentalAttributeType FAST_LAVA = get("gameplay/fast_lava"); + + public static final EnvironmentalAttributeType INCREASED_FIRE_BURNOUT = get("gameplay/increased_fire_burnout"); + + public static final EnvironmentalAttributeType MONSTERS_BURN = get("gameplay/monsters_burn"); + + public static final EnvironmentalAttributeType NETHER_PORTAL_SPAWNS_PIGLIN = get("gameplay/nether_portal_spawns_piglin"); + + public static final EnvironmentalAttributeType PIGLINS_ZOMBIFY = get("gameplay/piglins_zombify"); + + public static final EnvironmentalAttributeType RESPAWN_ANCHOR_WORKS = get("gameplay/respawn_anchor_works"); + + public static final EnvironmentalAttributeType SKY_LIGHT_LEVEL = get("gameplay/sky_light_level"); + + public static final EnvironmentalAttributeType SNOW_GOLEM_MELTS = get("gameplay/snow_golem_melts"); + + public static final EnvironmentalAttributeType SURFACE_SLIME_SPAWN_CHANCE = get("gameplay/surface_slime_spawn_chance"); + + public static final EnvironmentalAttributeType TURTLE_EGG_HATCH_CHANCE = get("gameplay/turtle_egg_hatch_chance"); + + // public static final EnvironmentalAttributeType VILLAGER_ACTIVITY = get("gameplay/villager_activity"); + + public static final EnvironmentalAttributeType WATER_EVAPORATES = get("gameplay/water_evaporates"); + + // ================ + // VISUAL + // ================ + + // public static final EnvironmentalAttributeType> AMBIENT_PARTICLES = get("visual/ambient_particles"); + + public static final EnvironmentalAttributeType CLOUD_COLOR = get("visual/cloud_color"); + + public static final EnvironmentalAttributeType CLOUD_FOG_END_DISTANCE = get("visual/cloud_fog_end_distance"); + + public static final EnvironmentalAttributeType CLOUD_HEIGHT = get("visual/cloud_height"); + + // public static final EnvironmentalAttributeType DEFAULT_DRIPSTONE_PARTICLE = get("visual/default_dripstone_particle"); + + public static final EnvironmentalAttributeType FOG_COLOR = get("visual/fog_color"); + + public static final EnvironmentalAttributeType FOG_END_DISTANCE = get("visual/fog_end_distance"); + + public static final EnvironmentalAttributeType FOG_START_DISTANCE = get("visual/fog_start_distance"); + + public static final EnvironmentalAttributeType MOON_ANGLE = get("visual/moon_angle"); + + public static final EnvironmentalAttributeType MOON_PHASE = get("visual/moon_phase"); + + public static final EnvironmentalAttributeType SKY_COLOR = get("visual/sky_color"); + + public static final EnvironmentalAttributeType SKY_FOG_END_DISTANCE = get("visual/sky_fog_end_distance"); + + public static final EnvironmentalAttributeType SKY_LIGHT_COLOR = get("visual/sky_light_color"); + + public static final EnvironmentalAttributeType SKY_LIGHT_FACTOR = get("visual/sky_light_factor"); + + public static final EnvironmentalAttributeType STAR_ANGLE = get("visual/star_angle"); + + public static final EnvironmentalAttributeType STAR_BRIGHTNESS = get("visual/star_brightness"); + + public static final EnvironmentalAttributeType SUN_ANGLE = get("visual/sun_angle"); + + public static final EnvironmentalAttributeType SUNRISE_SUNSET_COLOR = get("visual/sunrise_sunset_color"); + + public static final EnvironmentalAttributeType WATER_FOG_COLOR = get("visual/water_fog_color"); + + public static final EnvironmentalAttributeType WATER_FOG_END_DISTANCE = get("visual/water_fog_end_distance"); + + public static final EnvironmentalAttributeType WATER_FOG_START_DISTANCE = get("visual/water_fog_start_distance"); + + private EnvironmentalAttributeTypes() { + } + + @SuppressWarnings("unchecked") + private static EnvironmentalAttributeType get(final String key) { + return (EnvironmentalAttributeType) RegistryAccess.registryAccess().getRegistry(RegistryKey.ENVIRONMENT_ATTRIBUTE).getOrThrow(Key.key(key)); + } +} diff --git a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java index 0a9f1e9a68f7..2feb0363f993 100644 --- a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java +++ b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java @@ -32,6 +32,7 @@ import java.util.Set; import java.util.function.Consumer; import java.util.stream.Collectors; +import io.papermc.paper.world.attribute.EnvironmentalAttributeType; import net.minecraft.core.Registry; import net.minecraft.core.component.DataComponents; import net.minecraft.core.particles.ParticleTypes; @@ -39,6 +40,7 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.server.dialog.Dialogs; import net.minecraft.sounds.SoundEvents; +import net.minecraft.world.attribute.EnvironmentAttributes; import net.minecraft.world.damagesource.DamageTypes; import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.ai.attributes.Attributes; @@ -170,7 +172,8 @@ private static RegistryEntry inconsistentEntry(ResourceKey> DATA_DRIVEN = List.of( diff --git a/paper-server/src/main/java/io/papermc/paper/adventure/PaperAdventure.java b/paper-server/src/main/java/io/papermc/paper/adventure/PaperAdventure.java index 8cd1ea370dd4..13f27635c728 100644 --- a/paper-server/src/main/java/io/papermc/paper/adventure/PaperAdventure.java +++ b/paper-server/src/main/java/io/papermc/paper/adventure/PaperAdventure.java @@ -35,6 +35,7 @@ import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.kyori.adventure.translation.GlobalTranslator; import net.kyori.adventure.util.Codec; +import net.kyori.adventure.util.TriState; import net.minecraft.ChatFormatting; import net.minecraft.commands.CommandSourceStack; import net.minecraft.core.Holder; @@ -468,4 +469,21 @@ public static Style asAdventure(final net.minecraft.network.chat.Style style) { .parse(ops, encoded).getOrThrow(IllegalStateException::new); } + // TriState + + public static net.minecraft.util.TriState asVanilla(final TriState value) { + return switch (value) { + case TRUE -> net.minecraft.util.TriState.TRUE; + case FALSE -> net.minecraft.util.TriState.FALSE; + case NOT_SET -> net.minecraft.util.TriState.DEFAULT; + }; + } + + public static TriState asAdventure(final net.minecraft.util.TriState value) { + return switch(value) { + case TRUE -> TriState.TRUE; + case FALSE -> TriState.FALSE; + case DEFAULT -> TriState.NOT_SET; + }; + } } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java index 121babcfdda5..02c7bf6d8cc4 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java @@ -25,6 +25,8 @@ import io.papermc.paper.registry.entry.RegistryEntry; import io.papermc.paper.registry.entry.RegistryEntryMeta; import io.papermc.paper.registry.tag.TagKey; +import io.papermc.paper.world.attribute.EnvironmentalAttributeType; +import io.papermc.paper.world.attribute.PaperEnvironmentalAttributeType; import java.util.Collections; import java.util.IdentityHashMap; import java.util.List; @@ -121,6 +123,7 @@ public final class PaperRegistries { start(Registries.SOUND_EVENT, RegistryKey.SOUND_EVENT).craft(Sound.class, CraftSound::new, true).create(PaperSoundEventRegistryEntry.PaperBuilder::new, RegistryEntryMeta.RegistryModificationApiSupport.NONE), start(Registries.DATA_COMPONENT_TYPE, RegistryKey.DATA_COMPONENT_TYPE).craft(DataComponentTypes.class, PaperDataComponentType::of).build(), start(Registries.GAME_RULE, RegistryKey.GAME_RULE).craft(GameRule.class, CraftGameRule::new).build(), + start(Registries.ENVIRONMENT_ATTRIBUTE, RegistryKey.ENVIRONMENT_ATTRIBUTE).craft(EnvironmentalAttributeType.class, PaperEnvironmentalAttributeType::of).build(), // data-driven start(Registries.BIOME, RegistryKey.BIOME).craft(Biome.class, CraftBiome::new).build().delayed(), diff --git a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java new file mode 100644 index 000000000000..a0a9f076b338 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java @@ -0,0 +1,100 @@ +package io.papermc.paper.world.attribute; + +import io.papermc.paper.adventure.PaperAdventure; +import io.papermc.paper.registry.HolderableBase; +import io.papermc.paper.registry.data.typed.PaperTypedDataAdapter; +import io.papermc.paper.registry.data.typed.PaperTypedDataAdapters; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.attribute.EnvironmentAttribute; +import net.minecraft.world.attribute.EnvironmentAttributes; +import net.minecraft.world.level.MoonPhase; + +public final class PaperEnvironmentalAttributeType extends HolderableBase> implements EnvironmentalAttributeType { + + private static final PaperTypedDataAdapters ADAPTERS = PaperTypedDataAdapters.create( + BuiltInRegistries.ENVIRONMENT_ATTRIBUTE, + PaperEnvironmentalAttributeTypeCollector::new, + collector -> { + // Audio + // collector.register(EnvironmentAttributes.AMBIENT_SOUNDS, toApi, toNms); + // collector.register(EnvironmentAttributes.BACKGROUND_MUSIC, toApi, toNms); + collector.registerIdentity(EnvironmentAttributes.FIREFLY_BUSH_SOUNDS, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.MUSIC_VOLUME, EnvironmentAttribute::valueCodec); + + // Gameplay + // collector.register(EnvironmentAttributes.BABY_VILLAGER_ACTIVITY, toApi, toNms); + // collector.register(EnvironmentAttributes.BED_RULE, toApi, toNms); + collector.registerIdentity(EnvironmentAttributes.BEES_STAY_IN_HIVE, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.CAN_PILLAGER_PATROL_SPAWN, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.CAN_START_RAID, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.CAT_WAKING_UP_GIFT_CHANCE, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.CREAKING_ACTIVE, EnvironmentAttribute::valueCodec); + collector.register(EnvironmentAttributes.EYEBLOSSOM_OPEN, PaperAdventure::asAdventure, PaperAdventure::asVanilla); + collector.registerIdentity(EnvironmentAttributes.FAST_LAVA, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.INCREASED_FIRE_BURNOUT, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.MONSTERS_BURN, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.NETHER_PORTAL_SPAWNS_PIGLINS, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.PIGLINS_ZOMBIFY, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.RESPAWN_ANCHOR_WORKS, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.SKY_LIGHT_LEVEL, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.SNOW_GOLEM_MELTS, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.SURFACE_SLIME_SPAWN_CHANCE, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.TURTLE_EGG_HATCH_CHANCE, EnvironmentAttribute::valueCodec); + // collector.register(EnvironmentAttributes.VILLAGER_ACTIVITY, toApi, toNms); + collector.registerIdentity(EnvironmentAttributes.WATER_EVAPORATES, EnvironmentAttribute::valueCodec); + + // Visual + // collector.register(EnvironmentAttributes.AMBIENT_PARTICLES, toApi, toNms); + collector.registerIdentity(EnvironmentAttributes.CLOUD_COLOR, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.CLOUD_FOG_END_DISTANCE, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.CLOUD_HEIGHT, EnvironmentAttribute::valueCodec); + // collector.register(EnvironmentAttributes.DEFAULT_DRIPSTONE_PARTICLE, toApi, toNms); + collector.registerIdentity(EnvironmentAttributes.FOG_COLOR, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.FOG_END_DISTANCE, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.FOG_START_DISTANCE, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.MOON_ANGLE, EnvironmentAttribute::valueCodec); + collector.register(EnvironmentAttributes.MOON_PHASE, moonPhase -> io.papermc.paper.world.MoonPhase.values()[moonPhase.ordinal()], moonPhase -> MoonPhase.values()[moonPhase.ordinal()]); + collector.registerIdentity(EnvironmentAttributes.SKY_COLOR, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.SKY_FOG_END_DISTANCE, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.SKY_LIGHT_COLOR, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.SKY_LIGHT_FACTOR, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.STAR_ANGLE, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.STAR_BRIGHTNESS, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.SUN_ANGLE, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.SUNRISE_SUNSET_COLOR, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.WATER_FOG_COLOR, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.WATER_FOG_END_DISTANCE, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.WATER_FOG_START_DISTANCE, EnvironmentAttribute::valueCodec); + } + ); + + private final PaperTypedDataAdapter adapter; + + private PaperEnvironmentalAttributeType(Holder> holder, PaperTypedDataAdapter adapter) { + super(holder); + + this.adapter = adapter; + } + + @SuppressWarnings("unchecked") + public static EnvironmentalAttributeType of(final Holder holder) { + final PaperTypedDataAdapter adapter = PaperEnvironmentalAttributeType.ADAPTERS.getAdapter(holder.unwrapKey().orElseThrow()); + if (adapter == null) { + throw new IllegalArgumentException("No adapter found for " + holder); + } + if (!adapter.isValued()) { + throw new IllegalStateException("Non-valued adapter is not supported for environmental attribute types: " + holder); + } + return new PaperEnvironmentalAttributeType<>((Holder>) holder, adapter); + } + + @Override + public API getDefaultValue() { + return this.getAdapter().fromVanilla(this.getHandle().defaultValue()); + } + + public PaperTypedDataAdapter getAdapter() { + return this.adapter; + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeTypeCollector.java b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeTypeCollector.java new file mode 100644 index 000000000000..30eb1bb69383 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeTypeCollector.java @@ -0,0 +1,27 @@ +package io.papermc.paper.world.attribute; + +import io.papermc.paper.registry.data.typed.AbstractTypedDataCollector; +import io.papermc.paper.registry.data.typed.PaperTypedDataAdapter; +import java.util.Map; +import java.util.function.Function; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.attribute.EnvironmentAttribute; +import org.bukkit.craftbukkit.util.Handleable; + +class PaperEnvironmentalAttributeTypeCollector extends AbstractTypedDataCollector> { + + public PaperEnvironmentalAttributeTypeCollector(final Registry> registry, final Map, PaperTypedDataAdapter> adapters) { + super(registry, adapters); + } + + // Not using @Override because of generic types + public > void register(final EnvironmentAttribute dataComponentType, final Function vanillaToApi) { + super.register(dataComponentType, vanillaToApi); + } + + // Not using @Override because of generic types + public void register(final EnvironmentAttribute dataComponentType, final Function vanillaToApi, final Function apiToVanilla) { + super.register(dataComponentType, vanillaToApi, apiToVanilla); + } +} From 60ccda088f15a19e27f07e2cf53bce1dbfbc0fd8 Mon Sep 17 00:00:00 2001 From: roro1506HD Date: Sat, 29 Nov 2025 17:42:12 +0100 Subject: [PATCH 03/15] wip: update AbstractTypedDataCollector comment --- .../paper/registry/data/typed/AbstractTypedDataCollector.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/AbstractTypedDataCollector.java b/paper-server/src/main/java/io/papermc/paper/registry/data/typed/AbstractTypedDataCollector.java index e8bf7ad49b86..1444f1864ece 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/AbstractTypedDataCollector.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/data/typed/AbstractTypedDataCollector.java @@ -8,8 +8,9 @@ import org.bukkit.craftbukkit.util.Handleable; import org.jspecify.annotations.Nullable; -// This class exists only to be implemented, implementations must override the following register method: +// This class exists only to be implemented, implementations must override the following register methods: // void register(final TYPE type, final Function vanillaToApi, final Function apiToVanilla) +// void register(final TYPE type, final Function vanillaToApi) // BUT should NOT use the @Override annotation, this is a hack around generics limitations to prevent // having to define generics on each register call as seen below, making collectors easier to read: // collector.register(...) From a9f79b17ae73fd756e121635727e51cdb66a2db9 Mon Sep 17 00:00:00 2001 From: roro1506HD Date: Sun, 30 Nov 2025 21:32:23 +0100 Subject: [PATCH 04/15] fix: fixed failing tests --- .../org/bukkit/registry/RegistryConstantsTest.java | 10 ++++++++++ .../support/provider/RegistriesArgumentProvider.java | 11 ++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/paper-server/src/test/java/org/bukkit/registry/RegistryConstantsTest.java b/paper-server/src/test/java/org/bukkit/registry/RegistryConstantsTest.java index 2718c82e0b6b..9913bd4fe2fe 100644 --- a/paper-server/src/test/java/org/bukkit/registry/RegistryConstantsTest.java +++ b/paper-server/src/test/java/org/bukkit/registry/RegistryConstantsTest.java @@ -15,6 +15,7 @@ import net.minecraft.core.registries.Registries; import net.minecraft.resources.Identifier; import net.minecraft.resources.ResourceKey; +import net.minecraft.world.attribute.EnvironmentAttributes; import org.bukkit.Keyed; import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.support.RegistryHelper; @@ -58,6 +59,15 @@ public static void populateIgnored() { DataComponents.LOCK, DataComponents.CREATIVE_SLOT_LOCK )); + ignore(Registries.ENVIRONMENT_ATTRIBUTE, Set.of( + EnvironmentAttributes.AMBIENT_SOUNDS, + EnvironmentAttributes.BACKGROUND_MUSIC, + EnvironmentAttributes.BABY_VILLAGER_ACTIVITY, + EnvironmentAttributes.BED_RULE, + EnvironmentAttributes.VILLAGER_ACTIVITY, + EnvironmentAttributes.AMBIENT_PARTICLES, + EnvironmentAttributes.DEFAULT_DRIPSTONE_PARTICLE + )); } public static Stream registries() { diff --git a/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java b/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java index 00b949fc0982..6e85565ab378 100644 --- a/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java +++ b/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java @@ -6,19 +6,23 @@ import io.papermc.paper.dialog.PaperDialog; import io.papermc.paper.registry.PaperRegistries; import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.world.attribute.EnvironmentalAttributeType; +import io.papermc.paper.world.attribute.EnvironmentalAttributeTypes; import java.util.List; import java.util.stream.Stream; +import io.papermc.paper.world.attribute.PaperEnvironmentalAttributeType; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.attribute.EnvironmentAttribute; import net.minecraft.world.effect.MobEffect; -import net.minecraft.world.entity.animal.feline.CatVariant; import net.minecraft.world.entity.animal.chicken.ChickenVariant; import net.minecraft.world.entity.animal.cow.CowVariant; -import net.minecraft.world.entity.animal.pig.PigVariant; -import net.minecraft.world.entity.animal.nautilus.ZombieNautilusVariant; +import net.minecraft.world.entity.animal.feline.CatVariant; import net.minecraft.world.entity.animal.frog.FrogVariant; +import net.minecraft.world.entity.animal.nautilus.ZombieNautilusVariant; +import net.minecraft.world.entity.animal.pig.PigVariant; import net.minecraft.world.entity.animal.wolf.WolfSoundVariant; import net.minecraft.world.entity.animal.wolf.WolfVariant; import net.minecraft.world.entity.decoration.painting.PaintingVariant; @@ -149,6 +153,7 @@ public Object[] get() { register(Registries.ZOMBIE_NAUTILUS_VARIANT, ZombieNautilus.Variant.class, CraftZombieNautilus.CraftVariant.class, ZombieNautilusVariant.class); register(Registries.DIALOG, Dialog.class, PaperDialog.class, net.minecraft.server.dialog.Dialog.class); register(Registries.GAME_RULE, GameRule.class, GameRules.class, CraftGameRule.class, net.minecraft.world.level.gamerules.GameRule.class); + register(Registries.ENVIRONMENT_ATTRIBUTE, EnvironmentalAttributeType.class, EnvironmentalAttributeTypes.class, PaperEnvironmentalAttributeType.class, EnvironmentAttribute.class); } private static void register(ResourceKey> registryKey, Class api, Class impl, Class internal) { From a40ace11cf0cfd002ae11c308b8a730af6c6b305 Mon Sep 17 00:00:00 2001 From: roro1506HD Date: Sun, 30 Nov 2025 21:33:50 +0100 Subject: [PATCH 05/15] =?UTF-8?q?=C3=83feat:=20environmental=20attribute?= =?UTF-8?q?=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/papermc/paper/InternalAPIBridge.java | 3 + .../attribute/EnvironmentalAttribute.java | 22 +++++ .../EnvironmentalAttributeContext.java | 43 ++++++++++ .../attribute/EnvironmentalAttributeType.java | 2 - .../paper/world/attribute/package-info.java | 4 + paper-api/src/main/java/org/bukkit/World.java | 4 + .../attribute/WeatherAttributes.java.patch | 17 ++++ .../timeline/AttributeTrackSampler.java.patch | 11 +++ .../paper/PaperServerInternalAPIBridge.java | 7 ++ .../datacomponent/PaperDataComponentType.java | 22 ++--- .../data/typed/PaperTypedDataAdapter.java | 2 +- .../io/papermc/paper/util/FloatSupplier.java | 8 ++ .../PaperEnvironmentalAttribute.java | 32 ++++++++ .../PaperEnvironmentalAttributeContext.java | 81 +++++++++++++++++++ .../PaperEnvironmentalAttributeType.java | 8 +- .../paper/world/attribute/package-info.java | 4 + .../org/bukkit/craftbukkit/CraftWorld.java | 11 ++- 17 files changed, 262 insertions(+), 19 deletions(-) create mode 100644 paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttribute.java create mode 100644 paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeContext.java create mode 100644 paper-api/src/main/java/io/papermc/paper/world/attribute/package-info.java create mode 100644 paper-server/patches/sources/net/minecraft/world/attribute/WeatherAttributes.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/world/timeline/AttributeTrackSampler.java.patch create mode 100644 paper-server/src/main/java/io/papermc/paper/util/FloatSupplier.java create mode 100644 paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java create mode 100644 paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeContext.java create mode 100644 paper-server/src/main/java/io/papermc/paper/world/attribute/package-info.java diff --git a/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java b/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java index 609b4b1c7d97..fe4a8c7ff7d2 100644 --- a/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java +++ b/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java @@ -3,6 +3,7 @@ import com.destroystokyo.paper.SkinParts; import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.datacomponent.item.ResolvableProfile; +import io.papermc.paper.world.attribute.EnvironmentalAttributeContext; import io.papermc.paper.world.damagesource.CombatEntry; import io.papermc.paper.world.damagesource.FallLocationType; import java.util.function.Function; @@ -100,4 +101,6 @@ class Holder { Component defaultMannequinDescription(); GameRule legacyGameRuleBridge(GameRule rule, Function fromLegacyToModern, Function toLegacyFromModern, Class legacyClass); + + EnvironmentalAttributeContext.Builder environmentalAttributeContextBuilder(); } diff --git a/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttribute.java b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttribute.java new file mode 100644 index 000000000000..e0c632c2ce01 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttribute.java @@ -0,0 +1,22 @@ +package io.papermc.paper.world.attribute; + +import io.papermc.paper.math.Position; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Experimental +@ApiStatus.NonExtendable +public interface EnvironmentalAttribute { + + T getGlobal(); + + default T getPositioned(Position position) { + return this.getValue(EnvironmentalAttributeContext.builder().position(position).build()); + } + + default T getTimed(long time) { + return this.getValue(EnvironmentalAttributeContext.builder().time(time).build()); + } + + T getValue(EnvironmentalAttributeContext context); + +} diff --git a/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeContext.java b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeContext.java new file mode 100644 index 000000000000..c83dbf910613 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeContext.java @@ -0,0 +1,43 @@ +package io.papermc.paper.world.attribute; + +import io.papermc.paper.InternalAPIBridge; +import io.papermc.paper.math.Position; +import org.bukkit.WeatherType; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +@ApiStatus.Experimental +@ApiStatus.NonExtendable +public interface EnvironmentalAttributeContext { + + @Nullable Long time(); + + @Nullable Position position(); + + @Nullable Float rainLevel(); + + @Nullable Float thunderLevel(); + + static Builder builder() { + return InternalAPIBridge.get().environmentalAttributeContextBuilder(); + } + + @ApiStatus.NonExtendable + interface Builder { + + Builder time(@Nullable Long time); + + Builder position(@Nullable Position position); + + Builder rainLevel(@Nullable Float rainLevel); + + Builder raining(boolean raining); + + Builder thunderLevel(@Nullable Float thunderLevel); + + Builder thundering(boolean thundering); + + EnvironmentalAttributeContext build(); + + } +} diff --git a/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeType.java b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeType.java index c8f0cf5155fc..18197a02299e 100644 --- a/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeType.java +++ b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeType.java @@ -2,9 +2,7 @@ import org.bukkit.Keyed; import org.jetbrains.annotations.ApiStatus; -import org.jspecify.annotations.NullMarked; -@NullMarked @ApiStatus.Experimental @ApiStatus.NonExtendable public interface EnvironmentalAttributeType extends Keyed { diff --git a/paper-api/src/main/java/io/papermc/paper/world/attribute/package-info.java b/paper-api/src/main/java/io/papermc/paper/world/attribute/package-info.java new file mode 100644 index 000000000000..9f581b167111 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/world/attribute/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.papermc.paper.world.attribute; + +import org.jspecify.annotations.NullMarked; diff --git a/paper-api/src/main/java/org/bukkit/World.java b/paper-api/src/main/java/org/bukkit/World.java index 698f730efe1c..69291c0fe76d 100644 --- a/paper-api/src/main/java/org/bukkit/World.java +++ b/paper-api/src/main/java/org/bukkit/World.java @@ -11,6 +11,8 @@ import java.util.Set; import java.util.function.Consumer; import java.util.function.Predicate; +import io.papermc.paper.world.attribute.EnvironmentalAttribute; +import io.papermc.paper.world.attribute.EnvironmentalAttributeType; import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; @@ -4592,6 +4594,8 @@ default void setNoTickViewDistance(int viewDistance) { @NotNull public Collection getStructures(int x, int z, @NotNull Structure structure); + @NotNull EnvironmentalAttribute getEnvironmentalAttribute(@NotNull EnvironmentalAttributeType type); + /** * Represents various map environment types that a world may be */ diff --git a/paper-server/patches/sources/net/minecraft/world/attribute/WeatherAttributes.java.patch b/paper-server/patches/sources/net/minecraft/world/attribute/WeatherAttributes.java.patch new file mode 100644 index 000000000000..a7ae3b32275f --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/attribute/WeatherAttributes.java.patch @@ -0,0 +1,17 @@ +--- a/net/minecraft/world/attribute/WeatherAttributes.java ++++ b/net/minecraft/world/attribute/WeatherAttributes.java +@@ -69,12 +_,12 @@ + return new WeatherAttributes.WeatherAccess() { + @Override + public float rainLevel() { +- return level.getRainLevel(1.0F); ++ return io.papermc.paper.world.attribute.PaperEnvironmentalAttributeContext.CURRENT_CONTEXT.get().rainLevel(() -> level.getRainLevel(1.0F)); // Paper - Environmental Attribute API + } + + @Override + public float thunderLevel() { +- return level.getThunderLevel(1.0F); ++ return io.papermc.paper.world.attribute.PaperEnvironmentalAttributeContext.CURRENT_CONTEXT.get().thunderLevel(() -> level.getThunderLevel(1.0F)); // Paper - Environmental Attribute API + } + }; + } diff --git a/paper-server/patches/sources/net/minecraft/world/timeline/AttributeTrackSampler.java.patch b/paper-server/patches/sources/net/minecraft/world/timeline/AttributeTrackSampler.java.patch new file mode 100644 index 000000000000..60e696bcbb2c --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/timeline/AttributeTrackSampler.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/timeline/AttributeTrackSampler.java ++++ b/net/minecraft/world/timeline/AttributeTrackSampler.java +@@ -32,7 +_,7 @@ + public Value applyTimeBased(Value baseValue, int cacheTickId) { + if (this.cachedArgument == null || cacheTickId != this.cachedTickId) { + this.cachedTickId = cacheTickId; +- this.cachedArgument = this.argumentSampler.sample(this.dayTimeGetter.getAsLong()); ++ this.cachedArgument = this.argumentSampler.sample(io.papermc.paper.world.attribute.PaperEnvironmentalAttributeContext.CURRENT_CONTEXT.get().time(this.dayTimeGetter)); // Paper - Environmental Attribute API + } + + return this.modifier.apply(baseValue, this.cachedArgument); diff --git a/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java b/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java index f7979f188c3d..c20e434cc096 100644 --- a/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java +++ b/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java @@ -6,6 +6,8 @@ import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.datacomponent.item.PaperResolvableProfile; import io.papermc.paper.datacomponent.item.ResolvableProfile; +import io.papermc.paper.world.attribute.EnvironmentalAttributeContext; +import io.papermc.paper.world.attribute.PaperEnvironmentalAttributeContext; import io.papermc.paper.world.damagesource.CombatEntry; import io.papermc.paper.world.damagesource.FallLocationType; import io.papermc.paper.world.damagesource.PaperCombatEntryWrapper; @@ -116,4 +118,9 @@ public Component defaultMannequinDescription() { public GameRule legacyGameRuleBridge(GameRule rule, Function fromLegacyToModern, Function toLegacyFromModern, Class legacyClass) { return CraftGameRule.wrap(rule, fromLegacyToModern, toLegacyFromModern, legacyClass); } + + @Override + public EnvironmentalAttributeContext.Builder environmentalAttributeContextBuilder() { + return new PaperEnvironmentalAttributeContext.PaperBuilder(); + } } diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java index 31eed72cbaca..80767b7fd543 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java @@ -90,7 +90,7 @@ import static io.papermc.paper.util.MCUtil.transformUnmodifiable; -public abstract class PaperDataComponentType extends HolderableBase> implements DataComponentType { +public abstract class PaperDataComponentType extends HolderableBase> implements DataComponentType { private static final PaperTypedDataAdapters ADAPTERS = PaperTypedDataAdapters.create( BuiltInRegistries.DATA_COMPONENT_TYPE, @@ -231,9 +231,9 @@ public static Set minecraftToBukkit(final Set adapter; + private final PaperTypedDataAdapter adapter; - private PaperDataComponentType(final Holder> holder, final PaperTypedDataAdapter adapter) { + private PaperDataComponentType(final Holder> holder, final PaperTypedDataAdapter adapter) { super(holder); this.adapter = adapter; } @@ -243,13 +243,13 @@ public boolean isPersistent() { return !this.getHandle().isTransient(); } - public PaperTypedDataAdapter getAdapter() { + public PaperTypedDataAdapter getAdapter() { return this.adapter; } @SuppressWarnings("unchecked") public static DataComponentType of(final Holder holder) { - final PaperTypedDataAdapter< NMS, ?> adapter = PaperDataComponentType.ADAPTERS.getAdapter(holder.unwrapKey().orElseThrow()); + final PaperTypedDataAdapter adapter = PaperDataComponentType.ADAPTERS.getAdapter(holder.unwrapKey().orElseThrow()); if (adapter == null) { throw new IllegalArgumentException("No adapter found for " + holder); } @@ -262,31 +262,31 @@ public static DataComponentType of(final Holder holder) { } } - public static final class NonValuedImpl extends PaperDataComponentType implements NonValued { + public static final class NonValuedImpl extends PaperDataComponentType implements NonValued { NonValuedImpl( final Holder> holder, - final PaperTypedDataAdapter adapter + final PaperTypedDataAdapter adapter ) { super(holder, adapter); } } - public static final class ValuedImpl extends PaperDataComponentType implements Valued { + public static final class ValuedImpl extends PaperDataComponentType implements Valued { ValuedImpl( final Holder> holder, - final PaperTypedDataAdapter adapter + final PaperTypedDataAdapter adapter ) { super(holder, adapter); } } - public static final class Unimplemented extends PaperDataComponentType { + public static final class Unimplemented extends PaperDataComponentType { public Unimplemented( final Holder> holder, - final PaperTypedDataAdapter adapter + final PaperTypedDataAdapter adapter ) { super(holder, adapter); } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapter.java b/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapter.java index eb978dfaa5cd..8bec8480fc30 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapter.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapter.java @@ -8,7 +8,7 @@ import org.bukkit.craftbukkit.CraftRegistry; import org.jspecify.annotations.Nullable; -public record PaperTypedDataAdapter( +public record PaperTypedDataAdapter( Function apiToVanilla, Function vanillaToApi, @Nullable Codec codec diff --git a/paper-server/src/main/java/io/papermc/paper/util/FloatSupplier.java b/paper-server/src/main/java/io/papermc/paper/util/FloatSupplier.java new file mode 100644 index 000000000000..f2ef588a9720 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/util/FloatSupplier.java @@ -0,0 +1,8 @@ +package io.papermc.paper.util; + +@FunctionalInterface +public interface FloatSupplier { + + float getAsFloat(); + +} diff --git a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java new file mode 100644 index 000000000000..ca2eb9772acc --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java @@ -0,0 +1,32 @@ +package io.papermc.paper.world.attribute; + +import io.papermc.paper.registry.data.typed.PaperTypedDataAdapter; +import io.papermc.paper.util.MCUtil; +import net.minecraft.world.attribute.EnvironmentAttributeSystem; + +public class PaperEnvironmentalAttribute implements EnvironmentalAttribute { + + private final EnvironmentAttributeSystem attributeSystem; + private final PaperEnvironmentalAttributeType type; + private final PaperTypedDataAdapter adapter; + + public PaperEnvironmentalAttribute(final EnvironmentAttributeSystem attributeSystem, final PaperEnvironmentalAttributeType type) { + this.attributeSystem = attributeSystem; + this.type = type; + this.adapter = type.getAdapter(); + } + + @Override + public API getGlobal() { + return this.adapter.fromVanilla(this.attributeSystem.getDimensionValue(this.type.getHandle())); + } + + @Override + public API getValue(final EnvironmentalAttributeContext context) { + PaperEnvironmentalAttributeContext.CURRENT_CONTEXT.set((PaperEnvironmentalAttributeContext) context); + this.attributeSystem.invalidateTickCache(); // Invalidate cache, otherwise it would return the cached value if it was already requested in the same tick + API value = context.position() == null ? this.getGlobal() : this.adapter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), MCUtil.toVec3(context.position()))); + PaperEnvironmentalAttributeContext.CURRENT_CONTEXT.set(PaperEnvironmentalAttributeContext.EMPTY); + return value; + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeContext.java b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeContext.java new file mode 100644 index 000000000000..f7d9b9fe367b --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeContext.java @@ -0,0 +1,81 @@ +package io.papermc.paper.world.attribute; + +import io.papermc.paper.math.Position; +import io.papermc.paper.util.FloatSupplier; +import java.util.function.LongSupplier; +import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NonNull; + +public record PaperEnvironmentalAttributeContext( + @Nullable Long time, + @Nullable Position position, + @Nullable Float rainLevel, + @Nullable Float thunderLevel +) implements EnvironmentalAttributeContext { + + public static final PaperEnvironmentalAttributeContext EMPTY = new PaperEnvironmentalAttributeContext(null, null, null, null); + public static final ThreadLocal<@NonNull PaperEnvironmentalAttributeContext> CURRENT_CONTEXT = ThreadLocal.withInitial(() -> PaperEnvironmentalAttributeContext.EMPTY); + + public long time(LongSupplier fallbackSupplier) { + return this.time != null ? this.time : fallbackSupplier.getAsLong(); + } + + public float rainLevel(FloatSupplier fallbackSupplier) { + return this.rainLevel != null ? this.rainLevel : fallbackSupplier.getAsFloat(); + } + + public float thunderLevel(FloatSupplier fallbackSupplier) { + return this.thunderLevel != null ? this.thunderLevel : fallbackSupplier.getAsFloat(); + } + + public static class PaperBuilder implements EnvironmentalAttributeContext.Builder { + + private @Nullable Long time; + private @Nullable Position position; + private @Nullable Float rainLevel; + private @Nullable Float thunderLevel; + + @Override + public Builder time(@Nullable final Long time) { + this.time = time; + return this; + } + + @Override + public Builder position(@Nullable final Position position) { + this.position = position; + return this; + } + + @Override + public Builder rainLevel(@Nullable final Float rainLevel) { + this.rainLevel = rainLevel; + return this; + } + + @Override + public Builder raining(final boolean raining) { + return this.rainLevel(raining ? 1.0F : 0.0F); + } + + @Override + public Builder thunderLevel(@Nullable final Float thunderLevel) { + this.thunderLevel = thunderLevel; + return this; + } + + @Override + public Builder thundering(final boolean thundering) { + return this.thunderLevel(thundering ? 1.0F : 0.0F); + } + + @Override + public EnvironmentalAttributeContext build() { + if (this.time == null && this.position == null && this.rainLevel == null && this.thunderLevel == null) { + return PaperEnvironmentalAttributeContext.EMPTY; + } + + return new PaperEnvironmentalAttributeContext(this.time, this.position, this.rainLevel, this.thunderLevel); + } + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java index a0a9f076b338..5b6f87e8bff9 100644 --- a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java @@ -69,9 +69,9 @@ public final class PaperEnvironmentalAttributeType extends HolderableB } ); - private final PaperTypedDataAdapter adapter; + private final PaperTypedDataAdapter adapter; - private PaperEnvironmentalAttributeType(Holder> holder, PaperTypedDataAdapter adapter) { + private PaperEnvironmentalAttributeType(Holder> holder, PaperTypedDataAdapter adapter) { super(holder); this.adapter = adapter; @@ -79,7 +79,7 @@ private PaperEnvironmentalAttributeType(Holder> holder @SuppressWarnings("unchecked") public static EnvironmentalAttributeType of(final Holder holder) { - final PaperTypedDataAdapter adapter = PaperEnvironmentalAttributeType.ADAPTERS.getAdapter(holder.unwrapKey().orElseThrow()); + final PaperTypedDataAdapter adapter = PaperEnvironmentalAttributeType.ADAPTERS.getAdapter(holder.unwrapKey().orElseThrow()); if (adapter == null) { throw new IllegalArgumentException("No adapter found for " + holder); } @@ -94,7 +94,7 @@ public API getDefaultValue() { return this.getAdapter().fromVanilla(this.getHandle().defaultValue()); } - public PaperTypedDataAdapter getAdapter() { + public PaperTypedDataAdapter getAdapter() { return this.adapter; } } diff --git a/paper-server/src/main/java/io/papermc/paper/world/attribute/package-info.java b/paper-server/src/main/java/io/papermc/paper/world/attribute/package-info.java new file mode 100644 index 000000000000..9f581b167111 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.papermc.paper.world.attribute; + +import org.jspecify.annotations.NullMarked; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 5d1afba644e0..e45eebb99566 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -12,6 +12,10 @@ import io.papermc.paper.raytracing.RayTraceTarget; import io.papermc.paper.registry.RegistryAccess; import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.world.attribute.EnvironmentalAttribute; +import io.papermc.paper.world.attribute.EnvironmentalAttributeType; +import io.papermc.paper.world.attribute.PaperEnvironmentalAttribute; +import io.papermc.paper.world.attribute.PaperEnvironmentalAttributeType; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import java.nio.file.Path; import java.util.ArrayList; @@ -57,8 +61,8 @@ import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.util.Mth; -import net.minecraft.world.attribute.BedRule; import net.minecraft.util.NullOps; +import net.minecraft.world.attribute.BedRule; import net.minecraft.world.attribute.EnvironmentAttributes; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; @@ -2049,4 +2053,9 @@ public net.kyori.adventure.pointer.Pointers pointers() { return POINTERS_SUPPLIER.view(this); } // Paper end + + @Override + public @NotNull EnvironmentalAttribute getEnvironmentalAttribute(@NotNull final EnvironmentalAttributeType type) { + return new PaperEnvironmentalAttribute<>(this.getHandle().environmentAttributes(), (PaperEnvironmentalAttributeType) type); + } } From c39a37eaa08bef23058d93992b65ae20e8ad588a Mon Sep 17 00:00:00 2001 From: roro1506HD Date: Sun, 30 Nov 2025 23:44:44 +0100 Subject: [PATCH 06/15] feat: added Block#getAttributeValue(..) and optimized positioned lookups --- .../attribute/EnvironmentalAttribute.java | 4 +--- .../src/main/java/org/bukkit/block/Block.java | 3 +++ .../PaperEnvironmentalAttribute.java | 24 ++++++++++++++++++- .../org/bukkit/craftbukkit/CraftWorld.java | 2 +- .../bukkit/craftbukkit/block/CraftBlock.java | 7 ++++++ 5 files changed, 35 insertions(+), 5 deletions(-) diff --git a/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttribute.java b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttribute.java index e0c632c2ce01..121bb4c11be8 100644 --- a/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttribute.java +++ b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttribute.java @@ -9,9 +9,7 @@ public interface EnvironmentalAttribute { T getGlobal(); - default T getPositioned(Position position) { - return this.getValue(EnvironmentalAttributeContext.builder().position(position).build()); - } + T getPositioned(Position position); default T getTimed(long time) { return this.getValue(EnvironmentalAttributeContext.builder().time(time).build()); diff --git a/paper-api/src/main/java/org/bukkit/block/Block.java b/paper-api/src/main/java/org/bukkit/block/Block.java index fbee4ab2faae..855e8fc4c87d 100644 --- a/paper-api/src/main/java/org/bukkit/block/Block.java +++ b/paper-api/src/main/java/org/bukkit/block/Block.java @@ -1,5 +1,6 @@ package org.bukkit.block; +import io.papermc.paper.world.attribute.EnvironmentalAttributeType; import java.util.Collection; import org.bukkit.Chunk; import org.bukkit.FluidCollisionMode; @@ -834,4 +835,6 @@ default float getDestroySpeed(@NotNull ItemStack itemStack, boolean considerEnch * @return {@code true} if the block can suffocate */ boolean isSuffocating(); + + @NotNull T getAttributeValue(@NotNull EnvironmentalAttributeType type); } diff --git a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java index ca2eb9772acc..e96c2abb6ee2 100644 --- a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java @@ -1,7 +1,9 @@ package io.papermc.paper.world.attribute; +import io.papermc.paper.math.Position; import io.papermc.paper.registry.data.typed.PaperTypedDataAdapter; import io.papermc.paper.util.MCUtil; +import net.minecraft.core.BlockPos; import net.minecraft.world.attribute.EnvironmentAttributeSystem; public class PaperEnvironmentalAttribute implements EnvironmentalAttribute { @@ -21,11 +23,31 @@ public API getGlobal() { return this.adapter.fromVanilla(this.attributeSystem.getDimensionValue(this.type.getHandle())); } + @Override + public API getPositioned(final Position position) { + return this.adapter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), MCUtil.toVec3(position))); + } + + public API getPositioned(final BlockPos blockPos) { + return this.adapter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), blockPos)); + } + @Override public API getValue(final EnvironmentalAttributeContext context) { + if (context.equals(PaperEnvironmentalAttributeContext.EMPTY)) { + // No field is set, return the global value to prevent invalidating cache + return this.getGlobal(); + } + + Position position = context.position(); + if (position != null && context.time() == null && context.rainLevel() == null && context.thunderLevel() == null) { + // Only position is set, return cached positioned value + return this.getPositioned(position); + } + PaperEnvironmentalAttributeContext.CURRENT_CONTEXT.set((PaperEnvironmentalAttributeContext) context); this.attributeSystem.invalidateTickCache(); // Invalidate cache, otherwise it would return the cached value if it was already requested in the same tick - API value = context.position() == null ? this.getGlobal() : this.adapter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), MCUtil.toVec3(context.position()))); + API value = position == null ? this.getGlobal() : this.adapter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), MCUtil.toVec3(position))); PaperEnvironmentalAttributeContext.CURRENT_CONTEXT.set(PaperEnvironmentalAttributeContext.EMPTY); return value; } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index e45eebb99566..d03a2af3d27b 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -2055,7 +2055,7 @@ public net.kyori.adventure.pointer.Pointers pointers() { // Paper end @Override - public @NotNull EnvironmentalAttribute getEnvironmentalAttribute(@NotNull final EnvironmentalAttributeType type) { + public @NotNull PaperEnvironmentalAttribute getEnvironmentalAttribute(@NotNull final EnvironmentalAttributeType type) { return new PaperEnvironmentalAttribute<>(this.getHandle().environmentAttributes(), (PaperEnvironmentalAttributeType) type); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java index 31e665388bc6..3909eb06b920 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java @@ -6,6 +6,7 @@ import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +import io.papermc.paper.world.attribute.EnvironmentalAttributeType; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; @@ -60,6 +61,7 @@ import org.bukkit.util.BoundingBox; import org.bukkit.util.RayTraceResult; import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; public class CraftBlock implements Block { private final net.minecraft.world.level.LevelAccessor world; @@ -746,4 +748,9 @@ public void randomTick() { this.getNMS().randomTick(level, this.position, level.random); } // Paper end + + @Override + public @NotNull T getAttributeValue(@NotNull final EnvironmentalAttributeType type) { + return this.getCraftWorld().getEnvironmentalAttribute(type).getPositioned(this.getPosition()); + } } From 209ab74675f594f35a657541b6736eaa0397ad18 Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Mon, 12 Jan 2026 19:17:52 +0100 Subject: [PATCH 07/15] tweaks expose color attributes, add registry field, preload the correct class in the generator --- ...va => EnvironmentalAttributeTypeKeys.java} | 4 +- .../papermc/paper/registry/RegistryKey.java | 4 +- .../io/papermc/paper/world/MoonPhase.java | 1 + .../attribute/EnvironmentalAttribute.java | 7 +- .../EnvironmentalAttributeContext.java | 3 +- .../EnvironmentalAttributeTypes.java | 23 +++-- .../src/main/java/org/bukkit/Registry.java | 8 ++ paper-api/src/main/java/org/bukkit/World.java | 2 +- .../generator/registry/RegistryEntries.java | 14 +-- .../datacomponent/PaperDataComponentType.java | 32 ++++--- .../PaperDataComponentTypeCollector.java | 19 ++-- .../paper/registry/PaperRegistries.java | 4 +- .../data/typed/PaperTypedDataAdapter.java | 44 --------- .../data/typed/PaperTypedDataAdapters.java | 49 ---------- .../data/typed/PaperTypedDataCollector.java | 26 ------ .../typed/AbstractTypedDataCollector.java | 65 ++++++++------ .../registry/typed/PaperTypedDataAdapter.java | 57 ++++++++++++ .../typed/PaperTypedDataAdapters.java | 34 +++++++ .../typed/PaperTypedDataCollector.java | 40 +++++++++ .../{data => }/typed/package-info.java | 2 +- .../PaperEnvironmentalAttribute.java | 16 ++-- .../PaperEnvironmentalAttributeContext.java | 13 ++- .../PaperEnvironmentalAttributeType.java | 89 +++++++++---------- ...erEnvironmentalAttributeTypeCollector.java | 34 +++++-- .../org/bukkit/craftbukkit/CraftWorld.java | 2 +- .../bukkit/craftbukkit/block/CraftBlock.java | 5 +- .../craftbukkit/inventory/CraftItemStack.java | 4 +- 27 files changed, 326 insertions(+), 275 deletions(-) rename paper-api/src/generated/java/io/papermc/paper/registry/keys/{EnvironmentAttributeKeys.java => EnvironmentalAttributeTypeKeys.java} (99%) delete mode 100644 paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapter.java delete mode 100644 paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapters.java delete mode 100644 paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataCollector.java rename paper-server/src/main/java/io/papermc/paper/registry/{data => }/typed/AbstractTypedDataCollector.java (50%) create mode 100644 paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataAdapter.java create mode 100644 paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataAdapters.java create mode 100644 paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataCollector.java rename paper-server/src/main/java/io/papermc/paper/registry/{data => }/typed/package-info.java (55%) diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/EnvironmentAttributeKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/EnvironmentalAttributeTypeKeys.java similarity index 99% rename from paper-api/src/generated/java/io/papermc/paper/registry/keys/EnvironmentAttributeKeys.java rename to paper-api/src/generated/java/io/papermc/paper/registry/keys/EnvironmentalAttributeTypeKeys.java index f3c10d82ae0f..5dd4bb5ae1a8 100644 --- a/paper-api/src/generated/java/io/papermc/paper/registry/keys/EnvironmentAttributeKeys.java +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/EnvironmentalAttributeTypeKeys.java @@ -24,7 +24,7 @@ }) @NullMarked @GeneratedClass -public final class EnvironmentAttributeKeys { +public final class EnvironmentalAttributeTypeKeys { /** * {@code minecraft:audio/ambient_sounds} * @@ -340,7 +340,7 @@ public final class EnvironmentAttributeKeys { */ public static final TypedKey> VISUAL_WATER_FOG_START_DISTANCE = create(key("visual/water_fog_start_distance")); - private EnvironmentAttributeKeys() { + private EnvironmentalAttributeTypeKeys() { } private static TypedKey> create(final Key key) { diff --git a/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java b/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java index 5371ebebbf6f..66d3748a0985 100644 --- a/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java +++ b/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java @@ -40,6 +40,7 @@ import org.bukkit.map.MapCursor; import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionType; +import org.jetbrains.annotations.ApiStatus; import org.jspecify.annotations.NullMarked; import static io.papermc.paper.registry.RegistryKeyImpl.create; @@ -135,8 +136,9 @@ public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { RegistryKey> GAME_RULE = create("game_rule"); /** * Built-in registry for environmental attribute types. - * @see io.papermc.paper.registry.keys.EnvironmentAttributeKeys + * @see io.papermc.paper.registry.keys.EnvironmentalAttributeTypeKeys */ + @ApiStatus.Experimental RegistryKey> ENVIRONMENT_ATTRIBUTE = create("environment_attribute"); /* ********************** * diff --git a/paper-api/src/main/java/io/papermc/paper/world/MoonPhase.java b/paper-api/src/main/java/io/papermc/paper/world/MoonPhase.java index 0b24e1a92bba..fd245c6a55f9 100644 --- a/paper-api/src/main/java/io/papermc/paper/world/MoonPhase.java +++ b/paper-api/src/main/java/io/papermc/paper/world/MoonPhase.java @@ -6,6 +6,7 @@ @NullMarked public enum MoonPhase { + // todo generate FULL_MOON(0L), WANING_GIBBOUS(1L), LAST_QUARTER(2L), diff --git a/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttribute.java b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttribute.java index 121bb4c11be8..2d7101423c55 100644 --- a/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttribute.java +++ b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttribute.java @@ -1,6 +1,7 @@ package io.papermc.paper.world.attribute; import io.papermc.paper.math.Position; +import java.util.function.UnaryOperator; import org.jetbrains.annotations.ApiStatus; @ApiStatus.Experimental @@ -12,7 +13,11 @@ public interface EnvironmentalAttribute { T getPositioned(Position position); default T getTimed(long time) { - return this.getValue(EnvironmentalAttributeContext.builder().time(time).build()); + return this.getValue(context -> context.time(time)); + } + + default T getValue(UnaryOperator context) { + return this.getValue(context.apply(EnvironmentalAttributeContext.builder()).build()); } T getValue(EnvironmentalAttributeContext context); diff --git a/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeContext.java b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeContext.java index c83dbf910613..dfd0073d2ff2 100644 --- a/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeContext.java +++ b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeContext.java @@ -2,9 +2,8 @@ import io.papermc.paper.InternalAPIBridge; import io.papermc.paper.math.Position; -import org.bukkit.WeatherType; import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; @ApiStatus.Experimental @ApiStatus.NonExtendable diff --git a/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeTypes.java b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeTypes.java index 6dbddffc57d5..c3ff32b1858f 100644 --- a/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeTypes.java +++ b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeTypes.java @@ -1,13 +1,12 @@ package io.papermc.paper.world.attribute; -import io.papermc.paper.registry.RegistryAccess; -import io.papermc.paper.registry.RegistryKey; import io.papermc.paper.world.MoonPhase; import net.kyori.adventure.key.Key; +import net.kyori.adventure.key.KeyPattern; import net.kyori.adventure.util.TriState; -import org.jspecify.annotations.NullMarked; +import org.bukkit.Color; +import org.bukkit.Registry; -@NullMarked public final class EnvironmentalAttributeTypes { // ================ @@ -72,7 +71,7 @@ public final class EnvironmentalAttributeTypes { // public static final EnvironmentalAttributeType> AMBIENT_PARTICLES = get("visual/ambient_particles"); - public static final EnvironmentalAttributeType CLOUD_COLOR = get("visual/cloud_color"); + public static final EnvironmentalAttributeType CLOUD_COLOR = get("visual/cloud_color"); public static final EnvironmentalAttributeType CLOUD_FOG_END_DISTANCE = get("visual/cloud_fog_end_distance"); @@ -80,7 +79,7 @@ public final class EnvironmentalAttributeTypes { // public static final EnvironmentalAttributeType DEFAULT_DRIPSTONE_PARTICLE = get("visual/default_dripstone_particle"); - public static final EnvironmentalAttributeType FOG_COLOR = get("visual/fog_color"); + public static final EnvironmentalAttributeType FOG_COLOR = get("visual/fog_color"); public static final EnvironmentalAttributeType FOG_END_DISTANCE = get("visual/fog_end_distance"); @@ -90,11 +89,11 @@ public final class EnvironmentalAttributeTypes { public static final EnvironmentalAttributeType MOON_PHASE = get("visual/moon_phase"); - public static final EnvironmentalAttributeType SKY_COLOR = get("visual/sky_color"); + public static final EnvironmentalAttributeType SKY_COLOR = get("visual/sky_color"); public static final EnvironmentalAttributeType SKY_FOG_END_DISTANCE = get("visual/sky_fog_end_distance"); - public static final EnvironmentalAttributeType SKY_LIGHT_COLOR = get("visual/sky_light_color"); + public static final EnvironmentalAttributeType SKY_LIGHT_COLOR = get("visual/sky_light_color"); public static final EnvironmentalAttributeType SKY_LIGHT_FACTOR = get("visual/sky_light_factor"); @@ -104,9 +103,9 @@ public final class EnvironmentalAttributeTypes { public static final EnvironmentalAttributeType SUN_ANGLE = get("visual/sun_angle"); - public static final EnvironmentalAttributeType SUNRISE_SUNSET_COLOR = get("visual/sunrise_sunset_color"); + public static final EnvironmentalAttributeType SUNRISE_SUNSET_COLOR = get("visual/sunrise_sunset_color"); - public static final EnvironmentalAttributeType WATER_FOG_COLOR = get("visual/water_fog_color"); + public static final EnvironmentalAttributeType WATER_FOG_COLOR = get("visual/water_fog_color"); public static final EnvironmentalAttributeType WATER_FOG_END_DISTANCE = get("visual/water_fog_end_distance"); @@ -116,7 +115,7 @@ private EnvironmentalAttributeTypes() { } @SuppressWarnings("unchecked") - private static EnvironmentalAttributeType get(final String key) { - return (EnvironmentalAttributeType) RegistryAccess.registryAccess().getRegistry(RegistryKey.ENVIRONMENT_ATTRIBUTE).getOrThrow(Key.key(key)); + private static EnvironmentalAttributeType get(final @KeyPattern.Value String key) { + return (EnvironmentalAttributeType) Registry.ENVIRONMENT_ATTRIBUTE.getOrThrow(Key.key(Key.MINECRAFT_NAMESPACE, key)); } } diff --git a/paper-api/src/main/java/org/bukkit/Registry.java b/paper-api/src/main/java/org/bukkit/Registry.java index 0859653089ac..3cfa4feae9b6 100644 --- a/paper-api/src/main/java/org/bukkit/Registry.java +++ b/paper-api/src/main/java/org/bukkit/Registry.java @@ -10,6 +10,7 @@ import io.papermc.paper.registry.TypedKey; import io.papermc.paper.registry.tag.Tag; import io.papermc.paper.registry.tag.TagKey; +import io.papermc.paper.world.attribute.EnvironmentalAttributeType; import java.util.Collection; import java.util.Iterator; import java.util.Locale; @@ -355,6 +356,13 @@ public int size() { * @see GameRule */ Registry> GAME_RULE = registryFor(RegistryKey.GAME_RULE); + /** + * Environmental attribute types. + * + * @see io.papermc.paper.world.attribute.EnvironmentalAttribute + */ + @ApiStatus.Experimental + Registry> ENVIRONMENT_ATTRIBUTE = registryFor(RegistryKey.ENVIRONMENT_ATTRIBUTE); // /** diff --git a/paper-api/src/main/java/org/bukkit/World.java b/paper-api/src/main/java/org/bukkit/World.java index 69291c0fe76d..07333cb59a43 100644 --- a/paper-api/src/main/java/org/bukkit/World.java +++ b/paper-api/src/main/java/org/bukkit/World.java @@ -4594,7 +4594,7 @@ default void setNoTickViewDistance(int viewDistance) { @NotNull public Collection getStructures(int x, int z, @NotNull Structure structure); - @NotNull EnvironmentalAttribute getEnvironmentalAttribute(@NotNull EnvironmentalAttributeType type); + @NotNull EnvironmentalAttribute getEnvironmentalAttribute(@NotNull EnvironmentalAttributeType type); /** * Represents various map environment types that a world may be diff --git a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java index 2feb0363f993..820637c42921 100644 --- a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java +++ b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java @@ -20,6 +20,8 @@ import io.papermc.paper.registry.data.WolfVariantRegistryEntry; import io.papermc.paper.registry.data.ZombieNautilusVariantRegistryEntry; import io.papermc.paper.registry.data.dialog.DialogRegistryEntry; +import io.papermc.paper.world.attribute.EnvironmentalAttributeType; +import io.papermc.paper.world.attribute.EnvironmentalAttributeTypes; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.lang.reflect.Type; @@ -32,7 +34,6 @@ import java.util.Set; import java.util.function.Consumer; import java.util.stream.Collectors; -import io.papermc.paper.world.attribute.EnvironmentalAttributeType; import net.minecraft.core.Registry; import net.minecraft.core.component.DataComponents; import net.minecraft.core.particles.ParticleTypes; @@ -45,12 +46,12 @@ import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.animal.feline.CatVariants; import net.minecraft.world.entity.animal.chicken.ChickenVariants; import net.minecraft.world.entity.animal.cow.CowVariants; -import net.minecraft.world.entity.animal.pig.PigVariants; -import net.minecraft.world.entity.animal.nautilus.ZombieNautilusVariants; +import net.minecraft.world.entity.animal.feline.CatVariants; import net.minecraft.world.entity.animal.frog.FrogVariants; +import net.minecraft.world.entity.animal.nautilus.ZombieNautilusVariants; +import net.minecraft.world.entity.animal.pig.PigVariants; import net.minecraft.world.entity.animal.wolf.WolfSoundVariants; import net.minecraft.world.entity.animal.wolf.WolfVariants; import net.minecraft.world.entity.decoration.painting.PaintingVariants; @@ -155,7 +156,8 @@ private static RegistryEntry inconsistentEntry(ResourceKey> REGISTRY_CLASS_NAME_BASED_ON_API = Set.of( BlockType.class, - ItemType.class + ItemType.class, + EnvironmentalAttributeType.class ); public static final List> BUILT_IN = List.of( @@ -173,7 +175,7 @@ private static RegistryEntry inconsistentEntry(ResourceKey> DATA_DRIVEN = List.of( diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java index 80767b7fd543..48a3f3d9adf3 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java @@ -47,8 +47,8 @@ import io.papermc.paper.datacomponent.item.PaperWrittenBookContent; import io.papermc.paper.registry.HolderableBase; import io.papermc.paper.registry.PaperRegistries; -import io.papermc.paper.registry.data.typed.PaperTypedDataAdapter; -import io.papermc.paper.registry.data.typed.PaperTypedDataAdapters; +import io.papermc.paper.registry.typed.PaperTypedDataAdapter; +import io.papermc.paper.registry.typed.PaperTypedDataAdapters; import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -92,18 +92,18 @@ public abstract class PaperDataComponentType extends HolderableBase> implements DataComponentType { - private static final PaperTypedDataAdapters ADAPTERS = PaperTypedDataAdapters.create( + private static final PaperTypedDataAdapters> ADAPTERS = PaperTypedDataAdapters.create( BuiltInRegistries.DATA_COMPONENT_TYPE, PaperDataComponentTypeCollector::new, collector -> { - collector.registerIdentity(DataComponents.MAX_STACK_SIZE, net.minecraft.core.component.DataComponentType::codec); - collector.registerIdentity(DataComponents.MAX_DAMAGE, net.minecraft.core.component.DataComponentType::codec); - collector.registerIdentity(DataComponents.DAMAGE, net.minecraft.core.component.DataComponentType::codec); + collector.registerIdentity(DataComponents.MAX_STACK_SIZE); + collector.registerIdentity(DataComponents.MAX_DAMAGE); + collector.registerIdentity(DataComponents.DAMAGE); collector.registerUntyped(DataComponents.UNBREAKABLE); collector.register(DataComponents.USE_EFFECTS, PaperUseEffects::new); - collector.registerIdentity(DataComponents.POTION_DURATION_SCALE, net.minecraft.core.component.DataComponentType::codec); + collector.registerIdentity(DataComponents.POTION_DURATION_SCALE); collector.register(DataComponents.CUSTOM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla); - collector.registerIdentity(DataComponents.MINIMUM_ATTACK_CHARGE, net.minecraft.core.component.DataComponentType::codec); + collector.registerIdentity(DataComponents.MINIMUM_ATTACK_CHARGE); collector.register(DataComponents.DAMAGE_TYPE, nms -> CraftDamageType.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftDamageType.bukkitToMinecraftHolder(api))); collector.register(DataComponents.ITEM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla); collector.register(DataComponents.ITEM_MODEL, PaperAdventure::asAdventure, PaperAdventure::asVanilla); @@ -114,9 +114,9 @@ public abstract class PaperDataComponentType extends HolderableBase getAdapter() { @SuppressWarnings("unchecked") public static DataComponentType of(final Holder holder) { - final PaperTypedDataAdapter adapter = PaperDataComponentType.ADAPTERS.getAdapter(holder.unwrapKey().orElseThrow()); - if (adapter == null) { - throw new IllegalArgumentException("No adapter found for " + holder); - } + final Holder.Reference> reference = (Holder.Reference>) holder; + final PaperTypedDataAdapter adapter = PaperDataComponentType.ADAPTERS.get(reference.key()); if (adapter.isUnimplemented()) { return new Unimplemented<>((Holder>) holder, adapter); - } else if (adapter.isValued()) { - return new ValuedImpl<>((Holder>) holder, adapter); - } else { + } else if (adapter.isUntyped()) { return new NonValuedImpl<>((Holder>) holder, adapter); + } else { + return new ValuedImpl<>((Holder>) holder, adapter); } } diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentTypeCollector.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentTypeCollector.java index 435231edc5ec..824bbea445ac 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentTypeCollector.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentTypeCollector.java @@ -1,27 +1,30 @@ package io.papermc.paper.datacomponent; -import io.papermc.paper.registry.data.typed.AbstractTypedDataCollector; -import io.papermc.paper.registry.data.typed.PaperTypedDataAdapter; +import io.papermc.paper.registry.typed.AbstractTypedDataCollector; +import io.papermc.paper.registry.typed.PaperTypedDataAdapter; +import java.util.Map; +import java.util.function.Function; import net.minecraft.core.Registry; import net.minecraft.core.component.DataComponentType; import net.minecraft.resources.ResourceKey; import org.bukkit.craftbukkit.util.Handleable; -import java.util.Map; -import java.util.function.Function; class PaperDataComponentTypeCollector extends AbstractTypedDataCollector> { - public PaperDataComponentTypeCollector(final Registry> registry, final Map, PaperTypedDataAdapter> adapters) { + public PaperDataComponentTypeCollector(final Registry> registry, final Map>, PaperTypedDataAdapter> adapters) { super(registry, adapters); } - // Not using @Override because of generic types - public > void register(final DataComponentType dataComponentType, final Function vanillaToApi) { - super.register(dataComponentType, vanillaToApi); + public void registerIdentity(final DataComponentType dataComponentType) { + super.registerIdentity(dataComponentType, DataComponentType::codec); } // Not using @Override because of generic types public void register(final DataComponentType dataComponentType, final Function vanillaToApi, final Function apiToVanilla) { super.register(dataComponentType, vanillaToApi, apiToVanilla); } + + public > void register(final DataComponentType dataComponentType, final Function vanillaToApi) { + this.register(dataComponentType, vanillaToApi, Handleable::getHandle); + } } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java index 02c7bf6d8cc4..60d2b36f8262 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java @@ -25,7 +25,7 @@ import io.papermc.paper.registry.entry.RegistryEntry; import io.papermc.paper.registry.entry.RegistryEntryMeta; import io.papermc.paper.registry.tag.TagKey; -import io.papermc.paper.world.attribute.EnvironmentalAttributeType; +import io.papermc.paper.world.attribute.EnvironmentalAttributeTypes; import io.papermc.paper.world.attribute.PaperEnvironmentalAttributeType; import java.util.Collections; import java.util.IdentityHashMap; @@ -123,7 +123,7 @@ public final class PaperRegistries { start(Registries.SOUND_EVENT, RegistryKey.SOUND_EVENT).craft(Sound.class, CraftSound::new, true).create(PaperSoundEventRegistryEntry.PaperBuilder::new, RegistryEntryMeta.RegistryModificationApiSupport.NONE), start(Registries.DATA_COMPONENT_TYPE, RegistryKey.DATA_COMPONENT_TYPE).craft(DataComponentTypes.class, PaperDataComponentType::of).build(), start(Registries.GAME_RULE, RegistryKey.GAME_RULE).craft(GameRule.class, CraftGameRule::new).build(), - start(Registries.ENVIRONMENT_ATTRIBUTE, RegistryKey.ENVIRONMENT_ATTRIBUTE).craft(EnvironmentalAttributeType.class, PaperEnvironmentalAttributeType::of).build(), + start(Registries.ENVIRONMENT_ATTRIBUTE, RegistryKey.ENVIRONMENT_ATTRIBUTE).craft(EnvironmentalAttributeTypes.class, PaperEnvironmentalAttributeType::of).build(), // data-driven start(Registries.BIOME, RegistryKey.BIOME).craft(Biome.class, CraftBiome::new).build().delayed(), diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapter.java b/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapter.java deleted file mode 100644 index 8bec8480fc30..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapter.java +++ /dev/null @@ -1,44 +0,0 @@ -package io.papermc.paper.registry.data.typed; - -import com.mojang.serialization.Codec; -import java.util.function.Function; -import net.minecraft.core.Holder; -import net.minecraft.util.NullOps; -import net.minecraft.util.Unit; -import org.bukkit.craftbukkit.CraftRegistry; -import org.jspecify.annotations.Nullable; - -public record PaperTypedDataAdapter( - Function apiToVanilla, - Function vanillaToApi, - @Nullable Codec codec -) { - static final Function API_TO_UNIT_CONVERTER = $ -> Unit.INSTANCE; - - static final Function API_TO_UNIMPLEMENTED_CONVERTER = $ -> { - throw new UnsupportedOperationException("Cannot convert an API value to an unimplemented type"); - }; - - public boolean isValued() { - return this.apiToVanilla != API_TO_UNIT_CONVERTER; - } - - public boolean isUnimplemented() { - return this.apiToVanilla == API_TO_UNIMPLEMENTED_CONVERTER; - } - - public NMS toVanilla(final API value, final Holder type) { - final NMS nms = this.apiToVanilla.apply(value); - if (this.codec != null) { - this.codec.encodeStart(CraftRegistry.getMinecraftRegistry().createSerializationContext(NullOps.INSTANCE), nms).ifError(error -> { - throw new IllegalArgumentException("Failed to encode data component %s (%s)".formatted(type.unwrapKey().orElseThrow(), error.message())); - }); - } - - return nms; - } - - public API fromVanilla(final NMS value) { - return this.vanillaToApi.apply(value); - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapters.java b/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapters.java deleted file mode 100644 index bc2f442981c0..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataAdapters.java +++ /dev/null @@ -1,49 +0,0 @@ -package io.papermc.paper.registry.data.typed; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Consumer; -import java.util.function.Function; -import net.minecraft.core.Registry; -import net.minecraft.resources.ResourceKey; -import net.minecraft.util.Unit; -import org.jspecify.annotations.Nullable; - -public final class PaperTypedDataAdapters { - - static final Function UNIT_TO_API_CONVERTER = $ -> { - throw new UnsupportedOperationException("Cannot convert the Unit type to an API value"); - }; - - static final Function UNIMPLEMENTED_TO_API_CONVERTER = $ -> { - throw new UnsupportedOperationException("Cannot convert the an unimplemented type to an API value"); - }; - - private final Map, PaperTypedDataAdapter> adapters; - - private PaperTypedDataAdapters(Map, PaperTypedDataAdapter> adapters) { - this.adapters = adapters; - } - - public static > PaperTypedDataAdapters create( - Registry registry, - PaperTypedDataCollector.Factory collectorFactory, - Consumer consumer - ) { - Map, PaperTypedDataAdapter> adapters = new HashMap<>(); - COLLECTOR collector = collectorFactory.create(registry, adapters); - - consumer.accept(collector); - - // Loop through every entry in the registry and register any entry - // not already registered as unimplemented - collector.registerUnimplemented(); - - return new PaperTypedDataAdapters(adapters); - } - - @SuppressWarnings("unchecked") - public @Nullable RETURN getAdapter(ResourceKey key) { - return (RETURN) this.adapters.get(key); - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataCollector.java b/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataCollector.java deleted file mode 100644 index ed24fc910f58..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/PaperTypedDataCollector.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.papermc.paper.registry.data.typed; - -import com.mojang.serialization.Codec; -import java.util.Map; -import java.util.function.Function; -import net.minecraft.core.Registry; -import net.minecraft.resources.ResourceKey; -import org.bukkit.craftbukkit.util.Handleable; -import org.jspecify.annotations.Nullable; - -public interface PaperTypedDataCollector { - - void registerUntyped(final TYPE type); - - void registerIdentity(final TYPE type, final Function> codecGetter); - - > void register(final TYPE type, final Function vanillaToApi); - - void register(final TYPE type, final Function vanillaToApi, final Function apiToVanilla); - - interface Factory { - - COLLECTOR create(Registry registry, Map, PaperTypedDataAdapter> adapters); - - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/AbstractTypedDataCollector.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/AbstractTypedDataCollector.java similarity index 50% rename from paper-server/src/main/java/io/papermc/paper/registry/data/typed/AbstractTypedDataCollector.java rename to paper-server/src/main/java/io/papermc/paper/registry/typed/AbstractTypedDataCollector.java index 1444f1864ece..e446c95e120a 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/AbstractTypedDataCollector.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/AbstractTypedDataCollector.java @@ -1,76 +1,85 @@ -package io.papermc.paper.registry.data.typed; +package io.papermc.paper.registry.typed; import com.mojang.serialization.Codec; import java.util.Map; import java.util.function.Function; +import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; -import org.bukkit.craftbukkit.util.Handleable; import org.jspecify.annotations.Nullable; -// This class exists only to be implemented, implementations must override the following register methods: +// This class exists only to be implemented, implementations must override the following register method: // void register(final TYPE type, final Function vanillaToApi, final Function apiToVanilla) -// void register(final TYPE type, final Function vanillaToApi) // BUT should NOT use the @Override annotation, this is a hack around generics limitations to prevent // having to define generics on each register call as seen below, making collectors easier to read: // collector.register(...) public abstract class AbstractTypedDataCollector implements PaperTypedDataCollector { private final Registry registry; - private final Map, PaperTypedDataAdapter> adapters; + private final Map, PaperTypedDataAdapter> adapters; - public AbstractTypedDataCollector(final Registry registry, final Map, PaperTypedDataAdapter> adapters) { + protected AbstractTypedDataCollector( + final Registry registry, + final Map, PaperTypedDataAdapter> adapters + ) { this.registry = registry; this.adapters = adapters; } + private ResourceKey getKey(final TYPE type) { + return this.registry.getResourceKey(type).orElseThrow(); + } + @Override public void registerUntyped(final TYPE type) { - this.registerInternal(this.getKey(type), PaperTypedDataAdapters.UNIT_TO_API_CONVERTER, PaperTypedDataAdapter.API_TO_UNIT_CONVERTER, null); + this.registerUntyped(this.getKey(type)); } @Override - public void registerIdentity(final TYPE type, final Function> codecGetter) { - this.registerInternal(this.getKey(type), Function.identity(), Function.identity(), codecGetter.apply(type)); + public void registerUntyped(final ResourceKey type) { + this.registerInternal(type, PaperTypedDataAdapter.untyped()); } @Override - public > void register(final TYPE type, final Function vanillaToApi) { - this.registerInternal(this.getKey(type), vanillaToApi, Handleable::getHandle, null); + public void registerIdentity(final TYPE type, final Function> codecGetter) { + this.registerInternal(this.getKey(type), Function.identity(), Function.identity(), codecGetter.apply(type)); } @Override - public void register(final TYPE type, final Function vanillaToApi, final Function apiToVanilla) { - this.registerInternal(this.getKey(type), vanillaToApi, apiToVanilla, null); + public void registerIdentity(final Holder.Reference type, final Function> codecGetter) { + this.registerInternal(type.key(), Function.identity(), Function.identity(), codecGetter.apply(type.value())); } - private ResourceKey getKey(final TYPE type) { - return this.registry.getResourceKey(type).orElseThrow(); + @Override + public void registerIdentity(final ResourceKey type, final Function> codecGetter) { + this.registerInternal(type, Function.identity(), Function.identity(), codecGetter.apply(this.registry.getValueOrThrow(type))); } - void registerUnimplemented() { - for (final ResourceKey key : this.registry.registryKeySet()) { - if (!this.adapters.containsKey(key)) { - this.registerUnimplemented(key); - } - } + @Override + public void register(final TYPE type, final Function vanillaToApi, final Function apiToVanilla) { + this.register(this.getKey(type), vanillaToApi, apiToVanilla); } - @SuppressWarnings("unchecked") - private void registerUnimplemented(final ResourceKey key) { - this.registerInternal(key, PaperTypedDataAdapters.UNIMPLEMENTED_TO_API_CONVERTER, PaperTypedDataAdapter.API_TO_UNIMPLEMENTED_CONVERTER, null); + @Override + public void register(final ResourceKey type, final Function vanillaToApi, final Function apiToVanilla) { + this.registerInternal(type, vanillaToApi, apiToVanilla, null); } private void registerInternal( - final ResourceKey key, + final ResourceKey key, final Function vanillaToApi, final Function apiToVanilla, final @Nullable Codec codec ) { - if (this.adapters.containsKey(key)) { + this.registerInternal(key, new PaperTypedDataAdapter<>(vanillaToApi, apiToVanilla, codec)); + } + + private void registerInternal( + final ResourceKey key, + final PaperTypedDataAdapter adapter + ) { + if (this.adapters.put(key, adapter) != null) { throw new IllegalStateException("Duplicate adapter registration for " + key); } - - this.adapters.put(key, new PaperTypedDataAdapter<>(apiToVanilla, vanillaToApi, codec)); } } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataAdapter.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataAdapter.java new file mode 100644 index 000000000000..cfc896013b62 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataAdapter.java @@ -0,0 +1,57 @@ +package io.papermc.paper.registry.typed; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import java.util.function.Function; +import net.minecraft.util.NullOps; +import net.minecraft.util.Unit; +import org.bukkit.craftbukkit.CraftRegistry; +import org.jspecify.annotations.Nullable; + +public record PaperTypedDataAdapter( + Function vanillaToApi, + Function apiToVanilla, + @Nullable Codec codec +) { + private static final PaperTypedDataAdapter UNIMPLEMENTED = new PaperTypedDataAdapter<>($ -> { + throw new UnsupportedOperationException("Cannot convert an unimplemented type to an API value"); + }, $ -> { + throw new UnsupportedOperationException("Cannot convert an API value to an unimplemented type"); + }, null); + + private static final PaperTypedDataAdapter UNTYPED = new PaperTypedDataAdapter<>($ -> { + throw new UnsupportedOperationException("Cannot convert the Unit type to an API value"); + }, $ -> Unit.INSTANCE, null); + + @SuppressWarnings("unchecked") + public static PaperTypedDataAdapter unimplemented() { + return (PaperTypedDataAdapter) UNIMPLEMENTED; + } + + @SuppressWarnings("unchecked") + public static PaperTypedDataAdapter untyped() { + return (PaperTypedDataAdapter) UNTYPED; + } + + public boolean isUntyped() { + return this == UNTYPED; + } + + public boolean isUnimplemented() { + return this == UNIMPLEMENTED; + } + + public DataResult toVanilla(final API value) { + final NMS nms = this.apiToVanilla.apply(value); + if (this.codec != null) { + return this.codec.encodeStart(CraftRegistry.getMinecraftRegistry().createSerializationContext(NullOps.INSTANCE), nms) + .error().map(error -> DataResult.error(error::message, nms)).orElseGet(() -> DataResult.success(nms)); + } + + return DataResult.success(nms); + } + + public API fromVanilla(final NMS value) { + return this.vanillaToApi.apply(value); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataAdapters.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataAdapters.java new file mode 100644 index 000000000000..a2cadf22f523 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataAdapters.java @@ -0,0 +1,34 @@ +package io.papermc.paper.registry.typed; + +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.function.Consumer; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; + +public final class PaperTypedDataAdapters { + + private final Map, PaperTypedDataAdapter> adapters; + + private PaperTypedDataAdapters(final Map, PaperTypedDataAdapter> adapters) { + this.adapters = adapters; + } + + public static > PaperTypedDataAdapters create( + final Registry registry, + final PaperTypedDataCollector.Factory collectorFactory, + final Consumer consumer + ) { + Map, PaperTypedDataAdapter> adapters = new IdentityHashMap<>(); + COLLECTOR collector = collectorFactory.create(registry, adapters); + + consumer.accept(collector); + + return new PaperTypedDataAdapters<>(adapters); + } + + @SuppressWarnings("unchecked") + public > ADAPTER get(final ResourceKey key) { + return (ADAPTER) this.adapters.getOrDefault(key, PaperTypedDataAdapter.unimplemented()); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataCollector.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataCollector.java new file mode 100644 index 000000000000..1959b84d7b78 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataCollector.java @@ -0,0 +1,40 @@ +package io.papermc.paper.registry.typed; + +import com.mojang.serialization.Codec; +import java.util.Map; +import java.util.function.Function; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import org.jspecify.annotations.Nullable; + +public interface PaperTypedDataCollector { + + void registerUntyped(TYPE type); + + default void registerUntyped(Holder.Reference type) { + this.registerUntyped(type.key()); + } + + void registerUntyped(ResourceKey type); + + void registerIdentity(TYPE type, Function> codecGetter); + + void registerIdentity(Holder.Reference type, Function> codecGetter); + + void registerIdentity(ResourceKey type, Function> codecGetter); + + void register(TYPE type, Function vanillaToApi, Function apiToVanilla); + + default void register(Holder.Reference type, Function vanillaToApi, Function apiToVanilla) { + this.register(type.key(), vanillaToApi, apiToVanilla); + } + + void register(ResourceKey type, Function vanillaToApi, Function apiToVanilla); + + interface Factory> { + + COLLECTOR create(Registry registry, Map, PaperTypedDataAdapter> adapters); + + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/package-info.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/package-info.java similarity index 55% rename from paper-server/src/main/java/io/papermc/paper/registry/data/typed/package-info.java rename to paper-server/src/main/java/io/papermc/paper/registry/typed/package-info.java index 535e3cb038cd..c1a24cf2d68d 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/data/typed/package-info.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/package-info.java @@ -1,4 +1,4 @@ @NullMarked -package io.papermc.paper.registry.data.typed; +package io.papermc.paper.registry.typed; import org.jspecify.annotations.NullMarked; diff --git a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java index e96c2abb6ee2..b41b1dd7f0ec 100644 --- a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java @@ -1,7 +1,7 @@ package io.papermc.paper.world.attribute; import io.papermc.paper.math.Position; -import io.papermc.paper.registry.data.typed.PaperTypedDataAdapter; +import io.papermc.paper.registry.typed.PaperTypedDataAdapter; import io.papermc.paper.util.MCUtil; import net.minecraft.core.BlockPos; import net.minecraft.world.attribute.EnvironmentAttributeSystem; @@ -28,8 +28,8 @@ public API getPositioned(final Position position) { return this.adapter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), MCUtil.toVec3(position))); } - public API getPositioned(final BlockPos blockPos) { - return this.adapter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), blockPos)); + public API getPositioned(final BlockPos pos) { + return this.adapter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), pos)); } @Override @@ -46,9 +46,11 @@ public API getValue(final EnvironmentalAttributeContext context) { } PaperEnvironmentalAttributeContext.CURRENT_CONTEXT.set((PaperEnvironmentalAttributeContext) context); - this.attributeSystem.invalidateTickCache(); // Invalidate cache, otherwise it would return the cached value if it was already requested in the same tick - API value = position == null ? this.getGlobal() : this.adapter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), MCUtil.toVec3(position))); - PaperEnvironmentalAttributeContext.CURRENT_CONTEXT.set(PaperEnvironmentalAttributeContext.EMPTY); - return value; + try { + this.attributeSystem.invalidateTickCache(); // Invalidate cache, otherwise it would return the cached value if it was already requested in the same tick + return position == null ? this.getGlobal() : this.adapter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), MCUtil.toVec3(position))); + } finally { + PaperEnvironmentalAttributeContext.CURRENT_CONTEXT.set(PaperEnvironmentalAttributeContext.EMPTY); + } } } diff --git a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeContext.java b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeContext.java index f7d9b9fe367b..19c86f455539 100644 --- a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeContext.java +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeContext.java @@ -3,8 +3,7 @@ import io.papermc.paper.math.Position; import io.papermc.paper.util.FloatSupplier; import java.util.function.LongSupplier; -import org.jetbrains.annotations.Nullable; -import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; public record PaperEnvironmentalAttributeContext( @Nullable Long time, @@ -14,7 +13,7 @@ public record PaperEnvironmentalAttributeContext( ) implements EnvironmentalAttributeContext { public static final PaperEnvironmentalAttributeContext EMPTY = new PaperEnvironmentalAttributeContext(null, null, null, null); - public static final ThreadLocal<@NonNull PaperEnvironmentalAttributeContext> CURRENT_CONTEXT = ThreadLocal.withInitial(() -> PaperEnvironmentalAttributeContext.EMPTY); + public static final ThreadLocal CURRENT_CONTEXT = ThreadLocal.withInitial(() -> PaperEnvironmentalAttributeContext.EMPTY); public long time(LongSupplier fallbackSupplier) { return this.time != null ? this.time : fallbackSupplier.getAsLong(); @@ -36,19 +35,19 @@ public static class PaperBuilder implements EnvironmentalAttributeContext.Builde private @Nullable Float thunderLevel; @Override - public Builder time(@Nullable final Long time) { + public Builder time(final @Nullable Long time) { this.time = time; return this; } @Override - public Builder position(@Nullable final Position position) { + public Builder position(final @Nullable Position position) { this.position = position; return this; } @Override - public Builder rainLevel(@Nullable final Float rainLevel) { + public Builder rainLevel(final @Nullable Float rainLevel) { this.rainLevel = rainLevel; return this; } @@ -59,7 +58,7 @@ public Builder raining(final boolean raining) { } @Override - public Builder thunderLevel(@Nullable final Float thunderLevel) { + public Builder thunderLevel(final @Nullable Float thunderLevel) { this.thunderLevel = thunderLevel; return this; } diff --git a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java index 5b6f87e8bff9..e2d6bfe2fec2 100644 --- a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java @@ -2,8 +2,8 @@ import io.papermc.paper.adventure.PaperAdventure; import io.papermc.paper.registry.HolderableBase; -import io.papermc.paper.registry.data.typed.PaperTypedDataAdapter; -import io.papermc.paper.registry.data.typed.PaperTypedDataAdapters; +import io.papermc.paper.registry.typed.PaperTypedDataAdapter; +import io.papermc.paper.registry.typed.PaperTypedDataAdapters; import net.minecraft.core.Holder; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.attribute.EnvironmentAttribute; @@ -12,60 +12,60 @@ public final class PaperEnvironmentalAttributeType extends HolderableBase> implements EnvironmentalAttributeType { - private static final PaperTypedDataAdapters ADAPTERS = PaperTypedDataAdapters.create( + private static final PaperTypedDataAdapters> ADAPTERS = PaperTypedDataAdapters.create( BuiltInRegistries.ENVIRONMENT_ATTRIBUTE, PaperEnvironmentalAttributeTypeCollector::new, collector -> { // Audio // collector.register(EnvironmentAttributes.AMBIENT_SOUNDS, toApi, toNms); // collector.register(EnvironmentAttributes.BACKGROUND_MUSIC, toApi, toNms); - collector.registerIdentity(EnvironmentAttributes.FIREFLY_BUSH_SOUNDS, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.MUSIC_VOLUME, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.FIREFLY_BUSH_SOUNDS); + collector.registerIdentity(EnvironmentAttributes.MUSIC_VOLUME); // Gameplay // collector.register(EnvironmentAttributes.BABY_VILLAGER_ACTIVITY, toApi, toNms); // collector.register(EnvironmentAttributes.BED_RULE, toApi, toNms); - collector.registerIdentity(EnvironmentAttributes.BEES_STAY_IN_HIVE, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.CAN_PILLAGER_PATROL_SPAWN, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.CAN_START_RAID, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.CAT_WAKING_UP_GIFT_CHANCE, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.CREAKING_ACTIVE, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.BEES_STAY_IN_HIVE); + collector.registerIdentity(EnvironmentAttributes.CAN_PILLAGER_PATROL_SPAWN); + collector.registerIdentity(EnvironmentAttributes.CAN_START_RAID); + collector.registerIdentity(EnvironmentAttributes.CAT_WAKING_UP_GIFT_CHANCE); + collector.registerIdentity(EnvironmentAttributes.CREAKING_ACTIVE); collector.register(EnvironmentAttributes.EYEBLOSSOM_OPEN, PaperAdventure::asAdventure, PaperAdventure::asVanilla); - collector.registerIdentity(EnvironmentAttributes.FAST_LAVA, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.INCREASED_FIRE_BURNOUT, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.MONSTERS_BURN, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.NETHER_PORTAL_SPAWNS_PIGLINS, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.PIGLINS_ZOMBIFY, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.RESPAWN_ANCHOR_WORKS, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.SKY_LIGHT_LEVEL, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.SNOW_GOLEM_MELTS, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.SURFACE_SLIME_SPAWN_CHANCE, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.TURTLE_EGG_HATCH_CHANCE, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.FAST_LAVA); + collector.registerIdentity(EnvironmentAttributes.INCREASED_FIRE_BURNOUT); + collector.registerIdentity(EnvironmentAttributes.MONSTERS_BURN); + collector.registerIdentity(EnvironmentAttributes.NETHER_PORTAL_SPAWNS_PIGLINS); + collector.registerIdentity(EnvironmentAttributes.PIGLINS_ZOMBIFY); + collector.registerIdentity(EnvironmentAttributes.RESPAWN_ANCHOR_WORKS); + collector.registerIdentity(EnvironmentAttributes.SKY_LIGHT_LEVEL); + collector.registerIdentity(EnvironmentAttributes.SNOW_GOLEM_MELTS); + collector.registerIdentity(EnvironmentAttributes.SURFACE_SLIME_SPAWN_CHANCE); + collector.registerIdentity(EnvironmentAttributes.TURTLE_EGG_HATCH_CHANCE); // collector.register(EnvironmentAttributes.VILLAGER_ACTIVITY, toApi, toNms); - collector.registerIdentity(EnvironmentAttributes.WATER_EVAPORATES, EnvironmentAttribute::valueCodec); + collector.registerIdentity(EnvironmentAttributes.WATER_EVAPORATES); // Visual // collector.register(EnvironmentAttributes.AMBIENT_PARTICLES, toApi, toNms); - collector.registerIdentity(EnvironmentAttributes.CLOUD_COLOR, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.CLOUD_FOG_END_DISTANCE, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.CLOUD_HEIGHT, EnvironmentAttribute::valueCodec); + collector.registerIntAsColor(EnvironmentAttributes.CLOUD_COLOR); + collector.registerIdentity(EnvironmentAttributes.CLOUD_FOG_END_DISTANCE); + collector.registerIdentity(EnvironmentAttributes.CLOUD_HEIGHT); // collector.register(EnvironmentAttributes.DEFAULT_DRIPSTONE_PARTICLE, toApi, toNms); - collector.registerIdentity(EnvironmentAttributes.FOG_COLOR, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.FOG_END_DISTANCE, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.FOG_START_DISTANCE, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.MOON_ANGLE, EnvironmentAttribute::valueCodec); + collector.registerIntAsColor(EnvironmentAttributes.FOG_COLOR); + collector.registerIdentity(EnvironmentAttributes.FOG_END_DISTANCE); + collector.registerIdentity(EnvironmentAttributes.FOG_START_DISTANCE); + collector.registerIdentity(EnvironmentAttributes.MOON_ANGLE); collector.register(EnvironmentAttributes.MOON_PHASE, moonPhase -> io.papermc.paper.world.MoonPhase.values()[moonPhase.ordinal()], moonPhase -> MoonPhase.values()[moonPhase.ordinal()]); - collector.registerIdentity(EnvironmentAttributes.SKY_COLOR, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.SKY_FOG_END_DISTANCE, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.SKY_LIGHT_COLOR, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.SKY_LIGHT_FACTOR, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.STAR_ANGLE, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.STAR_BRIGHTNESS, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.SUN_ANGLE, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.SUNRISE_SUNSET_COLOR, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.WATER_FOG_COLOR, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.WATER_FOG_END_DISTANCE, EnvironmentAttribute::valueCodec); - collector.registerIdentity(EnvironmentAttributes.WATER_FOG_START_DISTANCE, EnvironmentAttribute::valueCodec); + collector.registerIntAsColor(EnvironmentAttributes.SKY_COLOR); + collector.registerIdentity(EnvironmentAttributes.SKY_FOG_END_DISTANCE); + collector.registerIntAsColor(EnvironmentAttributes.SKY_LIGHT_COLOR); + collector.registerIdentity(EnvironmentAttributes.SKY_LIGHT_FACTOR); + collector.registerIdentity(EnvironmentAttributes.STAR_ANGLE); + collector.registerIdentity(EnvironmentAttributes.STAR_BRIGHTNESS); + collector.registerIdentity(EnvironmentAttributes.SUN_ANGLE); + collector.registerIntAsColor(EnvironmentAttributes.SUNRISE_SUNSET_COLOR); + collector.registerIntAsColor(EnvironmentAttributes.WATER_FOG_COLOR); + collector.registerIdentity(EnvironmentAttributes.WATER_FOG_END_DISTANCE); + collector.registerIdentity(EnvironmentAttributes.WATER_FOG_START_DISTANCE); } ); @@ -79,14 +79,9 @@ private PaperEnvironmentalAttributeType(Holder> holder @SuppressWarnings("unchecked") public static EnvironmentalAttributeType of(final Holder holder) { - final PaperTypedDataAdapter adapter = PaperEnvironmentalAttributeType.ADAPTERS.getAdapter(holder.unwrapKey().orElseThrow()); - if (adapter == null) { - throw new IllegalArgumentException("No adapter found for " + holder); - } - if (!adapter.isValued()) { - throw new IllegalStateException("Non-valued adapter is not supported for environmental attribute types: " + holder); - } - return new PaperEnvironmentalAttributeType<>((Holder>) holder, adapter); + final Holder.Reference> reference = (Holder.Reference>) holder; + final PaperTypedDataAdapter adapter = PaperEnvironmentalAttributeType.ADAPTERS.get(reference.key()); + return new PaperEnvironmentalAttributeType<>(reference, adapter); } @Override diff --git a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeTypeCollector.java b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeTypeCollector.java index 30eb1bb69383..058179d39490 100644 --- a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeTypeCollector.java +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeTypeCollector.java @@ -1,27 +1,43 @@ package io.papermc.paper.world.attribute; -import io.papermc.paper.registry.data.typed.AbstractTypedDataCollector; -import io.papermc.paper.registry.data.typed.PaperTypedDataAdapter; +import io.papermc.paper.registry.typed.AbstractTypedDataCollector; +import io.papermc.paper.registry.typed.PaperTypedDataAdapter; import java.util.Map; import java.util.function.Function; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; +import net.minecraft.util.ARGB; +import net.minecraft.world.attribute.AttributeTypes; import net.minecraft.world.attribute.EnvironmentAttribute; -import org.bukkit.craftbukkit.util.Handleable; +import org.bukkit.Color; class PaperEnvironmentalAttributeTypeCollector extends AbstractTypedDataCollector> { - public PaperEnvironmentalAttributeTypeCollector(final Registry> registry, final Map, PaperTypedDataAdapter> adapters) { + public PaperEnvironmentalAttributeTypeCollector(final Registry> registry, final Map>, PaperTypedDataAdapter> adapters) { super(registry, adapters); } - // Not using @Override because of generic types - public > void register(final EnvironmentAttribute dataComponentType, final Function vanillaToApi) { - super.register(dataComponentType, vanillaToApi); + public void registerIdentity(final EnvironmentAttribute attribute) { + super.registerIdentity(attribute, EnvironmentAttribute::valueCodec); + } + + public void registerIntAsColor(final EnvironmentAttribute attribute) { + if (attribute.type() == AttributeTypes.ARGB_COLOR) { + this.register(attribute, Color::fromARGB, Color::asARGB); + } else if (attribute.type() == AttributeTypes.RGB_COLOR) { + this.register(attribute, color -> Color.fromRGB(color & 0x00FFFFFF), color -> ARGB.opaque(color.asRGB())); + } else { + throw new IllegalArgumentException("Environment attribute value cannot be converted as a color: " + attribute.type()); + } + } + + @Override + public void registerUntyped(final EnvironmentAttribute attribute) { + throw new IllegalStateException("Non-typed adapter is not supported for environmental attribute types! got: " + attribute); // TODO should be restricted by API design not at runtime } // Not using @Override because of generic types - public void register(final EnvironmentAttribute dataComponentType, final Function vanillaToApi, final Function apiToVanilla) { - super.register(dataComponentType, vanillaToApi, apiToVanilla); + public void register(final EnvironmentAttribute attribute, final Function vanillaToApi, final Function apiToVanilla) { + super.register(attribute, vanillaToApi, apiToVanilla); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index d03a2af3d27b..da0251c6d5c3 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -2055,7 +2055,7 @@ public net.kyori.adventure.pointer.Pointers pointers() { // Paper end @Override - public @NotNull PaperEnvironmentalAttribute getEnvironmentalAttribute(@NotNull final EnvironmentalAttributeType type) { + public PaperEnvironmentalAttribute getEnvironmentalAttribute(final EnvironmentalAttributeType type) { return new PaperEnvironmentalAttribute<>(this.getHandle().environmentAttributes(), (PaperEnvironmentalAttributeType) type); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java index 3909eb06b920..a94af271dc8c 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java @@ -61,7 +61,6 @@ import org.bukkit.util.BoundingBox; import org.bukkit.util.RayTraceResult; import org.bukkit.util.Vector; -import org.jetbrains.annotations.NotNull; public class CraftBlock implements Block { private final net.minecraft.world.level.LevelAccessor world; @@ -750,7 +749,7 @@ public void randomTick() { // Paper end @Override - public @NotNull T getAttributeValue(@NotNull final EnvironmentalAttributeType type) { - return this.getCraftWorld().getEnvironmentalAttribute(type).getPositioned(this.getPosition()); + public T getAttributeValue(final EnvironmentalAttributeType type) { + return this.getCraftWorld().getEnvironmentalAttribute(type).getPositioned(this.position); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java index 002682049fe8..77d7ef972f6c 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java @@ -582,7 +582,9 @@ public void setData(final io.papermc.paper.datacomponent.DataComponentType.NonVa } private void setDataInternal(final io.papermc.paper.datacomponent.PaperDataComponentType type, final A value) { - this.handle.set(type.getHandle(), type.getAdapter().toVanilla(value, type.getHolder())); + this.handle.set(type.getHandle(), type.getAdapter().toVanilla(value).getOrThrow(message -> { + return new IllegalArgumentException("Failed to encode data component %s (%s)".formatted(type.getKey().asString(), message)); + })); } @Override From b297cad2cb6aca53d0c12e32f218e746e5c042c8 Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Mon, 12 Jan 2026 19:37:40 +0100 Subject: [PATCH 08/15] rebuild patches for 1.21.11 --- .../net/minecraft/world/attribute/WeatherAttributes.java.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paper-server/patches/sources/net/minecraft/world/attribute/WeatherAttributes.java.patch b/paper-server/patches/sources/net/minecraft/world/attribute/WeatherAttributes.java.patch index a7ae3b32275f..199883fed4f0 100644 --- a/paper-server/patches/sources/net/minecraft/world/attribute/WeatherAttributes.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/attribute/WeatherAttributes.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/attribute/WeatherAttributes.java +++ b/net/minecraft/world/attribute/WeatherAttributes.java -@@ -69,12 +_,12 @@ +@@ -67,12 +_,12 @@ return new WeatherAttributes.WeatherAccess() { @Override public float rainLevel() { From c8d728cc8248d1dd0ad780ef3ae5f947003c3535 Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Sat, 31 Jan 2026 19:39:32 +0100 Subject: [PATCH 09/15] move getEnvironmentalAttribute in RegionAccessor --- paper-api/src/main/java/org/bukkit/RegionAccessor.java | 4 ++++ paper-api/src/main/java/org/bukkit/World.java | 4 ---- .../java/org/bukkit/craftbukkit/CraftRegionAccessor.java | 9 +++++++++ .../src/main/java/org/bukkit/craftbukkit/CraftWorld.java | 9 --------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/paper-api/src/main/java/org/bukkit/RegionAccessor.java b/paper-api/src/main/java/org/bukkit/RegionAccessor.java index f86ed60687bb..863f62dbcb67 100644 --- a/paper-api/src/main/java/org/bukkit/RegionAccessor.java +++ b/paper-api/src/main/java/org/bukkit/RegionAccessor.java @@ -1,5 +1,7 @@ package org.bukkit; +import io.papermc.paper.world.attribute.EnvironmentalAttribute; +import io.papermc.paper.world.attribute.EnvironmentalAttributeType; import java.util.Collection; import java.util.List; import java.util.Random; @@ -560,4 +562,6 @@ default T spawn(@NotNull Location location, @NotNull Class */ boolean hasCollisionsIn(@NotNull org.bukkit.util.BoundingBox boundingBox); // Paper end + + @NotNull EnvironmentalAttribute getEnvironmentalAttribute(@NotNull EnvironmentalAttributeType type); } diff --git a/paper-api/src/main/java/org/bukkit/World.java b/paper-api/src/main/java/org/bukkit/World.java index 9d14594f4179..b202bdb84bae 100644 --- a/paper-api/src/main/java/org/bukkit/World.java +++ b/paper-api/src/main/java/org/bukkit/World.java @@ -11,8 +11,6 @@ import java.util.Set; import java.util.function.Consumer; import java.util.function.Predicate; -import io.papermc.paper.world.attribute.EnvironmentalAttribute; -import io.papermc.paper.world.attribute.EnvironmentalAttributeType; import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; @@ -4562,8 +4560,6 @@ default void setNoTickViewDistance(int viewDistance) { @NotNull public Collection getStructures(int x, int z, @NotNull Structure structure); - @NotNull EnvironmentalAttribute getEnvironmentalAttribute(@NotNull EnvironmentalAttributeType type); - /** * Represents various map environment types that a world may be */ diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java index 21d594a39d09..831eea27490b 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java @@ -7,6 +7,9 @@ import java.util.Random; import java.util.function.Consumer; import java.util.function.Predicate; +import io.papermc.paper.world.attribute.EnvironmentalAttributeType; +import io.papermc.paper.world.attribute.PaperEnvironmentalAttribute; +import io.papermc.paper.world.attribute.PaperEnvironmentalAttributeType; import net.minecraft.SharedConstants; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; @@ -501,4 +504,10 @@ public boolean hasCollisionsIn(@org.jetbrains.annotations.NotNull org.bukkit.uti public java.util.Set getFeatureFlags() { return io.papermc.paper.world.flag.PaperFeatureFlagProviderImpl.fromNms(this.getHandle().enabledFeatures()); } + + @Override + public PaperEnvironmentalAttribute getEnvironmentalAttribute(final EnvironmentalAttributeType type) { + // todo should probably restrict the position lookup for LimitedRegion + return new PaperEnvironmentalAttribute<>(this.getHandle().getLevel().environmentAttributes(), (PaperEnvironmentalAttributeType) type); + } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 7fc9570f6ee8..ebc65e3338c6 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -13,10 +13,6 @@ import io.papermc.paper.raytracing.RayTraceTarget; import io.papermc.paper.registry.RegistryAccess; import io.papermc.paper.registry.RegistryKey; -import io.papermc.paper.world.attribute.EnvironmentalAttribute; -import io.papermc.paper.world.attribute.EnvironmentalAttributeType; -import io.papermc.paper.world.attribute.PaperEnvironmentalAttribute; -import io.papermc.paper.world.attribute.PaperEnvironmentalAttributeType; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import java.nio.file.Path; import java.util.ArrayList; @@ -2042,9 +2038,4 @@ public net.kyori.adventure.pointer.Pointers pointers() { return POINTERS_SUPPLIER.view(this); } // Paper end - - @Override - public PaperEnvironmentalAttribute getEnvironmentalAttribute(final EnvironmentalAttributeType type) { - return new PaperEnvironmentalAttribute<>(this.getHandle().environmentAttributes(), (PaperEnvironmentalAttributeType) type); - } } From 510077be005c3622c3e3e923652b1f41c47812b7 Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Sat, 7 Mar 2026 15:15:51 +0100 Subject: [PATCH 10/15] abstract converter a bit --- .../datacomponent/PaperDataComponentType.java | 282 +++++++++--------- .../PaperDataComponentTypeCollector.java | 30 -- .../item/PaperItemEnchantments.java | 8 +- .../typed/AbstractTypedDataCollector.java | 85 ------ .../registry/typed/PaperTypedDataAdapter.java | 57 ---- .../typed/PaperTypedDataAdapters.java | 28 +- .../typed/PaperTypedDataCollector.java | 43 +-- .../registry/typed/TypedDataCollector.java | 125 ++++++++ .../typed/converter/CodecConverter.java | 33 ++ .../typed/converter/CollectionConverter.java | 19 ++ .../registry/typed/converter/Converter.java | 42 +++ .../converter/ConverterClassDispatcher.java | 14 + .../typed/converter/ConverterDispatcher.java | 8 + .../registry/typed/converter/Converters.java | 88 ++++++ .../typed/converter/package-info.java | 4 + .../io/papermc/paper/util/PaperCodecs.java | 2 +- .../PaperEnvironmentalAttribute.java | 28 +- .../PaperEnvironmentalAttributeType.java | 162 ++++++---- ...erEnvironmentalAttributeTypeCollector.java | 43 --- .../craftbukkit/inventory/CraftItemStack.java | 15 +- 20 files changed, 648 insertions(+), 468 deletions(-) delete mode 100644 paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentTypeCollector.java delete mode 100644 paper-server/src/main/java/io/papermc/paper/registry/typed/AbstractTypedDataCollector.java delete mode 100644 paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataAdapter.java create mode 100644 paper-server/src/main/java/io/papermc/paper/registry/typed/TypedDataCollector.java create mode 100644 paper-server/src/main/java/io/papermc/paper/registry/typed/converter/CodecConverter.java create mode 100644 paper-server/src/main/java/io/papermc/paper/registry/typed/converter/CollectionConverter.java create mode 100644 paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converter.java create mode 100644 paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterClassDispatcher.java create mode 100644 paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterDispatcher.java create mode 100644 paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converters.java create mode 100644 paper-server/src/main/java/io/papermc/paper/registry/typed/converter/package-info.java delete mode 100644 paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeTypeCollector.java diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java index 48a3f3d9adf3..c6728a81ebc0 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java @@ -47,11 +47,14 @@ import io.papermc.paper.datacomponent.item.PaperWrittenBookContent; import io.papermc.paper.registry.HolderableBase; import io.papermc.paper.registry.PaperRegistries; -import io.papermc.paper.registry.typed.PaperTypedDataAdapter; import io.papermc.paper.registry.typed.PaperTypedDataAdapters; +import io.papermc.paper.registry.typed.TypedDataCollector; +import io.papermc.paper.registry.typed.converter.Converter; +import io.papermc.paper.registry.typed.converter.Converters; import java.util.Collections; import java.util.HashSet; import java.util.Set; +import java.util.function.Function; import net.minecraft.core.Holder; import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.component.DataComponents; @@ -63,17 +66,10 @@ import net.minecraft.world.item.component.MapPostProcessing; import net.minecraft.world.item.component.ProvidesTrimMaterial; import org.bukkit.DyeColor; -import org.bukkit.craftbukkit.CraftArt; import org.bukkit.craftbukkit.CraftMusicInstrument; import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.damage.CraftDamageType; -import org.bukkit.craftbukkit.entity.CraftCat; import org.bukkit.craftbukkit.entity.CraftChicken; -import org.bukkit.craftbukkit.entity.CraftCow; -import org.bukkit.craftbukkit.entity.CraftFrog; -import org.bukkit.craftbukkit.entity.CraftPig; -import org.bukkit.craftbukkit.entity.CraftVillager; -import org.bukkit.craftbukkit.entity.CraftWolf; import org.bukkit.craftbukkit.entity.CraftZombieNautilus; import org.bukkit.craftbukkit.inventory.CraftMetaFirework; import org.bukkit.craftbukkit.inventory.trim.CraftTrimMaterial; @@ -88,121 +84,135 @@ import org.bukkit.inventory.ItemRarity; import org.jspecify.annotations.Nullable; -import static io.papermc.paper.util.MCUtil.transformUnmodifiable; +import static io.papermc.paper.registry.typed.converter.Converter.direct; +import static io.papermc.paper.registry.typed.converter.Converters.list; +import static io.papermc.paper.registry.typed.converter.Converters.registryElement; +import static io.papermc.paper.registry.typed.converter.Converters.sameName; +import static io.papermc.paper.registry.typed.converter.Converters.sameOrder; +import static io.papermc.paper.registry.typed.converter.Converters.wrapper; -public abstract class PaperDataComponentType extends HolderableBase> implements DataComponentType { +public abstract class PaperDataComponentType extends HolderableBase> implements DataComponentType { - private static final PaperTypedDataAdapters> ADAPTERS = PaperTypedDataAdapters.create( + // this is a hack around generics limitations to prevent + // having to define generics on each register call as seen below, making collectors easier to read: + // collector.register(...) + private static void register(final TypedDataCollector> collector, final net.minecraft.core.component.DataComponentType dataComponentType, final Function vanillaToApi, final Function apiToVanilla) { + collector.register(dataComponentType, vanillaToApi, apiToVanilla); + } + + @SuppressWarnings("RedundantTypeArguments") + private static final PaperTypedDataAdapters> ADAPTERS = PaperTypedDataAdapters., TypedDataCollector.Unvaluable>>create( BuiltInRegistries.DATA_COMPONENT_TYPE, - PaperDataComponentTypeCollector::new, + TypedDataCollector.Unvaluable::new, collector -> { - collector.registerIdentity(DataComponents.MAX_STACK_SIZE); - collector.registerIdentity(DataComponents.MAX_DAMAGE); - collector.registerIdentity(DataComponents.DAMAGE); - collector.registerUntyped(DataComponents.UNBREAKABLE); - collector.register(DataComponents.USE_EFFECTS, PaperUseEffects::new); - collector.registerIdentity(DataComponents.POTION_DURATION_SCALE); - collector.register(DataComponents.CUSTOM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla); - collector.registerIdentity(DataComponents.MINIMUM_ATTACK_CHARGE); - collector.register(DataComponents.DAMAGE_TYPE, nms -> CraftDamageType.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftDamageType.bukkitToMinecraftHolder(api))); - collector.register(DataComponents.ITEM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla); - collector.register(DataComponents.ITEM_MODEL, PaperAdventure::asAdventure, PaperAdventure::asVanilla); - collector.register(DataComponents.LORE, PaperItemLore::new); - collector.register(DataComponents.RARITY, nms -> ItemRarity.valueOf(nms.name()), api -> Rarity.valueOf(api.name())); - collector.register(DataComponents.ENCHANTMENTS, PaperItemEnchantments::new); - collector.register(DataComponents.CAN_PLACE_ON, PaperItemAdventurePredicate::new); - collector.register(DataComponents.CAN_BREAK, PaperItemAdventurePredicate::new); - collector.register(DataComponents.ATTRIBUTE_MODIFIERS, PaperItemAttributeModifiers::new); - collector.register(DataComponents.CUSTOM_MODEL_DATA, PaperCustomModelData::new); - collector.registerIdentity(DataComponents.REPAIR_COST); + final Converter dyeColor = direct( + nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData()) + ); + collector.dispatch(type -> Converter.identity(type.codec())).add( + DataComponents.MAX_STACK_SIZE, + DataComponents.MAX_DAMAGE, + DataComponents.DAMAGE, + DataComponents.POTION_DURATION_SCALE, + DataComponents.MINIMUM_ATTACK_CHARGE, + DataComponents.REPAIR_COST, + DataComponents.ENCHANTMENT_GLINT_OVERRIDE + ); + collector.registerUnvalued(DataComponents.UNBREAKABLE); + collector.register(DataComponents.USE_EFFECTS, wrapper(PaperUseEffects::new)); + register(collector, DataComponents.CUSTOM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla); + register(collector, DataComponents.DAMAGE_TYPE, nms -> CraftDamageType.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftDamageType.bukkitToMinecraftHolder(api))); + register(collector, DataComponents.ITEM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla); + register(collector, DataComponents.ITEM_MODEL, PaperAdventure::asAdventure, PaperAdventure::asVanilla); + collector.register(DataComponents.LORE, wrapper(PaperItemLore::new)); + collector.register(DataComponents.RARITY, sameName(ItemRarity.class, Rarity.class)); + collector.register(DataComponents.ENCHANTMENTS, wrapper(PaperItemEnchantments::of)); + collector.register(DataComponents.CAN_PLACE_ON, wrapper(PaperItemAdventurePredicate::new)); + collector.register(DataComponents.CAN_BREAK, wrapper(PaperItemAdventurePredicate::new)); + collector.register(DataComponents.ATTRIBUTE_MODIFIERS, wrapper(PaperItemAttributeModifiers::new)); + collector.register(DataComponents.CUSTOM_MODEL_DATA, wrapper(PaperCustomModelData::new)); // registerUntyped(DataComponents.CREATIVE_SLOT_LOCK); - collector.registerIdentity(DataComponents.ENCHANTMENT_GLINT_OVERRIDE); - collector.registerUntyped(DataComponents.INTANGIBLE_PROJECTILE); - collector.register(DataComponents.FOOD, PaperFoodProperties::new); - collector.register(DataComponents.CONSUMABLE, PaperConsumable::new); - collector.register(DataComponents.USE_REMAINDER, PaperUseRemainder::new); - collector.register(DataComponents.USE_COOLDOWN, PaperUseCooldown::new); - collector.register(DataComponents.DAMAGE_RESISTANT, PaperDamageResistant::new); - collector.register(DataComponents.TOOL, PaperItemTool::new); - collector.register(DataComponents.ENCHANTABLE, PaperEnchantable::new); - collector.register(DataComponents.EQUIPPABLE, PaperEquippable::new); - collector.register(DataComponents.REPAIRABLE, PaperRepairable::new); - collector.registerUntyped(DataComponents.GLIDER); - collector.register(DataComponents.TOOLTIP_STYLE, PaperAdventure::asAdventure, PaperAdventure::asVanilla); - collector.register(DataComponents.DEATH_PROTECTION, PaperDeathProtection::new); - collector.register(DataComponents.STORED_ENCHANTMENTS, PaperItemEnchantments::new); - collector.register(DataComponents.DYED_COLOR, PaperDyedItemColor::new); - collector.register(DataComponents.MAP_COLOR, PaperMapItemColor::new); - collector.register(DataComponents.MAP_ID, PaperMapId::new); - collector.register(DataComponents.MAP_DECORATIONS, PaperMapDecorations::new); - collector.register(DataComponents.MAP_POST_PROCESSING, nms -> io.papermc.paper.item.MapPostProcessing.valueOf(nms.name()), api -> MapPostProcessing.valueOf(api.name())); - collector.register(DataComponents.CHARGED_PROJECTILES, PaperChargedProjectiles::new); - collector.register(DataComponents.BUNDLE_CONTENTS, PaperBundleContents::new); - collector.register(DataComponents.POTION_CONTENTS, PaperPotionContents::new); - collector.register(DataComponents.SUSPICIOUS_STEW_EFFECTS, PaperSuspiciousStewEffects::new); - collector.register(DataComponents.WRITTEN_BOOK_CONTENT, PaperWrittenBookContent::new); - collector.register(DataComponents.WRITABLE_BOOK_CONTENT, PaperWritableBookContent::new); - collector.register(DataComponents.TRIM, PaperItemArmorTrim::new); + collector.registerUnvalued(DataComponents.INTANGIBLE_PROJECTILE); + collector.register(DataComponents.FOOD, wrapper(PaperFoodProperties::new)); + collector.register(DataComponents.CONSUMABLE, wrapper(PaperConsumable::new)); + collector.register(DataComponents.USE_REMAINDER, wrapper(PaperUseRemainder::new)); + collector.register(DataComponents.USE_COOLDOWN, wrapper(PaperUseCooldown::new)); + collector.register(DataComponents.DAMAGE_RESISTANT, wrapper(PaperDamageResistant::new)); + collector.register(DataComponents.TOOL, wrapper(PaperItemTool::new)); + collector.register(DataComponents.ENCHANTABLE, wrapper(PaperEnchantable::new)); + collector.register(DataComponents.EQUIPPABLE, wrapper(PaperEquippable::new)); + collector.register(DataComponents.REPAIRABLE, wrapper(PaperRepairable::new)); + collector.registerUnvalued(DataComponents.GLIDER); + register(collector, DataComponents.TOOLTIP_STYLE, PaperAdventure::asAdventure, PaperAdventure::asVanilla); + collector.register(DataComponents.DEATH_PROTECTION, wrapper(PaperDeathProtection::new)); + collector.register(DataComponents.STORED_ENCHANTMENTS, wrapper(PaperItemEnchantments::of)); + collector.register(DataComponents.DYED_COLOR, wrapper(PaperDyedItemColor::new)); + collector.register(DataComponents.MAP_COLOR, wrapper(PaperMapItemColor::new)); + collector.register(DataComponents.MAP_ID, wrapper(PaperMapId::new)); + collector.register(DataComponents.MAP_DECORATIONS, wrapper(PaperMapDecorations::new)); + collector.register(DataComponents.MAP_POST_PROCESSING, sameName(MapPostProcessing.class, MapPostProcessing.class)); + collector.register(DataComponents.CHARGED_PROJECTILES, wrapper(PaperChargedProjectiles::new)); + collector.register(DataComponents.BUNDLE_CONTENTS, wrapper(PaperBundleContents::new)); + collector.register(DataComponents.POTION_CONTENTS, wrapper(PaperPotionContents::new)); + collector.register(DataComponents.SUSPICIOUS_STEW_EFFECTS, wrapper(PaperSuspiciousStewEffects::new)); + collector.register(DataComponents.WRITTEN_BOOK_CONTENT, wrapper(PaperWrittenBookContent::new)); + collector.register(DataComponents.WRITABLE_BOOK_CONTENT, wrapper(PaperWritableBookContent::new)); + collector.register(DataComponents.TRIM, wrapper(PaperItemArmorTrim::new)); // debug stick state // entity data // bucket entity data // block entity data - collector.register(DataComponents.INSTRUMENT, nms -> CraftMusicInstrument.minecraftHolderToBukkit(nms.instrument().unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new InstrumentComponent(CraftMusicInstrument.bukkitToMinecraftHolder(api))); - collector.register(DataComponents.PROVIDES_TRIM_MATERIAL, nms -> CraftTrimMaterial.minecraftHolderToBukkit(nms.material().unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new ProvidesTrimMaterial(CraftTrimMaterial.bukkitToMinecraftHolder(api))); - collector.register(DataComponents.OMINOUS_BOTTLE_AMPLIFIER, PaperOminousBottleAmplifier::new); - collector.register(DataComponents.JUKEBOX_PLAYABLE, PaperJukeboxPlayable::new); - collector.register(DataComponents.PROVIDES_BANNER_PATTERNS, PaperRegistries::fromNms, PaperRegistries::toNms); - collector.register( - DataComponents.RECIPES, - nms -> transformUnmodifiable(nms, PaperAdventure::asAdventureKey), - api -> transformUnmodifiable(api, key -> PaperAdventure.asVanilla(Registries.RECIPE, key)) - ); - collector.register(DataComponents.LODESTONE_TRACKER, PaperLodestoneTracker::new); + register(collector, DataComponents.INSTRUMENT, nms -> CraftMusicInstrument.minecraftHolderToBukkit(nms.instrument().unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new InstrumentComponent(CraftMusicInstrument.bukkitToMinecraftHolder(api))); + register(collector, DataComponents.PROVIDES_TRIM_MATERIAL, nms -> CraftTrimMaterial.minecraftHolderToBukkit(nms.material().unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new ProvidesTrimMaterial(CraftTrimMaterial.bukkitToMinecraftHolder(api))); + collector.register(DataComponents.OMINOUS_BOTTLE_AMPLIFIER, wrapper(PaperOminousBottleAmplifier::new)); + collector.register(DataComponents.JUKEBOX_PLAYABLE, wrapper(PaperJukeboxPlayable::new)); + register(collector, DataComponents.PROVIDES_BANNER_PATTERNS, PaperRegistries::fromNms, PaperRegistries::toNms); + collector.register(DataComponents.RECIPES, list(PaperAdventure::asAdventureKey, key -> PaperAdventure.asVanilla(Registries.RECIPE, key))); + collector.register(DataComponents.LODESTONE_TRACKER, wrapper(PaperLodestoneTracker::new)); collector.register(DataComponents.FIREWORK_EXPLOSION, CraftMetaFirework::getEffect, CraftMetaFirework::getExplosion); - collector.register(DataComponents.FIREWORKS, PaperFireworks::new); - collector.register(DataComponents.PROFILE, PaperResolvableProfile::new); - collector.register(DataComponents.NOTE_BLOCK_SOUND, PaperAdventure::asAdventure, PaperAdventure::asVanilla); - collector.register(DataComponents.BANNER_PATTERNS, PaperBannerPatternLayers::new); - collector.register(DataComponents.BASE_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); - collector.register(DataComponents.POT_DECORATIONS, PaperPotDecorations::new); - collector.register(DataComponents.CONTAINER, PaperItemContainerContents::new); - collector.register(DataComponents.BLOCK_STATE, PaperBlockItemDataProperties::new); + collector.register(DataComponents.FIREWORKS, wrapper(PaperFireworks::new)); + collector.register(DataComponents.PROFILE, wrapper(PaperResolvableProfile::new)); + register(collector, DataComponents.NOTE_BLOCK_SOUND, PaperAdventure::asAdventure, PaperAdventure::asVanilla); + collector.register(DataComponents.BANNER_PATTERNS, wrapper(PaperBannerPatternLayers::new)); + collector.register(DataComponents.BASE_COLOR, dyeColor); + collector.register(DataComponents.POT_DECORATIONS, wrapper(PaperPotDecorations::new)); + collector.register(DataComponents.CONTAINER, wrapper(PaperItemContainerContents::new)); + collector.register(DataComponents.BLOCK_STATE, wrapper(PaperBlockItemDataProperties::new)); // bees - // register(DataComponents.LOCK, PaperLockCode::new); - collector.register(DataComponents.CONTAINER_LOOT, PaperSeededContainerLoot::new); + // register(DataComponents.LOCK, wrapper(PaperLockCode::new)); + collector.register(DataComponents.CONTAINER_LOOT, wrapper(PaperSeededContainerLoot::new)); collector.register(DataComponents.BREAK_SOUND, nms -> PaperAdventure.asAdventure(nms.value().location()), PaperAdventure::resolveSound); - collector.register(DataComponents.TOOLTIP_DISPLAY, PaperTooltipDisplay::new); - collector.register(DataComponents.WEAPON, PaperWeapon::new); - collector.register(DataComponents.BLOCKS_ATTACKS, PaperBlocksAttacks::new); - collector.register(DataComponents.PIERCING_WEAPON, PaperPiercingWeapon::new); - collector.register(DataComponents.KINETIC_WEAPON, PaperKineticWeapon::new); - collector.register(DataComponents.ATTACK_RANGE, PaperAttackRange::new); - collector.register(DataComponents.SWING_ANIMATION, PaperSwingAnimation::new); - collector.register(DataComponents.VILLAGER_VARIANT, CraftVillager.CraftType::minecraftHolderToBukkit, CraftVillager.CraftType::bukkitToMinecraftHolder); - collector.register(DataComponents.WOLF_VARIANT, CraftWolf.CraftVariant::minecraftHolderToBukkit, CraftWolf.CraftVariant::bukkitToMinecraftHolder); - collector.register(DataComponents.WOLF_COLLAR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); - collector.register(DataComponents.WOLF_SOUND_VARIANT, CraftWolf.CraftSoundVariant::minecraftHolderToBukkit, CraftWolf.CraftSoundVariant::bukkitToMinecraftHolder); - collector.register(DataComponents.FOX_VARIANT, nms -> org.bukkit.entity.Fox.Type.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.fox.Fox.Variant.byId(api.ordinal())); - collector.register(DataComponents.SALMON_SIZE, nms -> Salmon.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.fish.Salmon.Variant.values()[api.ordinal()]); - collector.register(DataComponents.PARROT_VARIANT, nms -> Parrot.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.parrot.Parrot.Variant.byId(api.ordinal())); - collector.register(DataComponents.TROPICAL_FISH_PATTERN, nms -> TropicalFish.Pattern.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.fish.TropicalFish.Pattern.values()[api.ordinal()]); - collector.register(DataComponents.TROPICAL_FISH_BASE_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); - collector.register(DataComponents.TROPICAL_FISH_PATTERN_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); - collector.register(DataComponents.MOOSHROOM_VARIANT, nms -> MushroomCow.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.cow.MushroomCow.Variant.values()[api.ordinal()]); - collector.register(DataComponents.RABBIT_VARIANT, nms -> Rabbit.Type.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.rabbit.Rabbit.Variant.byId(api.ordinal())); - collector.register(DataComponents.PIG_VARIANT, CraftPig.CraftVariant::minecraftHolderToBukkit, CraftPig.CraftVariant::bukkitToMinecraftHolder); - collector.register(DataComponents.COW_VARIANT, CraftCow.CraftVariant::minecraftHolderToBukkit, CraftCow.CraftVariant::bukkitToMinecraftHolder); - collector.register(DataComponents.CHICKEN_VARIANT, nms -> CraftChicken.CraftVariant.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftChicken.CraftVariant.bukkitToMinecraftHolder(api))); - collector.register(DataComponents.FROG_VARIANT, CraftFrog.CraftVariant::minecraftHolderToBukkit, CraftFrog.CraftVariant::bukkitToMinecraftHolder); - collector.register(DataComponents.ZOMBIE_NAUTILUS_VARIANT, nms -> CraftZombieNautilus.CraftVariant.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftZombieNautilus.CraftVariant.bukkitToMinecraftHolder(api))); - collector.register(DataComponents.HORSE_VARIANT, nms -> Horse.Color.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.equine.Variant.byId(api.ordinal())); - collector.register(DataComponents.PAINTING_VARIANT, CraftArt::minecraftHolderToBukkit, CraftArt::bukkitToMinecraftHolder); - collector.register(DataComponents.LLAMA_VARIANT, nms -> Llama.Color.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.equine.Llama.Variant.byId(api.ordinal())); - collector.register(DataComponents.AXOLOTL_VARIANT, nms -> Axolotl.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.axolotl.Axolotl.Variant.byId(api.ordinal())); - collector.register(DataComponents.CAT_VARIANT, CraftCat.CraftType::minecraftHolderToBukkit, CraftCat.CraftType::bukkitToMinecraftHolder); - collector.register(DataComponents.CAT_COLLAR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); - collector.register(DataComponents.SHEEP_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); - collector.register(DataComponents.SHULKER_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); + collector.register(DataComponents.TOOLTIP_DISPLAY, wrapper(PaperTooltipDisplay::new)); + collector.register(DataComponents.WEAPON, wrapper(PaperWeapon::new)); + collector.register(DataComponents.BLOCKS_ATTACKS, wrapper(PaperBlocksAttacks::new)); + collector.register(DataComponents.PIERCING_WEAPON, wrapper(PaperPiercingWeapon::new)); + collector.register(DataComponents.KINETIC_WEAPON, wrapper(PaperKineticWeapon::new)); + collector.register(DataComponents.ATTACK_RANGE, wrapper(PaperAttackRange::new)); + collector.register(DataComponents.SWING_ANIMATION, wrapper(PaperSwingAnimation::new)); + collector.register(DataComponents.VILLAGER_VARIANT, registryElement(Registries.VILLAGER_TYPE)); + collector.register(DataComponents.WOLF_VARIANT, registryElement(Registries.WOLF_VARIANT)); + collector.register(DataComponents.WOLF_COLLAR, dyeColor); + collector.register(DataComponents.WOLF_SOUND_VARIANT, registryElement(Registries.WOLF_SOUND_VARIANT)); + collector.register(DataComponents.FOX_VARIANT, sameOrder(org.bukkit.entity.Fox.Type.class, net.minecraft.world.entity.animal.fox.Fox.Variant.class)); + collector.register(DataComponents.SALMON_SIZE, sameOrder(Salmon.Variant.class, net.minecraft.world.entity.animal.fish.Salmon.Variant.class)); + collector.register(DataComponents.PARROT_VARIANT, sameOrder(Parrot.Variant.class, net.minecraft.world.entity.animal.parrot.Parrot.Variant.class)); + collector.register(DataComponents.TROPICAL_FISH_PATTERN, sameOrder(TropicalFish.Pattern.class, net.minecraft.world.entity.animal.fish.TropicalFish.Pattern.class)); + collector.register(DataComponents.TROPICAL_FISH_BASE_COLOR, dyeColor); + collector.register(DataComponents.TROPICAL_FISH_PATTERN_COLOR, dyeColor); + collector.register(DataComponents.MOOSHROOM_VARIANT, sameOrder(MushroomCow.Variant.class, net.minecraft.world.entity.animal.cow.MushroomCow.Variant.class)); + collector.register(DataComponents.RABBIT_VARIANT, sameOrder(Rabbit.Type.class, net.minecraft.world.entity.animal.rabbit.Rabbit.Variant.class)); + collector.register(DataComponents.PIG_VARIANT, registryElement(Registries.PIG_VARIANT)); + collector.register(DataComponents.COW_VARIANT, registryElement(Registries.COW_VARIANT)); + register(collector, DataComponents.CHICKEN_VARIANT, nms -> CraftChicken.CraftVariant.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftChicken.CraftVariant.bukkitToMinecraftHolder(api))); + collector.register(DataComponents.FROG_VARIANT, registryElement(Registries.FROG_VARIANT)); + register(collector, DataComponents.ZOMBIE_NAUTILUS_VARIANT, nms -> CraftZombieNautilus.CraftVariant.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftZombieNautilus.CraftVariant.bukkitToMinecraftHolder(api))); + collector.register(DataComponents.HORSE_VARIANT, sameOrder(Horse.Color.class, net.minecraft.world.entity.animal.equine.Variant.class)); + collector.register(DataComponents.PAINTING_VARIANT, registryElement(Registries.PAINTING_VARIANT)); + collector.register(DataComponents.LLAMA_VARIANT, sameOrder(Llama.Color.class, net.minecraft.world.entity.animal.equine.Llama.Variant.class)); + collector.register(DataComponents.AXOLOTL_VARIANT, sameOrder(Axolotl.Variant.class, net.minecraft.world.entity.animal.axolotl.Axolotl.Variant.class)); + collector.register(DataComponents.CAT_VARIANT, registryElement(Registries.CAT_VARIANT)); + collector.register(DataComponents.CAT_COLLAR, dyeColor); + collector.register(DataComponents.SHEEP_COLOR, dyeColor); + collector.register(DataComponents.SHULKER_COLOR, dyeColor); } ); @@ -228,14 +238,14 @@ public static Set minecraftToBukkit(final Set adapter; + private final Converter converter; - private PaperDataComponentType(final Holder> holder, final PaperTypedDataAdapter adapter) { + private PaperDataComponentType(final Holder> holder, final Converter converter) { super(holder); - this.adapter = adapter; + this.converter = converter; } @Override @@ -243,50 +253,50 @@ public boolean isPersistent() { return !this.getHandle().isTransient(); } - public PaperTypedDataAdapter getAdapter() { - return this.adapter; + public Converter getConverter() { + return this.converter; } @SuppressWarnings("unchecked") - public static DataComponentType of(final Holder holder) { - final Holder.Reference> reference = (Holder.Reference>) holder; - final PaperTypedDataAdapter adapter = PaperDataComponentType.ADAPTERS.get(reference.key()); - if (adapter.isUnimplemented()) { - return new Unimplemented<>((Holder>) holder, adapter); - } else if (adapter.isUntyped()) { - return new NonValuedImpl<>((Holder>) holder, adapter); + public static DataComponentType of(final Holder holder) { + final Holder.Reference> reference = (Holder.Reference>) holder; + final Converter converter = PaperDataComponentType.ADAPTERS.get(reference.key()); + if (converter == Converters.unimplemented()) { + return new Unimplemented<>((Holder>) holder, converter); + } else if (converter == Converters.unvalued()) { + return new NonValuedImpl<>((Holder>) holder, converter); } else { - return new ValuedImpl<>((Holder>) holder, adapter); + return new ValuedImpl<>((Holder>) holder, converter); } } - public static final class NonValuedImpl extends PaperDataComponentType implements NonValued { + public static final class NonValuedImpl extends PaperDataComponentType implements NonValued { NonValuedImpl( - final Holder> holder, - final PaperTypedDataAdapter adapter + final Holder> holder, + final Converter adapter ) { super(holder, adapter); } } - public static final class ValuedImpl extends PaperDataComponentType implements Valued { + public static final class ValuedImpl extends PaperDataComponentType implements Valued { ValuedImpl( - final Holder> holder, - final PaperTypedDataAdapter adapter + final Holder> holder, + final Converter converter ) { - super(holder, adapter); + super(holder, converter); } } - public static final class Unimplemented extends PaperDataComponentType { + public static final class Unimplemented extends PaperDataComponentType { public Unimplemented( - final Holder> holder, - final PaperTypedDataAdapter adapter + final Holder> holder, + final Converter converter ) { - super(holder, adapter); + super(holder, converter); } } } diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentTypeCollector.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentTypeCollector.java deleted file mode 100644 index 824bbea445ac..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentTypeCollector.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.papermc.paper.datacomponent; - -import io.papermc.paper.registry.typed.AbstractTypedDataCollector; -import io.papermc.paper.registry.typed.PaperTypedDataAdapter; -import java.util.Map; -import java.util.function.Function; -import net.minecraft.core.Registry; -import net.minecraft.core.component.DataComponentType; -import net.minecraft.resources.ResourceKey; -import org.bukkit.craftbukkit.util.Handleable; - -class PaperDataComponentTypeCollector extends AbstractTypedDataCollector> { - - public PaperDataComponentTypeCollector(final Registry> registry, final Map>, PaperTypedDataAdapter> adapters) { - super(registry, adapters); - } - - public void registerIdentity(final DataComponentType dataComponentType) { - super.registerIdentity(dataComponentType, DataComponentType::codec); - } - - // Not using @Override because of generic types - public void register(final DataComponentType dataComponentType, final Function vanillaToApi, final Function apiToVanilla) { - super.register(dataComponentType, vanillaToApi, apiToVanilla); - } - - public > void register(final DataComponentType dataComponentType, final Function vanillaToApi) { - this.register(dataComponentType, vanillaToApi, Handleable::getHandle); - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperItemEnchantments.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperItemEnchantments.java index 489e77f4f04f..000fe495eed0 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperItemEnchantments.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperItemEnchantments.java @@ -16,8 +16,8 @@ public record PaperItemEnchantments( Map enchantments // API values are stored externally as the concept of a lazy key transformer map does not make much sense ) implements ItemEnchantments, Handleable { - public PaperItemEnchantments(final net.minecraft.world.item.enchantment.ItemEnchantments itemEnchantments) { - this(itemEnchantments, convert(itemEnchantments)); + public static PaperItemEnchantments of(final net.minecraft.world.item.enchantment.ItemEnchantments itemEnchantments) { + return new PaperItemEnchantments(itemEnchantments, convert(itemEnchantments)); } private static Map convert(final net.minecraft.world.item.enchantment.ItemEnchantments itemEnchantments) { @@ -62,14 +62,14 @@ public ItemEnchantments.Builder addAll(final Map enchantme public ItemEnchantments build() { final net.minecraft.world.item.enchantment.ItemEnchantments initialEnchantments = net.minecraft.world.item.enchantment.ItemEnchantments.EMPTY; if (this.enchantments.isEmpty()) { - return new PaperItemEnchantments(initialEnchantments); + return PaperItemEnchantments.of(initialEnchantments); } final net.minecraft.world.item.enchantment.ItemEnchantments.Mutable mutable = new net.minecraft.world.item.enchantment.ItemEnchantments.Mutable(initialEnchantments); this.enchantments.forEach((enchantment, level) -> mutable.set(CraftEnchantment.bukkitToMinecraftHolder(enchantment), level) ); - return new PaperItemEnchantments(mutable.toImmutable()); + return PaperItemEnchantments.of(mutable.toImmutable()); } } } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/AbstractTypedDataCollector.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/AbstractTypedDataCollector.java deleted file mode 100644 index e446c95e120a..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/AbstractTypedDataCollector.java +++ /dev/null @@ -1,85 +0,0 @@ -package io.papermc.paper.registry.typed; - -import com.mojang.serialization.Codec; -import java.util.Map; -import java.util.function.Function; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.resources.ResourceKey; -import org.jspecify.annotations.Nullable; - -// This class exists only to be implemented, implementations must override the following register method: -// void register(final TYPE type, final Function vanillaToApi, final Function apiToVanilla) -// BUT should NOT use the @Override annotation, this is a hack around generics limitations to prevent -// having to define generics on each register call as seen below, making collectors easier to read: -// collector.register(...) -public abstract class AbstractTypedDataCollector implements PaperTypedDataCollector { - - private final Registry registry; - private final Map, PaperTypedDataAdapter> adapters; - - protected AbstractTypedDataCollector( - final Registry registry, - final Map, PaperTypedDataAdapter> adapters - ) { - this.registry = registry; - this.adapters = adapters; - } - - private ResourceKey getKey(final TYPE type) { - return this.registry.getResourceKey(type).orElseThrow(); - } - - @Override - public void registerUntyped(final TYPE type) { - this.registerUntyped(this.getKey(type)); - } - - @Override - public void registerUntyped(final ResourceKey type) { - this.registerInternal(type, PaperTypedDataAdapter.untyped()); - } - - @Override - public void registerIdentity(final TYPE type, final Function> codecGetter) { - this.registerInternal(this.getKey(type), Function.identity(), Function.identity(), codecGetter.apply(type)); - } - - @Override - public void registerIdentity(final Holder.Reference type, final Function> codecGetter) { - this.registerInternal(type.key(), Function.identity(), Function.identity(), codecGetter.apply(type.value())); - } - - @Override - public void registerIdentity(final ResourceKey type, final Function> codecGetter) { - this.registerInternal(type, Function.identity(), Function.identity(), codecGetter.apply(this.registry.getValueOrThrow(type))); - } - - @Override - public void register(final TYPE type, final Function vanillaToApi, final Function apiToVanilla) { - this.register(this.getKey(type), vanillaToApi, apiToVanilla); - } - - @Override - public void register(final ResourceKey type, final Function vanillaToApi, final Function apiToVanilla) { - this.registerInternal(type, vanillaToApi, apiToVanilla, null); - } - - private void registerInternal( - final ResourceKey key, - final Function vanillaToApi, - final Function apiToVanilla, - final @Nullable Codec codec - ) { - this.registerInternal(key, new PaperTypedDataAdapter<>(vanillaToApi, apiToVanilla, codec)); - } - - private void registerInternal( - final ResourceKey key, - final PaperTypedDataAdapter adapter - ) { - if (this.adapters.put(key, adapter) != null) { - throw new IllegalStateException("Duplicate adapter registration for " + key); - } - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataAdapter.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataAdapter.java deleted file mode 100644 index cfc896013b62..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataAdapter.java +++ /dev/null @@ -1,57 +0,0 @@ -package io.papermc.paper.registry.typed; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; -import java.util.function.Function; -import net.minecraft.util.NullOps; -import net.minecraft.util.Unit; -import org.bukkit.craftbukkit.CraftRegistry; -import org.jspecify.annotations.Nullable; - -public record PaperTypedDataAdapter( - Function vanillaToApi, - Function apiToVanilla, - @Nullable Codec codec -) { - private static final PaperTypedDataAdapter UNIMPLEMENTED = new PaperTypedDataAdapter<>($ -> { - throw new UnsupportedOperationException("Cannot convert an unimplemented type to an API value"); - }, $ -> { - throw new UnsupportedOperationException("Cannot convert an API value to an unimplemented type"); - }, null); - - private static final PaperTypedDataAdapter UNTYPED = new PaperTypedDataAdapter<>($ -> { - throw new UnsupportedOperationException("Cannot convert the Unit type to an API value"); - }, $ -> Unit.INSTANCE, null); - - @SuppressWarnings("unchecked") - public static PaperTypedDataAdapter unimplemented() { - return (PaperTypedDataAdapter) UNIMPLEMENTED; - } - - @SuppressWarnings("unchecked") - public static PaperTypedDataAdapter untyped() { - return (PaperTypedDataAdapter) UNTYPED; - } - - public boolean isUntyped() { - return this == UNTYPED; - } - - public boolean isUnimplemented() { - return this == UNIMPLEMENTED; - } - - public DataResult toVanilla(final API value) { - final NMS nms = this.apiToVanilla.apply(value); - if (this.codec != null) { - return this.codec.encodeStart(CraftRegistry.getMinecraftRegistry().createSerializationContext(NullOps.INSTANCE), nms) - .error().map(error -> DataResult.error(error::message, nms)).orElseGet(() -> DataResult.success(nms)); - } - - return DataResult.success(nms); - } - - public API fromVanilla(final NMS value) { - return this.vanillaToApi.apply(value); - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataAdapters.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataAdapters.java index a2cadf22f523..77597bff790e 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataAdapters.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataAdapters.java @@ -1,34 +1,36 @@ package io.papermc.paper.registry.typed; +import io.papermc.paper.registry.typed.converter.Converter; +import io.papermc.paper.registry.typed.converter.Converters; import java.util.IdentityHashMap; import java.util.Map; import java.util.function.Consumer; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; -public final class PaperTypedDataAdapters { +public final class PaperTypedDataAdapters { - private final Map, PaperTypedDataAdapter> adapters; + private final Map, Converter> converters; - private PaperTypedDataAdapters(final Map, PaperTypedDataAdapter> adapters) { - this.adapters = adapters; + private PaperTypedDataAdapters(final Map, Converter> converters) { + this.converters = converters; } - public static > PaperTypedDataAdapters create( - final Registry registry, - final PaperTypedDataCollector.Factory collectorFactory, - final Consumer consumer + public static > PaperTypedDataAdapters create( + final Registry registry, + final PaperTypedDataCollector.Factory collectorFactory, + final Consumer consumer ) { - Map, PaperTypedDataAdapter> adapters = new IdentityHashMap<>(); - COLLECTOR collector = collectorFactory.create(registry, adapters); + final Map, Converter> converters = new IdentityHashMap<>(); + final C collector = collectorFactory.create(registry, converters); consumer.accept(collector); - return new PaperTypedDataAdapters<>(adapters); + return new PaperTypedDataAdapters<>(converters); } @SuppressWarnings("unchecked") - public > ADAPTER get(final ResourceKey key) { - return (ADAPTER) this.adapters.getOrDefault(key, PaperTypedDataAdapter.unimplemented()); + public > A get(final ResourceKey key) { + return (A) this.converters.getOrDefault(key, Converters.unimplemented()); } } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataCollector.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataCollector.java index 1959b84d7b78..f475b80cc0c7 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataCollector.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataCollector.java @@ -1,40 +1,49 @@ package io.papermc.paper.registry.typed; -import com.mojang.serialization.Codec; +import io.papermc.paper.registry.typed.converter.Converter; +import io.papermc.paper.registry.typed.converter.ConverterClassDispatcher; +import io.papermc.paper.registry.typed.converter.ConverterDispatcher; import java.util.Map; import java.util.function.Function; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; -import org.jspecify.annotations.Nullable; -public interface PaperTypedDataCollector { +public interface PaperTypedDataCollector { - void registerUntyped(TYPE type); + interface Unvalued { + void registerUnvalued(T type); - default void registerUntyped(Holder.Reference type) { - this.registerUntyped(type.key()); - } + default void registerUnvalued(final Holder.Reference type) { + this.registerUnvalued(type.key()); + } - void registerUntyped(ResourceKey type); + void registerUnvalued(ResourceKey type); + } - void registerIdentity(TYPE type, Function> codecGetter); + void register(T type, Function vanillaToApi, Function apiToVanilla); - void registerIdentity(Holder.Reference type, Function> codecGetter); + default void register(final Holder.Reference type, final Function vanillaToApi, final Function apiToVanilla) { + this.register(type.key(), vanillaToApi, apiToVanilla); + } - void registerIdentity(ResourceKey type, Function> codecGetter); + void register(ResourceKey type, Function vanillaToApi, Function apiToVanilla); - void register(TYPE type, Function vanillaToApi, Function apiToVanilla); + void register(T type, Converter converter); - default void register(Holder.Reference type, Function vanillaToApi, Function apiToVanilla) { - this.register(type.key(), vanillaToApi, apiToVanilla); + default void register(final Holder.Reference type, final Converter converter) { + this.register(type.key(), converter); } - void register(ResourceKey type, Function vanillaToApi, Function apiToVanilla); + void register(ResourceKey type, Converter converter); + + ConverterDispatcher dispatch(Function> converter); + + ConverterClassDispatcher dispatchClass(Function, Converter> converter); - interface Factory> { + interface Factory> { - COLLECTOR create(Registry registry, Map, PaperTypedDataAdapter> adapters); + C create(Registry registry, Map, Converter> adapters); } } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/TypedDataCollector.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/TypedDataCollector.java new file mode 100644 index 000000000000..1110ab123216 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/TypedDataCollector.java @@ -0,0 +1,125 @@ +package io.papermc.paper.registry.typed; + +import io.papermc.paper.registry.typed.converter.Converter; +import io.papermc.paper.registry.typed.converter.ConverterClassDispatcher; +import io.papermc.paper.registry.typed.converter.ConverterDispatcher; +import io.papermc.paper.registry.typed.converter.Converters; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Map; +import java.util.function.Function; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; + +public class TypedDataCollector implements PaperTypedDataCollector { + + private final Registry registry; + private final Map, Converter> converters; + + public TypedDataCollector( + final Registry registry, + final Map, Converter> converters + ) { + this.registry = registry; + this.converters = converters; + } + + protected ResourceKey getKey(final T type) { + return this.registry.getResourceKey(type).orElseThrow(); + } + + @Override + public void register(final T type, final Function vanillaToApi, final Function apiToVanilla) { + this.register(this.getKey(type), vanillaToApi, apiToVanilla); + } + + @Override + public void register(final ResourceKey type, final Function vanillaToApi, final Function apiToVanilla) { + this.registerInternal(type, vanillaToApi, apiToVanilla); + } + + @Override + public void register(final T type, final Converter converter) { + this.register(this.getKey(type), converter); + } + + @Override + public void register(final ResourceKey type, final Converter converter) { + this.registerInternal(type, converter); + } + + @Override + public ConverterDispatcher dispatch(final Function> converter) { + return new ConverterDispatcher<>() { + @Override + public void add(final Iterable types) { + types.forEach(type -> { + TypedDataCollector.this.register(TypedDataCollector.this.getKey(type), converter.apply(type)); + }); + } + + @Override + public void add(final T type, final T... types) { + TypedDataCollector.this.register(TypedDataCollector.this.getKey(type), converter.apply(type)); + for (final T t : types) { + TypedDataCollector.this.register(TypedDataCollector.this.getKey(t), converter.apply(t)); + } + } + }; + } + + @Override + public ConverterClassDispatcher dispatchClass(final Function, Converter> converter) { + return (from, toType, toValueClass) -> { + for (final Field field : from.getDeclaredFields()) { + final int mod = field.getModifiers(); + if (!Modifier.isStatic(mod) || !Modifier.isPublic(mod)) { + continue; + } + + final Class valueClass = toValueClass.apply(field); + if (valueClass == null) { + continue; + } + try { + TypedDataCollector.this.register(TypedDataCollector.this.getKey(toType.apply(field)), converter.apply(valueClass)); + } catch (final ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + }; + } + + protected void registerInternal( + final ResourceKey key, + final Function vanillaToApi, + final Function apiToVanilla + ) { + this.registerInternal(key, Converter.direct(vanillaToApi, apiToVanilla)); + } + + protected void registerInternal( + final ResourceKey key, + final Converter converter + ) { + if (this.converters.put(key, converter) != null) { + throw new IllegalStateException("Duplicate adapter registration for " + key); + } + } + + public static class Unvaluable extends TypedDataCollector implements PaperTypedDataCollector, Unvalued { + public Unvaluable(final Registry registry, final Map, Converter> converters) { + super(registry, converters); + } + + @Override + public void registerUnvalued(final T type) { + this.registerUnvalued(this.getKey(type)); + } + + @Override + public void registerUnvalued(final ResourceKey type) { + this.registerInternal(type, Converters.unvalued()); + } + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/CodecConverter.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/CodecConverter.java new file mode 100644 index 000000000000..ece5b43ac5ba --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/CodecConverter.java @@ -0,0 +1,33 @@ +package io.papermc.paper.registry.typed.converter; + +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Encoder; +import java.util.Optional; +import net.minecraft.util.NullOps; +import net.minecraft.util.Unit; +import org.bukkit.craftbukkit.CraftRegistry; + +public record CodecConverter( + Converter converter, + Encoder serializer +) implements Converter { + + @Override + public M toVanilla(final A value) { + return this.converter.toVanilla(value); + } + + @Override + public A fromVanilla(final M value) { + return this.converter.fromVanilla(value); + } + + public Optional validate(final M value, final boolean requireRegistryAccess) { + DynamicOps ops = NullOps.INSTANCE; + if (requireRegistryAccess) { + ops = CraftRegistry.getMinecraftRegistry().createSerializationContext(ops); + } + return this.serializer.encodeStart(ops, value).error().map(DataResult.Error::message); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/CollectionConverter.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/CollectionConverter.java new file mode 100644 index 000000000000..924b92698e24 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/CollectionConverter.java @@ -0,0 +1,19 @@ +package io.papermc.paper.registry.typed.converter; + +import io.papermc.paper.util.MCUtil; +import java.util.Collection; + +public record CollectionConverter( + Converter converter +) implements Converter, Collection> { + + @Override + public Collection toVanilla(final Collection value) { + return MCUtil.transformUnmodifiable(value, this.converter::toVanilla); + } + + @Override + public Collection fromVanilla(final Collection value) { + return MCUtil.transformUnmodifiable(value, this.converter::fromVanilla); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converter.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converter.java new file mode 100644 index 000000000000..e6d178887c6b --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converter.java @@ -0,0 +1,42 @@ +package io.papermc.paper.registry.typed.converter; + +import com.mojang.serialization.Encoder; +import java.util.function.Function; + +public interface Converter { + + static Converter direct(final Function vanillaToApi, final Function apiToVanilla) { + return new Converter<>() { + @Override + public M toVanilla(final A value) { + return apiToVanilla.apply(value); + } + + @Override + public A fromVanilla(final M value) { + return vanillaToApi.apply(value); + } + }; + } + + static Converter identity() { + final class Holder { + private static final Converter NO_OP = direct(Function.identity(), Function.identity()); + } + + //noinspection unchecked + return (Converter) Holder.NO_OP; + } + + static Converter identity(final Encoder serializer) { + return new CodecConverter<>(identity(), serializer); + } + + default CodecConverter serializable(final Encoder serializer) { + return new CodecConverter<>(this, serializer); + } + + M toVanilla(A value); + + A fromVanilla(M value); +} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterClassDispatcher.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterClassDispatcher.java new file mode 100644 index 000000000000..952efab48c26 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterClassDispatcher.java @@ -0,0 +1,14 @@ +package io.papermc.paper.registry.typed.converter; + +import java.lang.reflect.Field; +import java.util.function.Function; +import org.jspecify.annotations.Nullable; + +public interface ConverterClassDispatcher { + + void scanConstants(Class from, ReflectiveFunction toType, Function> toValueClass); + + interface ReflectiveFunction { + T apply(Field field) throws ReflectiveOperationException; + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterDispatcher.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterDispatcher.java new file mode 100644 index 000000000000..779ff523b3fb --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterDispatcher.java @@ -0,0 +1,8 @@ +package io.papermc.paper.registry.typed.converter; + +public interface ConverterDispatcher { + + void add(Iterable types); + + void add(T type, T... types); +} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converters.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converters.java new file mode 100644 index 000000000000..cf488811b650 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converters.java @@ -0,0 +1,88 @@ +package io.papermc.paper.registry.typed.converter; + +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import net.minecraft.util.Unit; +import org.bukkit.Keyed; +import org.bukkit.craftbukkit.CraftRegistry; +import org.bukkit.craftbukkit.util.Handleable; + +import static io.papermc.paper.util.MCUtil.transformUnmodifiable; + +public final class Converters { + + public static , A extends Enum> Converter sameName(final Class apiEnum, final Class internalEnum) { + return Converter.direct( + value -> Enum.valueOf(apiEnum, value.name()), + value -> Enum.valueOf(internalEnum, value.name()) + ); + } + + public static , A extends Enum> Converter sameOrder(final Class apiEnum, final Class internalEnum) { + final A[] apiValues = apiEnum.getEnumConstants(); + final M[] internalValues = internalEnum.getEnumConstants(); + return Converter.direct( + value -> apiValues[value.ordinal()], + value -> internalValues[value.ordinal()] + ); + } + + public static Converter, Collection> collection(final Function vanillaToApi, final Function apiToVanilla) { + return Converter.direct( + collection -> transformUnmodifiable(collection, vanillaToApi), + collection -> transformUnmodifiable(collection, apiToVanilla) + ); + } + + public static Converter, List> list(final Function vanillaToApi, final Function apiToVanilla) { + return Converter.direct( + list -> transformUnmodifiable(list, vanillaToApi), + list -> transformUnmodifiable(list, apiToVanilla) + ); + } + + public static Converter, Set> set(final Function vanillaToApi, final Function apiToVanilla) { + return Converter.direct( + set -> set.stream().map(vanillaToApi).collect(Collectors.toUnmodifiableSet()), + set -> set.stream().map(apiToVanilla).collect(Collectors.toUnmodifiableSet()) + ); + } + + // make sure that no custom logic run in the specialized methods under implementation + public static Converter, A> registryElement(final ResourceKey> registryKey) { // todo remove Keyed + return Converter.direct( + holder -> CraftRegistry.minecraftHolderToBukkit(holder, registryKey), + CraftRegistry::bukkitToMinecraftHolder + ); + } + + public static > Converter wrapper(final Function vanillaToApi) { + return Converter.direct(vanillaToApi, Handleable::getHandle); + } + + private static final Converter UNIMPLEMENTED = Converter.direct($ -> { + throw new UnsupportedOperationException("Cannot convert an unimplemented type to an API value"); + }, $ -> { + throw new UnsupportedOperationException("Cannot convert an API value to an unimplemented type"); + }); + + private static final Converter UNVALUED = Converter.direct($ -> { + throw new UnsupportedOperationException("Cannot convert the Unit type to an API value"); + }, $ -> Unit.INSTANCE); + + @SuppressWarnings("unchecked") + public static Converter unimplemented() { + return (Converter) UNIMPLEMENTED; + } + + @SuppressWarnings("unchecked") + public static Converter unvalued() { + return (Converter) UNVALUED; + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/package-info.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/package-info.java new file mode 100644 index 000000000000..fb7eef83f80f --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.papermc.paper.registry.typed.converter; + +import org.jspecify.annotations.NullMarked; diff --git a/paper-server/src/main/java/io/papermc/paper/util/PaperCodecs.java b/paper-server/src/main/java/io/papermc/paper/util/PaperCodecs.java index 5eb2d60042c0..bb33d9b4eb56 100644 --- a/paper-server/src/main/java/io/papermc/paper/util/PaperCodecs.java +++ b/paper-server/src/main/java/io/papermc/paper/util/PaperCodecs.java @@ -34,7 +34,7 @@ public final class PaperCodecs { }, TriState::name); /** - * This codec is lenient on decoding and encoding compared to native OptionalFieldCodec + * This serializer is lenient on decoding and encoding compared to native OptionalFieldCodec * which only has options to be lenient on decoding. */ public static MapCodec> lenientCodec(final String name, final Codec codec) { diff --git a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java index b41b1dd7f0ec..1d22a51d6a59 100644 --- a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java @@ -1,39 +1,39 @@ package io.papermc.paper.world.attribute; import io.papermc.paper.math.Position; -import io.papermc.paper.registry.typed.PaperTypedDataAdapter; +import io.papermc.paper.registry.typed.converter.Converter; import io.papermc.paper.util.MCUtil; import net.minecraft.core.BlockPos; import net.minecraft.world.attribute.EnvironmentAttributeSystem; -public class PaperEnvironmentalAttribute implements EnvironmentalAttribute { +public class PaperEnvironmentalAttribute implements EnvironmentalAttribute { private final EnvironmentAttributeSystem attributeSystem; - private final PaperEnvironmentalAttributeType type; - private final PaperTypedDataAdapter adapter; + private final PaperEnvironmentalAttributeType type; + private final Converter converter; - public PaperEnvironmentalAttribute(final EnvironmentAttributeSystem attributeSystem, final PaperEnvironmentalAttributeType type) { + public PaperEnvironmentalAttribute(final EnvironmentAttributeSystem attributeSystem, final PaperEnvironmentalAttributeType type) { this.attributeSystem = attributeSystem; this.type = type; - this.adapter = type.getAdapter(); + this.converter = type.getConverter(); } @Override - public API getGlobal() { - return this.adapter.fromVanilla(this.attributeSystem.getDimensionValue(this.type.getHandle())); + public A getGlobal() { + return this.converter.fromVanilla(this.attributeSystem.getDimensionValue(this.type.getHandle())); } @Override - public API getPositioned(final Position position) { - return this.adapter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), MCUtil.toVec3(position))); + public A getPositioned(final Position position) { + return this.converter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), MCUtil.toVec3(position))); } - public API getPositioned(final BlockPos pos) { - return this.adapter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), pos)); + public A getPositioned(final BlockPos pos) { + return this.converter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), pos)); } @Override - public API getValue(final EnvironmentalAttributeContext context) { + public A getValue(final EnvironmentalAttributeContext context) { if (context.equals(PaperEnvironmentalAttributeContext.EMPTY)) { // No field is set, return the global value to prevent invalidating cache return this.getGlobal(); @@ -48,7 +48,7 @@ public API getValue(final EnvironmentalAttributeContext context) { PaperEnvironmentalAttributeContext.CURRENT_CONTEXT.set((PaperEnvironmentalAttributeContext) context); try { this.attributeSystem.invalidateTickCache(); // Invalidate cache, otherwise it would return the cached value if it was already requested in the same tick - return position == null ? this.getGlobal() : this.adapter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), MCUtil.toVec3(position))); + return position == null ? this.getGlobal() : this.converter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), MCUtil.toVec3(position))); } finally { PaperEnvironmentalAttributeContext.CURRENT_CONTEXT.set(PaperEnvironmentalAttributeContext.EMPTY); } diff --git a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java index e2d6bfe2fec2..ef56dd4df918 100644 --- a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java @@ -2,94 +2,130 @@ import io.papermc.paper.adventure.PaperAdventure; import io.papermc.paper.registry.HolderableBase; -import io.papermc.paper.registry.typed.PaperTypedDataAdapter; import io.papermc.paper.registry.typed.PaperTypedDataAdapters; +import io.papermc.paper.registry.typed.TypedDataCollector; +import io.papermc.paper.registry.typed.converter.Converter; +import java.util.IdentityHashMap; +import java.util.Map; import net.minecraft.core.Holder; import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.util.ARGB; +import net.minecraft.util.TriState; +import net.minecraft.util.Util; +import net.minecraft.world.attribute.AttributeType; +import net.minecraft.world.attribute.AttributeTypes; import net.minecraft.world.attribute.EnvironmentAttribute; import net.minecraft.world.attribute.EnvironmentAttributes; import net.minecraft.world.level.MoonPhase; +import org.bukkit.Color; -public final class PaperEnvironmentalAttributeType extends HolderableBase> implements EnvironmentalAttributeType { +import static io.papermc.paper.registry.typed.converter.Converter.direct; - private static final PaperTypedDataAdapters> ADAPTERS = PaperTypedDataAdapters.create( +public final class PaperEnvironmentalAttributeType extends HolderableBase> implements EnvironmentalAttributeType { + + @SuppressWarnings("RedundantTypeArguments") + private static final PaperTypedDataAdapters> ADAPTERS = PaperTypedDataAdapters., TypedDataCollector>>create( BuiltInRegistries.ENVIRONMENT_ATTRIBUTE, - PaperEnvironmentalAttributeTypeCollector::new, + TypedDataCollector::new, collector -> { - // Audio - // collector.register(EnvironmentAttributes.AMBIENT_SOUNDS, toApi, toNms); - // collector.register(EnvironmentAttributes.BACKGROUND_MUSIC, toApi, toNms); - collector.registerIdentity(EnvironmentAttributes.FIREFLY_BUSH_SOUNDS); - collector.registerIdentity(EnvironmentAttributes.MUSIC_VOLUME); + final Converter intAsColor = direct( + Color::fromARGB, + Color::asARGB + ); + final Converter intAsOpaqueColor = direct( + color -> Color.fromRGB(color & 0x00FFFFFF), color -> ARGB.opaque(color.asRGB()) + ); + final Converter triState = direct(PaperAdventure::asAdventure, PaperAdventure::asVanilla); + final Converter moonPhase = direct( + phase -> io.papermc.paper.world.MoonPhase.values()[phase.ordinal()], + phase -> MoonPhase.values()[phase.ordinal()] + ); - // Gameplay - // collector.register(EnvironmentAttributes.BABY_VILLAGER_ACTIVITY, toApi, toNms); - // collector.register(EnvironmentAttributes.BED_RULE, toApi, toNms); - collector.registerIdentity(EnvironmentAttributes.BEES_STAY_IN_HIVE); - collector.registerIdentity(EnvironmentAttributes.CAN_PILLAGER_PATROL_SPAWN); - collector.registerIdentity(EnvironmentAttributes.CAN_START_RAID); - collector.registerIdentity(EnvironmentAttributes.CAT_WAKING_UP_GIFT_CHANCE); - collector.registerIdentity(EnvironmentAttributes.CREAKING_ACTIVE); - collector.register(EnvironmentAttributes.EYEBLOSSOM_OPEN, PaperAdventure::asAdventure, PaperAdventure::asVanilla); - collector.registerIdentity(EnvironmentAttributes.FAST_LAVA); - collector.registerIdentity(EnvironmentAttributes.INCREASED_FIRE_BURNOUT); - collector.registerIdentity(EnvironmentAttributes.MONSTERS_BURN); - collector.registerIdentity(EnvironmentAttributes.NETHER_PORTAL_SPAWNS_PIGLINS); - collector.registerIdentity(EnvironmentAttributes.PIGLINS_ZOMBIFY); - collector.registerIdentity(EnvironmentAttributes.RESPAWN_ANCHOR_WORKS); - collector.registerIdentity(EnvironmentAttributes.SKY_LIGHT_LEVEL); - collector.registerIdentity(EnvironmentAttributes.SNOW_GOLEM_MELTS); - collector.registerIdentity(EnvironmentAttributes.SURFACE_SLIME_SPAWN_CHANCE); - collector.registerIdentity(EnvironmentAttributes.TURTLE_EGG_HATCH_CHANCE); - // collector.register(EnvironmentAttributes.VILLAGER_ACTIVITY, toApi, toNms); - collector.registerIdentity(EnvironmentAttributes.WATER_EVAPORATES); + final Map, Converter> converters = Util.make(new IdentityHashMap<>(), map -> { + map.put(AttributeTypes.ARGB_COLOR, intAsColor); + map.put(AttributeTypes.RGB_COLOR, intAsOpaqueColor); + map.put(AttributeTypes.TRI_STATE, triState); + map.put(AttributeTypes.MOON_PHASE, moonPhase); + }); - // Visual - // collector.register(EnvironmentAttributes.AMBIENT_PARTICLES, toApi, toNms); - collector.registerIntAsColor(EnvironmentAttributes.CLOUD_COLOR); - collector.registerIdentity(EnvironmentAttributes.CLOUD_FOG_END_DISTANCE); - collector.registerIdentity(EnvironmentAttributes.CLOUD_HEIGHT); - // collector.register(EnvironmentAttributes.DEFAULT_DRIPSTONE_PARTICLE, toApi, toNms); - collector.registerIntAsColor(EnvironmentAttributes.FOG_COLOR); - collector.registerIdentity(EnvironmentAttributes.FOG_END_DISTANCE); - collector.registerIdentity(EnvironmentAttributes.FOG_START_DISTANCE); - collector.registerIdentity(EnvironmentAttributes.MOON_ANGLE); - collector.register(EnvironmentAttributes.MOON_PHASE, moonPhase -> io.papermc.paper.world.MoonPhase.values()[moonPhase.ordinal()], moonPhase -> MoonPhase.values()[moonPhase.ordinal()]); - collector.registerIntAsColor(EnvironmentAttributes.SKY_COLOR); - collector.registerIdentity(EnvironmentAttributes.SKY_FOG_END_DISTANCE); - collector.registerIntAsColor(EnvironmentAttributes.SKY_LIGHT_COLOR); - collector.registerIdentity(EnvironmentAttributes.SKY_LIGHT_FACTOR); - collector.registerIdentity(EnvironmentAttributes.STAR_ANGLE); - collector.registerIdentity(EnvironmentAttributes.STAR_BRIGHTNESS); - collector.registerIdentity(EnvironmentAttributes.SUN_ANGLE); - collector.registerIntAsColor(EnvironmentAttributes.SUNRISE_SUNSET_COLOR); - collector.registerIntAsColor(EnvironmentAttributes.WATER_FOG_COLOR); - collector.registerIdentity(EnvironmentAttributes.WATER_FOG_END_DISTANCE); - collector.registerIdentity(EnvironmentAttributes.WATER_FOG_START_DISTANCE); + collector.dispatch(attribute -> { + final Converter converter = converters.get(attribute.type()); + if (converter == null) { + throw new UnsupportedOperationException("Unknown attribute type: " + BuiltInRegistries.ATTRIBUTE_TYPE.getKey(attribute.type())); + } + return converter; + }).add( + EnvironmentAttributes.EYEBLOSSOM_OPEN, + EnvironmentAttributes.MOON_PHASE, + EnvironmentAttributes.CLOUD_COLOR, + EnvironmentAttributes.FOG_COLOR, + EnvironmentAttributes.SKY_COLOR, + EnvironmentAttributes.SKY_LIGHT_COLOR, + EnvironmentAttributes.SUNRISE_SUNSET_COLOR, + EnvironmentAttributes.WATER_FOG_COLOR + // EnvironmentAttributes.VILLAGER_ACTIVITY + // EnvironmentAttributes.AMBIENT_PARTICLES + // EnvironmentAttributes.DEFAULT_DRIPSTONE_PARTICLE + // EnvironmentAttributes.AMBIENT_SOUNDS + // EnvironmentAttributes.BACKGROUND_MUSIC + // EnvironmentAttributes.BABY_VILLAGER_ACTIVITY + // EnvironmentAttributes.BED_RULE + ); + collector.dispatch(type -> Converter.identity(type.valueCodec())).add( + EnvironmentAttributes.FIREFLY_BUSH_SOUNDS, + EnvironmentAttributes.MUSIC_VOLUME, + EnvironmentAttributes.BEES_STAY_IN_HIVE, + EnvironmentAttributes.CAN_PILLAGER_PATROL_SPAWN, + EnvironmentAttributes.CAN_START_RAID, + EnvironmentAttributes.CAT_WAKING_UP_GIFT_CHANCE, + EnvironmentAttributes.CREAKING_ACTIVE, + EnvironmentAttributes.FAST_LAVA, + EnvironmentAttributes.INCREASED_FIRE_BURNOUT, + EnvironmentAttributes.MONSTERS_BURN, + EnvironmentAttributes.NETHER_PORTAL_SPAWNS_PIGLINS, + EnvironmentAttributes.PIGLINS_ZOMBIFY, + EnvironmentAttributes.RESPAWN_ANCHOR_WORKS, + EnvironmentAttributes.SKY_LIGHT_LEVEL, + EnvironmentAttributes.SNOW_GOLEM_MELTS, + EnvironmentAttributes.SURFACE_SLIME_SPAWN_CHANCE, + EnvironmentAttributes.TURTLE_EGG_HATCH_CHANCE, + EnvironmentAttributes.WATER_EVAPORATES, + EnvironmentAttributes.CLOUD_FOG_END_DISTANCE, + EnvironmentAttributes.CLOUD_HEIGHT, + EnvironmentAttributes.FOG_END_DISTANCE, + EnvironmentAttributes.FOG_START_DISTANCE, + EnvironmentAttributes.MOON_ANGLE, + EnvironmentAttributes.SKY_FOG_END_DISTANCE, + EnvironmentAttributes.SKY_LIGHT_FACTOR, + EnvironmentAttributes.STAR_ANGLE, + EnvironmentAttributes.STAR_BRIGHTNESS, + EnvironmentAttributes.SUN_ANGLE, + EnvironmentAttributes.WATER_FOG_END_DISTANCE, + EnvironmentAttributes.WATER_FOG_START_DISTANCE + ); } ); - private final PaperTypedDataAdapter adapter; + private final Converter converter; - private PaperEnvironmentalAttributeType(Holder> holder, PaperTypedDataAdapter adapter) { + private PaperEnvironmentalAttributeType(final Holder> holder, final Converter converter) { super(holder); - - this.adapter = adapter; + this.converter = converter; } @SuppressWarnings("unchecked") - public static EnvironmentalAttributeType of(final Holder holder) { - final Holder.Reference> reference = (Holder.Reference>) holder; - final PaperTypedDataAdapter adapter = PaperEnvironmentalAttributeType.ADAPTERS.get(reference.key()); + public static EnvironmentalAttributeType of(final Holder holder) { + final Holder.Reference> reference = (Holder.Reference>) holder; + final Converter adapter = PaperEnvironmentalAttributeType.ADAPTERS.get(reference.key()); return new PaperEnvironmentalAttributeType<>(reference, adapter); } @Override - public API getDefaultValue() { - return this.getAdapter().fromVanilla(this.getHandle().defaultValue()); + public A getDefaultValue() { + return this.getConverter().fromVanilla(this.getHandle().defaultValue()); } - public PaperTypedDataAdapter getAdapter() { - return this.adapter; + public Converter getConverter() { + return this.converter; } } diff --git a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeTypeCollector.java b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeTypeCollector.java deleted file mode 100644 index 058179d39490..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeTypeCollector.java +++ /dev/null @@ -1,43 +0,0 @@ -package io.papermc.paper.world.attribute; - -import io.papermc.paper.registry.typed.AbstractTypedDataCollector; -import io.papermc.paper.registry.typed.PaperTypedDataAdapter; -import java.util.Map; -import java.util.function.Function; -import net.minecraft.core.Registry; -import net.minecraft.resources.ResourceKey; -import net.minecraft.util.ARGB; -import net.minecraft.world.attribute.AttributeTypes; -import net.minecraft.world.attribute.EnvironmentAttribute; -import org.bukkit.Color; - -class PaperEnvironmentalAttributeTypeCollector extends AbstractTypedDataCollector> { - - public PaperEnvironmentalAttributeTypeCollector(final Registry> registry, final Map>, PaperTypedDataAdapter> adapters) { - super(registry, adapters); - } - - public void registerIdentity(final EnvironmentAttribute attribute) { - super.registerIdentity(attribute, EnvironmentAttribute::valueCodec); - } - - public void registerIntAsColor(final EnvironmentAttribute attribute) { - if (attribute.type() == AttributeTypes.ARGB_COLOR) { - this.register(attribute, Color::fromARGB, Color::asARGB); - } else if (attribute.type() == AttributeTypes.RGB_COLOR) { - this.register(attribute, color -> Color.fromRGB(color & 0x00FFFFFF), color -> ARGB.opaque(color.asRGB())); - } else { - throw new IllegalArgumentException("Environment attribute value cannot be converted as a color: " + attribute.type()); - } - } - - @Override - public void registerUntyped(final EnvironmentAttribute attribute) { - throw new IllegalStateException("Non-typed adapter is not supported for environmental attribute types! got: " + attribute); // TODO should be restricted by API design not at runtime - } - - // Not using @Override because of generic types - public void register(final EnvironmentAttribute attribute, final Function vanillaToApi, final Function apiToVanilla) { - super.register(attribute, vanillaToApi, apiToVanilla); - } -} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java index 77d7ef972f6c..f6d0fa1d2485 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java @@ -1,8 +1,8 @@ package org.bukkit.craftbukkit.inventory; import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableMap; import io.papermc.paper.adventure.PaperAdventure; +import io.papermc.paper.registry.typed.converter.CodecConverter; import java.util.Collections; import java.util.Map; import java.util.Optional; @@ -36,6 +36,7 @@ import org.bukkit.material.MaterialData; import org.bukkit.persistence.PersistentDataContainer; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; @DelegateDeserialization(ItemStack.class) public final class CraftItemStack extends ItemStack { @@ -581,10 +582,14 @@ public void setData(final io.papermc.paper.datacomponent.DataComponentType.NonVa this.setDataInternal((io.papermc.paper.datacomponent.PaperDataComponentType.NonValuedImpl) type, null); } - private void setDataInternal(final io.papermc.paper.datacomponent.PaperDataComponentType type, final A value) { - this.handle.set(type.getHandle(), type.getAdapter().toVanilla(value).getOrThrow(message -> { - return new IllegalArgumentException("Failed to encode data component %s (%s)".formatted(type.getKey().asString(), message)); - })); + private void setDataInternal(final io.papermc.paper.datacomponent.PaperDataComponentType type, final @Nullable A value) { + final V v = type.getConverter().toVanilla(value); + if (type.getConverter() instanceof CodecConverter codecConverter) { + codecConverter.validate(v, true).ifPresent(message -> { + throw new IllegalArgumentException("Failed to encode data component %s (%s)".formatted(type.getKey().asString(), message)); + }); + } + this.handle.set(type.getHandle(), v); } @Override From 8d0e70b4be3be99a596eb0068fcb411d81574562 Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Sat, 7 Mar 2026 16:46:34 +0100 Subject: [PATCH 11/15] port changes needed for memory key --- .../datacomponent/PaperDataComponentType.java | 6 +-- .../typed/PaperTypedDataCollector.java | 3 +- .../registry/typed/TypedDataCollector.java | 17 +++++---- .../typed/converter/CollectionConverter.java | 19 ---------- .../registry/typed/converter/Converter.java | 38 ++++++++++++++++++- .../converter/ConverterClassDispatcher.java | 5 ++- .../registry/typed/converter/Converters.java | 9 +++++ 7 files changed, 64 insertions(+), 33 deletions(-) delete mode 100644 paper-server/src/main/java/io/papermc/paper/registry/typed/converter/CollectionConverter.java diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java index c6728a81ebc0..ea30ac8c67e6 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java @@ -262,11 +262,11 @@ public static DataComponentType of(final Holder holder) { final Holder.Reference> reference = (Holder.Reference>) holder; final Converter converter = PaperDataComponentType.ADAPTERS.get(reference.key()); if (converter == Converters.unimplemented()) { - return new Unimplemented<>((Holder>) holder, converter); + return new Unimplemented<>(reference, converter); } else if (converter == Converters.unvalued()) { - return new NonValuedImpl<>((Holder>) holder, converter); + return new NonValuedImpl<>(reference, converter); } else { - return new ValuedImpl<>((Holder>) holder, converter); + return new ValuedImpl<>(reference, converter); } } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataCollector.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataCollector.java index f475b80cc0c7..54709f4f2dd4 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataCollector.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataCollector.java @@ -3,6 +3,7 @@ import io.papermc.paper.registry.typed.converter.Converter; import io.papermc.paper.registry.typed.converter.ConverterClassDispatcher; import io.papermc.paper.registry.typed.converter.ConverterDispatcher; +import java.lang.reflect.Type; import java.util.Map; import java.util.function.Function; import net.minecraft.core.Holder; @@ -39,7 +40,7 @@ default void register(final Holder.Reference type, final Converter dispatch(Function> converter); - ConverterClassDispatcher dispatchClass(Function, Converter> converter); + ConverterClassDispatcher dispatchClass(Function> converter); interface Factory> { diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/TypedDataCollector.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/TypedDataCollector.java index 1110ab123216..20c671517e90 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/TypedDataCollector.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/TypedDataCollector.java @@ -6,6 +6,7 @@ import io.papermc.paper.registry.typed.converter.Converters; import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.lang.reflect.Type; import java.util.Map; import java.util.function.Function; import net.minecraft.core.Registry; @@ -69,23 +70,25 @@ public void add(final T type, final T... types) { } @Override - public ConverterClassDispatcher dispatchClass(final Function, Converter> converter) { - return (from, toType, toValueClass) -> { + public ConverterClassDispatcher dispatchClass(final Function> converter) { + return (from, toType, toValueType) -> { for (final Field field : from.getDeclaredFields()) { final int mod = field.getModifiers(); if (!Modifier.isStatic(mod) || !Modifier.isPublic(mod)) { continue; } - final Class valueClass = toValueClass.apply(field); - if (valueClass == null) { - continue; - } + final T value; try { - TypedDataCollector.this.register(TypedDataCollector.this.getKey(toType.apply(field)), converter.apply(valueClass)); + value = toType.apply(field); } catch (final ReflectiveOperationException e) { throw new RuntimeException(e); } + final Type valueType = toValueType.apply(value, field); + if (valueType == null) { + continue; + } + TypedDataCollector.this.register(TypedDataCollector.this.getKey(value), converter.apply(valueType)); } }; } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/CollectionConverter.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/CollectionConverter.java deleted file mode 100644 index 924b92698e24..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/CollectionConverter.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.papermc.paper.registry.typed.converter; - -import io.papermc.paper.util.MCUtil; -import java.util.Collection; - -public record CollectionConverter( - Converter converter -) implements Converter, Collection> { - - @Override - public Collection toVanilla(final Collection value) { - return MCUtil.transformUnmodifiable(value, this.converter::toVanilla); - } - - @Override - public Collection fromVanilla(final Collection value) { - return MCUtil.transformUnmodifiable(value, this.converter::fromVanilla); - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converter.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converter.java index e6d178887c6b..6a0a7a2f682f 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converter.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converter.java @@ -1,7 +1,13 @@ package io.papermc.paper.registry.typed.converter; import com.mojang.serialization.Encoder; +import java.util.Collection; +import java.util.List; +import java.util.Set; import java.util.function.Function; +import java.util.stream.Collectors; + +import static io.papermc.paper.util.MCUtil.transformUnmodifiable; public interface Converter { @@ -32,10 +38,40 @@ static Converter identity(final Encoder serializer) { return new CodecConverter<>(identity(), serializer); } - default CodecConverter serializable(final Encoder serializer) { + default Converter serializable(final Encoder serializer) { return new CodecConverter<>(this, serializer); } + default Converter, Collection> collection() { + if (this instanceof CodecConverter codecConverter) { + return codecConverter.converter().collection(); + } + return Converter.direct( + collection -> transformUnmodifiable(collection, this::fromVanilla), + collection -> transformUnmodifiable(collection, this::toVanilla) + ); + } + + default Converter, List> list() { + if (this instanceof CodecConverter codecConverter) { + return codecConverter.converter().list(); + } + return Converter.direct( + collection -> transformUnmodifiable(collection, this::fromVanilla), + collection -> transformUnmodifiable(collection, this::toVanilla) + ); + } + + default Converter, Set> set() { + if (this instanceof CodecConverter codecConverter) { + return codecConverter.converter().set(); + } + return Converter.direct( + set -> set.stream().map(this::fromVanilla).collect(Collectors.toUnmodifiableSet()), + set -> set.stream().map(this::toVanilla).collect(Collectors.toUnmodifiableSet()) + ); + } + M toVanilla(A value); A fromVanilla(M value); diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterClassDispatcher.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterClassDispatcher.java index 952efab48c26..d7037c6781c5 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterClassDispatcher.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterClassDispatcher.java @@ -1,12 +1,13 @@ package io.papermc.paper.registry.typed.converter; import java.lang.reflect.Field; -import java.util.function.Function; +import java.lang.reflect.Type; +import java.util.function.BiFunction; import org.jspecify.annotations.Nullable; public interface ConverterClassDispatcher { - void scanConstants(Class from, ReflectiveFunction toType, Function> toValueClass); + void scanConstants(Class from, ReflectiveFunction toType, BiFunction toValueType); interface ReflectiveFunction { T apply(Field field) throws ReflectiveOperationException; diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converters.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converters.java index cf488811b650..6feca793360a 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converters.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converters.java @@ -9,8 +9,10 @@ import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; import net.minecraft.util.Unit; +import net.minecraft.world.entity.Entity; import org.bukkit.Keyed; import org.bukkit.craftbukkit.CraftRegistry; +import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.util.Handleable; import static io.papermc.paper.util.MCUtil.transformUnmodifiable; @@ -66,6 +68,13 @@ public static > Converter wrapper(final Functio return Converter.direct(vanillaToApi, Handleable::getHandle); } + public static Converter entity(final Class vanillaEntity, final Class apiEntity) { + return Converter.direct( + entity -> apiEntity.cast(entity.getBukkitEntity()), + entity -> vanillaEntity.cast(entity.getHandle()) + ); + } + private static final Converter UNIMPLEMENTED = Converter.direct($ -> { throw new UnsupportedOperationException("Cannot convert an unimplemented type to an API value"); }, $ -> { From 38bf80dc09544510ab9b2f67b5eaa01876e37c68 Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Sat, 7 Mar 2026 17:26:12 +0100 Subject: [PATCH 12/15] revert bad rename --- paper-api/src/main/java/io/papermc/paper/world/MoonPhase.java | 1 - .../src/main/java/io/papermc/paper/util/PaperCodecs.java | 2 +- .../main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/paper-api/src/main/java/io/papermc/paper/world/MoonPhase.java b/paper-api/src/main/java/io/papermc/paper/world/MoonPhase.java index fd245c6a55f9..0b24e1a92bba 100644 --- a/paper-api/src/main/java/io/papermc/paper/world/MoonPhase.java +++ b/paper-api/src/main/java/io/papermc/paper/world/MoonPhase.java @@ -6,7 +6,6 @@ @NullMarked public enum MoonPhase { - // todo generate FULL_MOON(0L), WANING_GIBBOUS(1L), LAST_QUARTER(2L), diff --git a/paper-server/src/main/java/io/papermc/paper/util/PaperCodecs.java b/paper-server/src/main/java/io/papermc/paper/util/PaperCodecs.java index bb33d9b4eb56..5eb2d60042c0 100644 --- a/paper-server/src/main/java/io/papermc/paper/util/PaperCodecs.java +++ b/paper-server/src/main/java/io/papermc/paper/util/PaperCodecs.java @@ -34,7 +34,7 @@ public final class PaperCodecs { }, TriState::name); /** - * This serializer is lenient on decoding and encoding compared to native OptionalFieldCodec + * This codec is lenient on decoding and encoding compared to native OptionalFieldCodec * which only has options to be lenient on decoding. */ public static MapCodec> lenientCodec(final String name, final Codec codec) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java index 831eea27490b..52393f9772f2 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java @@ -507,7 +507,6 @@ public java.util.Set getFeatureFlags() { @Override public PaperEnvironmentalAttribute getEnvironmentalAttribute(final EnvironmentalAttributeType type) { - // todo should probably restrict the position lookup for LimitedRegion return new PaperEnvironmentalAttribute<>(this.getHandle().getLevel().environmentAttributes(), (PaperEnvironmentalAttributeType) type); } } From d96cc5f2dfffe1da00568ff3642859291830c385 Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Sun, 8 Mar 2026 20:03:11 +0100 Subject: [PATCH 13/15] fix map_post_processing component and generate MapPostProcessing --- .../io/papermc/paper/item/MapPostProcessing.java | 4 +++- .../main/java/io/papermc/generator/Rewriters.java | 2 ++ .../paper/datacomponent/PaperDataComponentType.java | 4 ++-- .../paper/registry/typed/converter/Converter.java | 13 +++++++++---- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/paper-api/src/main/java/io/papermc/paper/item/MapPostProcessing.java b/paper-api/src/main/java/io/papermc/paper/item/MapPostProcessing.java index 5843768d0be2..7071cacd66ef 100644 --- a/paper-api/src/main/java/io/papermc/paper/item/MapPostProcessing.java +++ b/paper-api/src/main/java/io/papermc/paper/item/MapPostProcessing.java @@ -1,6 +1,8 @@ package io.papermc.paper.item; public enum MapPostProcessing { + // Start generate - MapPostProcessing LOCK, - SCALE + SCALE; + // End generate - MapPostProcessing } diff --git a/paper-generator/src/main/java/io/papermc/generator/Rewriters.java b/paper-generator/src/main/java/io/papermc/generator/Rewriters.java index 6a337d533bff..a59da4df70bf 100644 --- a/paper-generator/src/main/java/io/papermc/generator/Rewriters.java +++ b/paper-generator/src/main/java/io/papermc/generator/Rewriters.java @@ -26,6 +26,7 @@ import io.papermc.paper.datacomponent.item.SwingAnimation; import io.papermc.paper.datacomponent.item.consumable.ItemUseAnimation; import io.papermc.paper.dialog.Dialog; +import io.papermc.paper.item.MapPostProcessing; import io.papermc.paper.world.WeatheringCopperState; import io.papermc.typewriter.preset.EnumCloneRewriter; import io.papermc.typewriter.preset.model.EnumValue; @@ -158,6 +159,7 @@ protected EnumValue.Builder rewriteEnumValue(ParticleStatus status) { )) .register("ItemUseAnimation", ItemUseAnimation.class, new EnumCloneRewriter<>(net.minecraft.world.item.ItemUseAnimation.class)) .register("SwingAnimationType", SwingAnimation.Animation.class, new EnumCloneRewriter<>(SwingAnimationType.class)) + .register("MapPostProcessing", MapPostProcessing.class, new EnumCloneRewriter<>(net.minecraft.world.item.component.MapPostProcessing.class)) .register("ItemRarity", ItemRarity.class, new EnumCloneRewriter<>(Rarity.class) { @Override protected EnumValue.Builder rewriteEnumValue(Rarity rarity) { diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java index ea30ac8c67e6..0e3125a60eaf 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java @@ -45,6 +45,7 @@ import io.papermc.paper.datacomponent.item.PaperWeapon; import io.papermc.paper.datacomponent.item.PaperWritableBookContent; import io.papermc.paper.datacomponent.item.PaperWrittenBookContent; +import io.papermc.paper.item.MapPostProcessing; import io.papermc.paper.registry.HolderableBase; import io.papermc.paper.registry.PaperRegistries; import io.papermc.paper.registry.typed.PaperTypedDataAdapters; @@ -63,7 +64,6 @@ import net.minecraft.world.item.EitherHolder; import net.minecraft.world.item.Rarity; import net.minecraft.world.item.component.InstrumentComponent; -import net.minecraft.world.item.component.MapPostProcessing; import net.minecraft.world.item.component.ProvidesTrimMaterial; import org.bukkit.DyeColor; import org.bukkit.craftbukkit.CraftMusicInstrument; @@ -149,7 +149,7 @@ private static void register(final TypedDataCollector) Holder.NO_OP; } - static Converter identity(final Encoder serializer) { - return new CodecConverter<>(identity(), serializer); + static Converter identity(final @Nullable Encoder serializer) { + final Converter i = identity(); + if (serializer == null) { + return i; + } + return i.serializable(serializer); } default Converter serializable(final Encoder serializer) { @@ -57,8 +62,8 @@ default Converter, List> list() { return codecConverter.converter().list(); } return Converter.direct( - collection -> transformUnmodifiable(collection, this::fromVanilla), - collection -> transformUnmodifiable(collection, this::toVanilla) + list -> transformUnmodifiable(list, this::fromVanilla), + list -> transformUnmodifiable(list, this::toVanilla) ); } From 8dabadbbb94a15053c2ec59c17a31202dd6b7ba9 Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Mon, 9 Mar 2026 16:51:08 +0100 Subject: [PATCH 14/15] move converter package, simplify --- .../datacomponent/PaperDataComponentType.java | 34 ++--- .../typed/PaperTypedDataAdapters.java | 8 +- .../typed/PaperTypedDataCollector.java | 111 ++++++++++++---- .../registry/typed/TypedDataCollector.java | 124 ++++-------------- .../converter/ConverterClassDispatcher.java | 15 --- .../typed/converter/ConverterDispatcher.java | 8 -- .../converter/CodecConverter.java | 2 +- .../typed => util}/converter/Converter.java | 4 +- .../typed => util}/converter/Converters.java | 2 +- .../converter/package-info.java | 2 +- .../PaperEnvironmentalAttribute.java | 2 +- .../PaperEnvironmentalAttributeType.java | 29 ++-- .../craftbukkit/inventory/CraftItemStack.java | 2 +- 13 files changed, 154 insertions(+), 189 deletions(-) delete mode 100644 paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterClassDispatcher.java delete mode 100644 paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterDispatcher.java rename paper-server/src/main/java/io/papermc/paper/{registry/typed => util}/converter/CodecConverter.java (95%) rename paper-server/src/main/java/io/papermc/paper/{registry/typed => util}/converter/Converter.java (98%) rename paper-server/src/main/java/io/papermc/paper/{registry/typed => util}/converter/Converters.java (98%) rename paper-server/src/main/java/io/papermc/paper/{registry/typed => util}/converter/package-info.java (52%) diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java index 0e3125a60eaf..b240e49d6b6e 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/PaperDataComponentType.java @@ -49,9 +49,9 @@ import io.papermc.paper.registry.HolderableBase; import io.papermc.paper.registry.PaperRegistries; import io.papermc.paper.registry.typed.PaperTypedDataAdapters; -import io.papermc.paper.registry.typed.TypedDataCollector; -import io.papermc.paper.registry.typed.converter.Converter; -import io.papermc.paper.registry.typed.converter.Converters; +import io.papermc.paper.registry.typed.PaperTypedDataCollector; +import io.papermc.paper.util.converter.Converter; +import io.papermc.paper.util.converter.Converters; import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -84,30 +84,36 @@ import org.bukkit.inventory.ItemRarity; import org.jspecify.annotations.Nullable; -import static io.papermc.paper.registry.typed.converter.Converter.direct; -import static io.papermc.paper.registry.typed.converter.Converters.list; -import static io.papermc.paper.registry.typed.converter.Converters.registryElement; -import static io.papermc.paper.registry.typed.converter.Converters.sameName; -import static io.papermc.paper.registry.typed.converter.Converters.sameOrder; -import static io.papermc.paper.registry.typed.converter.Converters.wrapper; +import static io.papermc.paper.util.converter.Converter.direct; +import static io.papermc.paper.util.converter.Converters.list; +import static io.papermc.paper.util.converter.Converters.registryElement; +import static io.papermc.paper.util.converter.Converters.sameName; +import static io.papermc.paper.util.converter.Converters.sameOrder; +import static io.papermc.paper.util.converter.Converters.wrapper; public abstract class PaperDataComponentType extends HolderableBase> implements DataComponentType { // this is a hack around generics limitations to prevent // having to define generics on each register call as seen below, making collectors easier to read: // collector.register(...) - private static void register(final TypedDataCollector> collector, final net.minecraft.core.component.DataComponentType dataComponentType, final Function vanillaToApi, final Function apiToVanilla) { + private static void register(final PaperTypedDataCollector> collector, final net.minecraft.core.component.DataComponentType dataComponentType, final Function vanillaToApi, final Function apiToVanilla) { collector.register(dataComponentType, vanillaToApi, apiToVanilla); } @SuppressWarnings("RedundantTypeArguments") - private static final PaperTypedDataAdapters> ADAPTERS = PaperTypedDataAdapters., TypedDataCollector.Unvaluable>>create( + private static final PaperTypedDataAdapters> ADAPTERS = PaperTypedDataAdapters., PaperTypedDataCollector>>create( BuiltInRegistries.DATA_COMPONENT_TYPE, - TypedDataCollector.Unvaluable::new, + PaperTypedDataCollector::new, collector -> { final Converter dyeColor = direct( nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData()) ); + collector.dispatch($ -> Converters.unvalued()).add( + DataComponents.UNBREAKABLE, + DataComponents.INTANGIBLE_PROJECTILE, + DataComponents.GLIDER + // DataComponents.CREATIVE_SLOT_LOCK + ); collector.dispatch(type -> Converter.identity(type.codec())).add( DataComponents.MAX_STACK_SIZE, DataComponents.MAX_DAMAGE, @@ -117,7 +123,6 @@ private static void register(final TypedDataCollector CraftDamageType.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftDamageType.bukkitToMinecraftHolder(api))); @@ -130,8 +135,6 @@ private static void register(final TypedDataCollector void register(final TypedDataCollector, Converter> conver this.converters = converters; } - public static > PaperTypedDataAdapters create( + public static > PaperTypedDataAdapters create( final Registry registry, - final PaperTypedDataCollector.Factory collectorFactory, + final TypedDataCollector.Factory collectorFactory, final Consumer consumer ) { final Map, Converter> converters = new IdentityHashMap<>(); diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataCollector.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataCollector.java index 54709f4f2dd4..67f5866dc094 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataCollector.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataCollector.java @@ -1,50 +1,109 @@ package io.papermc.paper.registry.typed; -import io.papermc.paper.registry.typed.converter.Converter; -import io.papermc.paper.registry.typed.converter.ConverterClassDispatcher; -import io.papermc.paper.registry.typed.converter.ConverterDispatcher; +import io.papermc.paper.util.converter.Converter; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.Map; import java.util.function.Function; -import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; -public interface PaperTypedDataCollector { +public class PaperTypedDataCollector implements TypedDataCollector { - interface Unvalued { - void registerUnvalued(T type); + private final Registry registry; + private final Map, Converter> converters; - default void registerUnvalued(final Holder.Reference type) { - this.registerUnvalued(type.key()); - } - - void registerUnvalued(ResourceKey type); + public PaperTypedDataCollector( + final Registry registry, + final Map, Converter> converters + ) { + this.registry = registry; + this.converters = converters; } - void register(T type, Function vanillaToApi, Function apiToVanilla); - - default void register(final Holder.Reference type, final Function vanillaToApi, final Function apiToVanilla) { - this.register(type.key(), vanillaToApi, apiToVanilla); + protected ResourceKey getKey(final T type) { + return this.registry.getResourceKey(type).orElseThrow(); } - void register(ResourceKey type, Function vanillaToApi, Function apiToVanilla); - - void register(T type, Converter converter); + @Override + public void register(final T type, final Function vanillaToApi, final Function apiToVanilla) { + this.register(this.getKey(type), vanillaToApi, apiToVanilla); + } - default void register(final Holder.Reference type, final Converter converter) { - this.register(type.key(), converter); + @Override + public void register(final ResourceKey type, final Function vanillaToApi, final Function apiToVanilla) { + this.registerInternal(type, vanillaToApi, apiToVanilla); } - void register(ResourceKey type, Converter converter); + @Override + public void register(final T type, final Converter converter) { + this.register(this.getKey(type), converter); + } - ConverterDispatcher dispatch(Function> converter); + @Override + public void register(final ResourceKey type, final Converter converter) { + this.registerInternal(type, converter); + } - ConverterClassDispatcher dispatchClass(Function> converter); + @Override + public Dispatcher dispatch(final Function> converter) { + return new Dispatcher<>() { + @Override + public void add(final Iterable types) { + types.forEach(type -> { + PaperTypedDataCollector.this.register(PaperTypedDataCollector.this.getKey(type), converter.apply(type)); + }); + } + + @Override + public void add(final T type, final T... types) { + PaperTypedDataCollector.this.register(PaperTypedDataCollector.this.getKey(type), converter.apply(type)); + for (final T t : types) { + PaperTypedDataCollector.this.register(PaperTypedDataCollector.this.getKey(t), converter.apply(t)); + } + } + }; + } - interface Factory> { + @Override + public ClassDispatcher dispatchClass(final Function> converter) { + return (from, toType, toValueType) -> { + for (final Field field : from.getDeclaredFields()) { + final int mod = field.getModifiers(); + if (!Modifier.isStatic(mod) || !Modifier.isPublic(mod)) { + continue; + } + + final T value; + try { + value = toType.apply(field); + } catch (final ReflectiveOperationException e) { + throw new RuntimeException(e); + } + final Type valueType = toValueType.apply(value, field); + if (valueType == null) { + continue; + } + PaperTypedDataCollector.this.register(PaperTypedDataCollector.this.getKey(value), converter.apply(valueType)); + } + }; + } - C create(Registry registry, Map, Converter> adapters); + protected void registerInternal( + final ResourceKey key, + final Function vanillaToApi, + final Function apiToVanilla + ) { + this.registerInternal(key, Converter.direct(vanillaToApi, apiToVanilla)); + } + protected void registerInternal( + final ResourceKey key, + final Converter converter + ) { + if (this.converters.put(key, converter) != null) { + throw new IllegalStateException("Duplicate converter registration for " + key); + } } } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/TypedDataCollector.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/TypedDataCollector.java index 20c671517e90..561f5fb43904 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/TypedDataCollector.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/TypedDataCollector.java @@ -1,128 +1,56 @@ package io.papermc.paper.registry.typed; -import io.papermc.paper.registry.typed.converter.Converter; -import io.papermc.paper.registry.typed.converter.ConverterClassDispatcher; -import io.papermc.paper.registry.typed.converter.ConverterDispatcher; -import io.papermc.paper.registry.typed.converter.Converters; +import io.papermc.paper.util.converter.Converter; import java.lang.reflect.Field; -import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.Map; +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.jspecify.annotations.Nullable; -public class TypedDataCollector implements PaperTypedDataCollector { +public interface TypedDataCollector { - private final Registry registry; - private final Map, Converter> converters; + void register(T type, Function vanillaToApi, Function apiToVanilla); - public TypedDataCollector( - final Registry registry, - final Map, Converter> converters - ) { - this.registry = registry; - this.converters = converters; + default void register(final Holder.Reference type, final Function vanillaToApi, final Function apiToVanilla) { + this.register(type.key(), vanillaToApi, apiToVanilla); } - protected ResourceKey getKey(final T type) { - return this.registry.getResourceKey(type).orElseThrow(); - } + void register(ResourceKey type, Function vanillaToApi, Function apiToVanilla); - @Override - public void register(final T type, final Function vanillaToApi, final Function apiToVanilla) { - this.register(this.getKey(type), vanillaToApi, apiToVanilla); - } + void register(T type, Converter converter); - @Override - public void register(final ResourceKey type, final Function vanillaToApi, final Function apiToVanilla) { - this.registerInternal(type, vanillaToApi, apiToVanilla); + default void register(final Holder.Reference type, final Converter converter) { + this.register(type.key(), converter); } - @Override - public void register(final T type, final Converter converter) { - this.register(this.getKey(type), converter); - } + void register(ResourceKey type, Converter converter); - @Override - public void register(final ResourceKey type, final Converter converter) { - this.registerInternal(type, converter); - } + Dispatcher dispatch(Function> converter); - @Override - public ConverterDispatcher dispatch(final Function> converter) { - return new ConverterDispatcher<>() { - @Override - public void add(final Iterable types) { - types.forEach(type -> { - TypedDataCollector.this.register(TypedDataCollector.this.getKey(type), converter.apply(type)); - }); - } - - @Override - public void add(final T type, final T... types) { - TypedDataCollector.this.register(TypedDataCollector.this.getKey(type), converter.apply(type)); - for (final T t : types) { - TypedDataCollector.this.register(TypedDataCollector.this.getKey(t), converter.apply(t)); - } - } - }; - } + ClassDispatcher dispatchClass(Function> converter); - @Override - public ConverterClassDispatcher dispatchClass(final Function> converter) { - return (from, toType, toValueType) -> { - for (final Field field : from.getDeclaredFields()) { - final int mod = field.getModifiers(); - if (!Modifier.isStatic(mod) || !Modifier.isPublic(mod)) { - continue; - } - - final T value; - try { - value = toType.apply(field); - } catch (final ReflectiveOperationException e) { - throw new RuntimeException(e); - } - final Type valueType = toValueType.apply(value, field); - if (valueType == null) { - continue; - } - TypedDataCollector.this.register(TypedDataCollector.this.getKey(value), converter.apply(valueType)); - } - }; - } + interface Factory> { - protected void registerInternal( - final ResourceKey key, - final Function vanillaToApi, - final Function apiToVanilla - ) { - this.registerInternal(key, Converter.direct(vanillaToApi, apiToVanilla)); + C create(Registry registry, Map, Converter> adapters); } - protected void registerInternal( - final ResourceKey key, - final Converter converter - ) { - if (this.converters.put(key, converter) != null) { - throw new IllegalStateException("Duplicate adapter registration for " + key); - } + interface Dispatcher { + + void add(Iterable types); + + void add(T type, T... types); } - public static class Unvaluable extends TypedDataCollector implements PaperTypedDataCollector, Unvalued { - public Unvaluable(final Registry registry, final Map, Converter> converters) { - super(registry, converters); - } + interface ClassDispatcher { - @Override - public void registerUnvalued(final T type) { - this.registerUnvalued(this.getKey(type)); - } + void scanConstants(Class from, ReflectiveFunction toType, BiFunction toValueType); - @Override - public void registerUnvalued(final ResourceKey type) { - this.registerInternal(type, Converters.unvalued()); + interface ReflectiveFunction { + T apply(Field field) throws ReflectiveOperationException; } } } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterClassDispatcher.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterClassDispatcher.java deleted file mode 100644 index d7037c6781c5..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterClassDispatcher.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.papermc.paper.registry.typed.converter; - -import java.lang.reflect.Field; -import java.lang.reflect.Type; -import java.util.function.BiFunction; -import org.jspecify.annotations.Nullable; - -public interface ConverterClassDispatcher { - - void scanConstants(Class from, ReflectiveFunction toType, BiFunction toValueType); - - interface ReflectiveFunction { - T apply(Field field) throws ReflectiveOperationException; - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterDispatcher.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterDispatcher.java deleted file mode 100644 index 779ff523b3fb..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/ConverterDispatcher.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.papermc.paper.registry.typed.converter; - -public interface ConverterDispatcher { - - void add(Iterable types); - - void add(T type, T... types); -} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/CodecConverter.java b/paper-server/src/main/java/io/papermc/paper/util/converter/CodecConverter.java similarity index 95% rename from paper-server/src/main/java/io/papermc/paper/registry/typed/converter/CodecConverter.java rename to paper-server/src/main/java/io/papermc/paper/util/converter/CodecConverter.java index ece5b43ac5ba..f6fc4f539017 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/CodecConverter.java +++ b/paper-server/src/main/java/io/papermc/paper/util/converter/CodecConverter.java @@ -1,4 +1,4 @@ -package io.papermc.paper.registry.typed.converter; +package io.papermc.paper.util.converter; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converter.java b/paper-server/src/main/java/io/papermc/paper/util/converter/Converter.java similarity index 98% rename from paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converter.java rename to paper-server/src/main/java/io/papermc/paper/util/converter/Converter.java index 63e0bb9eabfd..15d1b2a2f068 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converter.java +++ b/paper-server/src/main/java/io/papermc/paper/util/converter/Converter.java @@ -1,12 +1,12 @@ -package io.papermc.paper.registry.typed.converter; +package io.papermc.paper.util.converter; import com.mojang.serialization.Encoder; -import org.jspecify.annotations.Nullable; import java.util.Collection; import java.util.List; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; import static io.papermc.paper.util.MCUtil.transformUnmodifiable; diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converters.java b/paper-server/src/main/java/io/papermc/paper/util/converter/Converters.java similarity index 98% rename from paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converters.java rename to paper-server/src/main/java/io/papermc/paper/util/converter/Converters.java index 6feca793360a..d915673026dd 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/Converters.java +++ b/paper-server/src/main/java/io/papermc/paper/util/converter/Converters.java @@ -1,4 +1,4 @@ -package io.papermc.paper.registry.typed.converter; +package io.papermc.paper.util.converter; import java.util.Collection; import java.util.List; diff --git a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/package-info.java b/paper-server/src/main/java/io/papermc/paper/util/converter/package-info.java similarity index 52% rename from paper-server/src/main/java/io/papermc/paper/registry/typed/converter/package-info.java rename to paper-server/src/main/java/io/papermc/paper/util/converter/package-info.java index fb7eef83f80f..107361ad57aa 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/typed/converter/package-info.java +++ b/paper-server/src/main/java/io/papermc/paper/util/converter/package-info.java @@ -1,4 +1,4 @@ @NullMarked -package io.papermc.paper.registry.typed.converter; +package io.papermc.paper.util.converter; import org.jspecify.annotations.NullMarked; diff --git a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java index 1d22a51d6a59..442136e9a38c 100644 --- a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java @@ -1,8 +1,8 @@ package io.papermc.paper.world.attribute; import io.papermc.paper.math.Position; -import io.papermc.paper.registry.typed.converter.Converter; import io.papermc.paper.util.MCUtil; +import io.papermc.paper.util.converter.Converter; import net.minecraft.core.BlockPos; import net.minecraft.world.attribute.EnvironmentAttributeSystem; diff --git a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java index ef56dd4df918..34a76774be55 100644 --- a/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java @@ -3,8 +3,9 @@ import io.papermc.paper.adventure.PaperAdventure; import io.papermc.paper.registry.HolderableBase; import io.papermc.paper.registry.typed.PaperTypedDataAdapters; -import io.papermc.paper.registry.typed.TypedDataCollector; -import io.papermc.paper.registry.typed.converter.Converter; +import io.papermc.paper.registry.typed.PaperTypedDataCollector; +import io.papermc.paper.util.converter.Converter; +import io.papermc.paper.util.converter.Converters; import java.util.IdentityHashMap; import java.util.Map; import net.minecraft.core.Holder; @@ -19,27 +20,22 @@ import net.minecraft.world.level.MoonPhase; import org.bukkit.Color; -import static io.papermc.paper.registry.typed.converter.Converter.direct; +import static io.papermc.paper.util.converter.Converter.direct; +import static io.papermc.paper.util.converter.Converters.sameOrder; public final class PaperEnvironmentalAttributeType extends HolderableBase> implements EnvironmentalAttributeType { @SuppressWarnings("RedundantTypeArguments") - private static final PaperTypedDataAdapters> ADAPTERS = PaperTypedDataAdapters., TypedDataCollector>>create( + private static final PaperTypedDataAdapters> ADAPTERS = PaperTypedDataAdapters., PaperTypedDataCollector>>create( BuiltInRegistries.ENVIRONMENT_ATTRIBUTE, - TypedDataCollector::new, + PaperTypedDataCollector::new, collector -> { - final Converter intAsColor = direct( - Color::fromARGB, - Color::asARGB - ); + final Converter intAsColor = direct(Color::fromARGB, Color::asARGB); final Converter intAsOpaqueColor = direct( color -> Color.fromRGB(color & 0x00FFFFFF), color -> ARGB.opaque(color.asRGB()) ); final Converter triState = direct(PaperAdventure::asAdventure, PaperAdventure::asVanilla); - final Converter moonPhase = direct( - phase -> io.papermc.paper.world.MoonPhase.values()[phase.ordinal()], - phase -> MoonPhase.values()[phase.ordinal()] - ); + final Converter moonPhase = sameOrder(io.papermc.paper.world.MoonPhase.class, MoonPhase.class); final Map, Converter> converters = Util.make(new IdentityHashMap<>(), map -> { map.put(AttributeTypes.ARGB_COLOR, intAsColor); @@ -116,8 +112,11 @@ private PaperEnvironmentalAttributeType(final Holder> ho @SuppressWarnings("unchecked") public static EnvironmentalAttributeType of(final Holder holder) { final Holder.Reference> reference = (Holder.Reference>) holder; - final Converter adapter = PaperEnvironmentalAttributeType.ADAPTERS.get(reference.key()); - return new PaperEnvironmentalAttributeType<>(reference, adapter); + final Converter converter = PaperEnvironmentalAttributeType.ADAPTERS.get(reference.key()); + if (converter == Converters.unvalued()) { + throw new IllegalStateException("Non-valued converter is not supported for environmental attribute type: " + reference.key()); + } + return new PaperEnvironmentalAttributeType<>(reference, converter); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java index f6d0fa1d2485..e30830f44209 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java @@ -2,7 +2,7 @@ import com.google.common.base.Preconditions; import io.papermc.paper.adventure.PaperAdventure; -import io.papermc.paper.registry.typed.converter.CodecConverter; +import io.papermc.paper.util.converter.CodecConverter; import java.util.Collections; import java.util.Map; import java.util.Optional; From 2fcdd5349243de6bdcaa5925f61ee4d797b46dd6 Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Tue, 10 Mar 2026 17:54:37 +0100 Subject: [PATCH 15/15] Implement particle type registry --- .../paper/registry/keys/ParticleTypeKeys.java | 839 ++++++++++++++++++ .../papermc/paper/particle/ParticleType.java | 18 + .../io/papermc/paper/particle/Particles.java | 149 ++++ .../papermc/paper/registry/RegistryKey.java | 8 +- .../src/main/java/org/bukkit/Registry.java | 5 +- .../main/java/org/bukkit/entity/Player.java | 5 + .../generator/registry/RegistryEntries.java | 8 +- .../paper/particle/PaperParticleType.java | 285 ++++++ .../paper/registry/PaperRegistries.java | 4 +- .../paper/registry/PaperSimpleRegistry.java | 5 - .../org/bukkit/craftbukkit/CraftParticle.java | 5 +- .../craftbukkit/entity/CraftPlayer.java | 29 + .../provider/RegistriesArgumentProvider.java | 6 +- 13 files changed, 1349 insertions(+), 17 deletions(-) create mode 100644 paper-api/src/generated/java/io/papermc/paper/registry/keys/ParticleTypeKeys.java create mode 100644 paper-api/src/main/java/io/papermc/paper/particle/ParticleType.java create mode 100644 paper-api/src/main/java/io/papermc/paper/particle/Particles.java create mode 100644 paper-server/src/main/java/io/papermc/paper/particle/PaperParticleType.java diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/ParticleTypeKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/ParticleTypeKeys.java new file mode 100644 index 000000000000..9e38910e2f2a --- /dev/null +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/ParticleTypeKeys.java @@ -0,0 +1,839 @@ +package io.papermc.paper.registry.keys; + +import static net.kyori.adventure.key.Key.key; + +import io.papermc.paper.annotation.GeneratedClass; +import io.papermc.paper.particle.ParticleType; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import net.kyori.adventure.key.Key; +import org.jspecify.annotations.NullMarked; + +/** + * Vanilla keys for {@link RegistryKey#PARTICLE_TYPE}. + * + * @apiNote The fields provided here are a direct representation of + * what is available from the vanilla game source. They may be + * changed (including removals) on any Minecraft version + * bump, so cross-version compatibility is not provided on the + * same level as it is on most of the other API. + */ +@SuppressWarnings({ + "unused", + "SpellCheckingInspection" +}) +@NullMarked +@GeneratedClass +public final class ParticleTypeKeys { + /** + * {@code minecraft:angry_villager} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ANGRY_VILLAGER = create(key("angry_villager")); + + /** + * {@code minecraft:ash} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ASH = create(key("ash")); + + /** + * {@code minecraft:block} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BLOCK = create(key("block")); + + /** + * {@code minecraft:block_crumble} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BLOCK_CRUMBLE = create(key("block_crumble")); + + /** + * {@code minecraft:block_marker} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BLOCK_MARKER = create(key("block_marker")); + + /** + * {@code minecraft:bubble} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BUBBLE = create(key("bubble")); + + /** + * {@code minecraft:bubble_column_up} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BUBBLE_COLUMN_UP = create(key("bubble_column_up")); + + /** + * {@code minecraft:bubble_pop} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BUBBLE_POP = create(key("bubble_pop")); + + /** + * {@code minecraft:campfire_cosy_smoke} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey CAMPFIRE_COSY_SMOKE = create(key("campfire_cosy_smoke")); + + /** + * {@code minecraft:campfire_signal_smoke} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey CAMPFIRE_SIGNAL_SMOKE = create(key("campfire_signal_smoke")); + + /** + * {@code minecraft:cherry_leaves} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey CHERRY_LEAVES = create(key("cherry_leaves")); + + /** + * {@code minecraft:cloud} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey CLOUD = create(key("cloud")); + + /** + * {@code minecraft:composter} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey COMPOSTER = create(key("composter")); + + /** + * {@code minecraft:copper_fire_flame} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey COPPER_FIRE_FLAME = create(key("copper_fire_flame")); + + /** + * {@code minecraft:crimson_spore} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey CRIMSON_SPORE = create(key("crimson_spore")); + + /** + * {@code minecraft:crit} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey CRIT = create(key("crit")); + + /** + * {@code minecraft:current_down} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey CURRENT_DOWN = create(key("current_down")); + + /** + * {@code minecraft:damage_indicator} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DAMAGE_INDICATOR = create(key("damage_indicator")); + + /** + * {@code minecraft:dolphin} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DOLPHIN = create(key("dolphin")); + + /** + * {@code minecraft:dragon_breath} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DRAGON_BREATH = create(key("dragon_breath")); + + /** + * {@code minecraft:dripping_dripstone_lava} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DRIPPING_DRIPSTONE_LAVA = create(key("dripping_dripstone_lava")); + + /** + * {@code minecraft:dripping_dripstone_water} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DRIPPING_DRIPSTONE_WATER = create(key("dripping_dripstone_water")); + + /** + * {@code minecraft:dripping_honey} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DRIPPING_HONEY = create(key("dripping_honey")); + + /** + * {@code minecraft:dripping_lava} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DRIPPING_LAVA = create(key("dripping_lava")); + + /** + * {@code minecraft:dripping_obsidian_tear} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DRIPPING_OBSIDIAN_TEAR = create(key("dripping_obsidian_tear")); + + /** + * {@code minecraft:dripping_water} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DRIPPING_WATER = create(key("dripping_water")); + + /** + * {@code minecraft:dust} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DUST = create(key("dust")); + + /** + * {@code minecraft:dust_color_transition} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DUST_COLOR_TRANSITION = create(key("dust_color_transition")); + + /** + * {@code minecraft:dust_pillar} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DUST_PILLAR = create(key("dust_pillar")); + + /** + * {@code minecraft:dust_plume} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DUST_PLUME = create(key("dust_plume")); + + /** + * {@code minecraft:effect} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey EFFECT = create(key("effect")); + + /** + * {@code minecraft:egg_crack} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey EGG_CRACK = create(key("egg_crack")); + + /** + * {@code minecraft:elder_guardian} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ELDER_GUARDIAN = create(key("elder_guardian")); + + /** + * {@code minecraft:electric_spark} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ELECTRIC_SPARK = create(key("electric_spark")); + + /** + * {@code minecraft:enchant} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENCHANT = create(key("enchant")); + + /** + * {@code minecraft:enchanted_hit} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENCHANTED_HIT = create(key("enchanted_hit")); + + /** + * {@code minecraft:end_rod} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey END_ROD = create(key("end_rod")); + + /** + * {@code minecraft:entity_effect} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_EFFECT = create(key("entity_effect")); + + /** + * {@code minecraft:explosion} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey EXPLOSION = create(key("explosion")); + + /** + * {@code minecraft:explosion_emitter} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey EXPLOSION_EMITTER = create(key("explosion_emitter")); + + /** + * {@code minecraft:falling_dripstone_lava} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey FALLING_DRIPSTONE_LAVA = create(key("falling_dripstone_lava")); + + /** + * {@code minecraft:falling_dripstone_water} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey FALLING_DRIPSTONE_WATER = create(key("falling_dripstone_water")); + + /** + * {@code minecraft:falling_dust} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey FALLING_DUST = create(key("falling_dust")); + + /** + * {@code minecraft:falling_honey} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey FALLING_HONEY = create(key("falling_honey")); + + /** + * {@code minecraft:falling_lava} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey FALLING_LAVA = create(key("falling_lava")); + + /** + * {@code minecraft:falling_nectar} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey FALLING_NECTAR = create(key("falling_nectar")); + + /** + * {@code minecraft:falling_obsidian_tear} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey FALLING_OBSIDIAN_TEAR = create(key("falling_obsidian_tear")); + + /** + * {@code minecraft:falling_spore_blossom} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey FALLING_SPORE_BLOSSOM = create(key("falling_spore_blossom")); + + /** + * {@code minecraft:falling_water} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey FALLING_WATER = create(key("falling_water")); + + /** + * {@code minecraft:firefly} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey FIREFLY = create(key("firefly")); + + /** + * {@code minecraft:firework} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey FIREWORK = create(key("firework")); + + /** + * {@code minecraft:fishing} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey FISHING = create(key("fishing")); + + /** + * {@code minecraft:flame} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey FLAME = create(key("flame")); + + /** + * {@code minecraft:flash} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey FLASH = create(key("flash")); + + /** + * {@code minecraft:glow} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey GLOW = create(key("glow")); + + /** + * {@code minecraft:glow_squid_ink} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey GLOW_SQUID_INK = create(key("glow_squid_ink")); + + /** + * {@code minecraft:gust} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey GUST = create(key("gust")); + + /** + * {@code minecraft:gust_emitter_large} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey GUST_EMITTER_LARGE = create(key("gust_emitter_large")); + + /** + * {@code minecraft:gust_emitter_small} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey GUST_EMITTER_SMALL = create(key("gust_emitter_small")); + + /** + * {@code minecraft:happy_villager} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey HAPPY_VILLAGER = create(key("happy_villager")); + + /** + * {@code minecraft:heart} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey HEART = create(key("heart")); + + /** + * {@code minecraft:infested} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey INFESTED = create(key("infested")); + + /** + * {@code minecraft:instant_effect} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey INSTANT_EFFECT = create(key("instant_effect")); + + /** + * {@code minecraft:item} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ITEM = create(key("item")); + + /** + * {@code minecraft:item_cobweb} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ITEM_COBWEB = create(key("item_cobweb")); + + /** + * {@code minecraft:item_slime} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ITEM_SLIME = create(key("item_slime")); + + /** + * {@code minecraft:item_snowball} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ITEM_SNOWBALL = create(key("item_snowball")); + + /** + * {@code minecraft:landing_honey} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LANDING_HONEY = create(key("landing_honey")); + + /** + * {@code minecraft:landing_lava} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LANDING_LAVA = create(key("landing_lava")); + + /** + * {@code minecraft:landing_obsidian_tear} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LANDING_OBSIDIAN_TEAR = create(key("landing_obsidian_tear")); + + /** + * {@code minecraft:large_smoke} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LARGE_SMOKE = create(key("large_smoke")); + + /** + * {@code minecraft:lava} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LAVA = create(key("lava")); + + /** + * {@code minecraft:mycelium} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey MYCELIUM = create(key("mycelium")); + + /** + * {@code minecraft:nautilus} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NAUTILUS = create(key("nautilus")); + + /** + * {@code minecraft:note} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NOTE = create(key("note")); + + /** + * {@code minecraft:ominous_spawning} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey OMINOUS_SPAWNING = create(key("ominous_spawning")); + + /** + * {@code minecraft:pale_oak_leaves} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey PALE_OAK_LEAVES = create(key("pale_oak_leaves")); + + /** + * {@code minecraft:poof} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey POOF = create(key("poof")); + + /** + * {@code minecraft:portal} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey PORTAL = create(key("portal")); + + /** + * {@code minecraft:raid_omen} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey RAID_OMEN = create(key("raid_omen")); + + /** + * {@code minecraft:rain} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey RAIN = create(key("rain")); + + /** + * {@code minecraft:reverse_portal} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey REVERSE_PORTAL = create(key("reverse_portal")); + + /** + * {@code minecraft:scrape} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SCRAPE = create(key("scrape")); + + /** + * {@code minecraft:sculk_charge} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SCULK_CHARGE = create(key("sculk_charge")); + + /** + * {@code minecraft:sculk_charge_pop} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SCULK_CHARGE_POP = create(key("sculk_charge_pop")); + + /** + * {@code minecraft:sculk_soul} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SCULK_SOUL = create(key("sculk_soul")); + + /** + * {@code minecraft:shriek} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SHRIEK = create(key("shriek")); + + /** + * {@code minecraft:small_flame} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SMALL_FLAME = create(key("small_flame")); + + /** + * {@code minecraft:small_gust} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SMALL_GUST = create(key("small_gust")); + + /** + * {@code minecraft:smoke} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SMOKE = create(key("smoke")); + + /** + * {@code minecraft:sneeze} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SNEEZE = create(key("sneeze")); + + /** + * {@code minecraft:snowflake} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SNOWFLAKE = create(key("snowflake")); + + /** + * {@code minecraft:sonic_boom} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SONIC_BOOM = create(key("sonic_boom")); + + /** + * {@code minecraft:soul} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SOUL = create(key("soul")); + + /** + * {@code minecraft:soul_fire_flame} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SOUL_FIRE_FLAME = create(key("soul_fire_flame")); + + /** + * {@code minecraft:spit} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SPIT = create(key("spit")); + + /** + * {@code minecraft:splash} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SPLASH = create(key("splash")); + + /** + * {@code minecraft:spore_blossom_air} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SPORE_BLOSSOM_AIR = create(key("spore_blossom_air")); + + /** + * {@code minecraft:squid_ink} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SQUID_INK = create(key("squid_ink")); + + /** + * {@code minecraft:sweep_attack} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SWEEP_ATTACK = create(key("sweep_attack")); + + /** + * {@code minecraft:tinted_leaves} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey TINTED_LEAVES = create(key("tinted_leaves")); + + /** + * {@code minecraft:totem_of_undying} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey TOTEM_OF_UNDYING = create(key("totem_of_undying")); + + /** + * {@code minecraft:trail} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey TRAIL = create(key("trail")); + + /** + * {@code minecraft:trial_omen} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey TRIAL_OMEN = create(key("trial_omen")); + + /** + * {@code minecraft:trial_spawner_detection} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey TRIAL_SPAWNER_DETECTION = create(key("trial_spawner_detection")); + + /** + * {@code minecraft:trial_spawner_detection_ominous} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey TRIAL_SPAWNER_DETECTION_OMINOUS = create(key("trial_spawner_detection_ominous")); + + /** + * {@code minecraft:underwater} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey UNDERWATER = create(key("underwater")); + + /** + * {@code minecraft:vault_connection} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey VAULT_CONNECTION = create(key("vault_connection")); + + /** + * {@code minecraft:vibration} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey VIBRATION = create(key("vibration")); + + /** + * {@code minecraft:warped_spore} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey WARPED_SPORE = create(key("warped_spore")); + + /** + * {@code minecraft:wax_off} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey WAX_OFF = create(key("wax_off")); + + /** + * {@code minecraft:wax_on} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey WAX_ON = create(key("wax_on")); + + /** + * {@code minecraft:white_ash} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey WHITE_ASH = create(key("white_ash")); + + /** + * {@code minecraft:white_smoke} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey WHITE_SMOKE = create(key("white_smoke")); + + /** + * {@code minecraft:witch} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey WITCH = create(key("witch")); + + private ParticleTypeKeys() { + } + + private static TypedKey create(final Key key) { + return TypedKey.create(RegistryKey.PARTICLE_TYPE, key); + } +} diff --git a/paper-api/src/main/java/io/papermc/paper/particle/ParticleType.java b/paper-api/src/main/java/io/papermc/paper/particle/ParticleType.java new file mode 100644 index 000000000000..d33f76b2072d --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/particle/ParticleType.java @@ -0,0 +1,18 @@ +package io.papermc.paper.particle; + +import org.bukkit.Keyed; +import org.jetbrains.annotations.ApiStatus; + +public interface ParticleType extends Keyed { // todo migrate on top of existing api? + + @SuppressWarnings("unused") + @ApiStatus.NonExtendable + interface Valued extends ParticleType { + + } + + @ApiStatus.NonExtendable + interface NonValued extends ParticleType { + + } +} diff --git a/paper-api/src/main/java/io/papermc/paper/particle/Particles.java b/paper-api/src/main/java/io/papermc/paper/particle/Particles.java new file mode 100644 index 000000000000..cf5088ef6349 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/particle/Particles.java @@ -0,0 +1,149 @@ +package io.papermc.paper.particle; + +import net.kyori.adventure.key.Key; +import net.kyori.adventure.key.KeyPattern; +import org.bukkit.Color; +import org.bukkit.Particle; +import org.bukkit.Registry; +import org.bukkit.Vibration; +import org.bukkit.block.data.BlockData; +import org.bukkit.inventory.ItemStack; + +public final class Particles { + + public static final ParticleType.NonValued POOF = unvalued("poof"); + public static final ParticleType.NonValued EXPLOSION = unvalued("explosion"); + public static final ParticleType.NonValued EXPLOSION_EMITTER = unvalued("explosion_emitter"); + public static final ParticleType.NonValued FIREWORK = unvalued("firework"); + public static final ParticleType.NonValued BUBBLE = unvalued("bubble"); + public static final ParticleType.NonValued SPLASH = unvalued("splash"); + public static final ParticleType.NonValued FISHING = unvalued("fishing"); + public static final ParticleType.NonValued UNDERWATER = unvalued("underwater"); + public static final ParticleType.NonValued CRIT = unvalued("crit"); + public static final ParticleType.NonValued ENCHANTED_HIT = unvalued("enchanted_hit"); + public static final ParticleType.NonValued SMOKE = unvalued("smoke"); + public static final ParticleType.NonValued LARGE_SMOKE = unvalued("large_smoke"); + public static final ParticleType.Valued EFFECT = valued("effect"); + public static final ParticleType.Valued INSTANT_EFFECT = valued("instant_effect"); + public static final ParticleType.Valued ENTITY_EFFECT = valued("entity_effect"); + public static final ParticleType.NonValued WITCH = unvalued("witch"); + public static final ParticleType.NonValued DRIPPING_WATER = unvalued("dripping_water"); + public static final ParticleType.NonValued DRIPPING_LAVA = unvalued("dripping_lava"); + public static final ParticleType.NonValued ANGRY_VILLAGER = unvalued("angry_villager"); + public static final ParticleType.NonValued HAPPY_VILLAGER = unvalued("happy_villager"); + public static final ParticleType.NonValued MYCELIUM = unvalued("mycelium"); + public static final ParticleType.NonValued NOTE = unvalued("note"); + public static final ParticleType.NonValued PORTAL = unvalued("portal"); + public static final ParticleType.NonValued ENCHANT = unvalued("enchant"); + public static final ParticleType.NonValued FLAME = unvalued("flame"); + public static final ParticleType.NonValued LAVA = unvalued("lava"); + public static final ParticleType.NonValued CLOUD = unvalued("cloud"); + public static final ParticleType.Valued DUST = valued("dust"); + public static final ParticleType.NonValued ITEM_SNOWBALL = unvalued("item_snowball"); + public static final ParticleType.NonValued ITEM_SLIME = unvalued("item_slime"); + public static final ParticleType.NonValued HEART = unvalued("heart"); + public static final ParticleType.Valued ITEM = valued("item"); + public static final ParticleType.Valued BLOCK = valued("block"); + public static final ParticleType.NonValued RAIN = unvalued("rain"); + public static final ParticleType.NonValued ELDER_GUARDIAN = unvalued("elder_guardian"); + public static final ParticleType.Valued DRAGON_BREATH = valued("dragon_breath"); + public static final ParticleType.NonValued END_ROD = unvalued("end_rod"); + public static final ParticleType.NonValued DAMAGE_INDICATOR = unvalued("damage_indicator"); + public static final ParticleType.NonValued SWEEP_ATTACK = unvalued("sweep_attack"); + public static final ParticleType.Valued FALLING_DUST = valued("falling_dust"); + public static final ParticleType.NonValued TOTEM_OF_UNDYING = unvalued("totem_of_undying"); + public static final ParticleType.NonValued SPIT = unvalued("spit"); + public static final ParticleType.NonValued SQUID_INK = unvalued("squid_ink"); + public static final ParticleType.NonValued BUBBLE_POP = unvalued("bubble_pop"); + public static final ParticleType.NonValued CURRENT_DOWN = unvalued("current_down"); + public static final ParticleType.NonValued BUBBLE_COLUMN_UP = unvalued("bubble_column_up"); + public static final ParticleType.NonValued NAUTILUS = unvalued("nautilus"); + public static final ParticleType.NonValued DOLPHIN = unvalued("dolphin"); + public static final ParticleType.NonValued SNEEZE = unvalued("sneeze"); + public static final ParticleType.NonValued CAMPFIRE_COSY_SMOKE = unvalued("campfire_cosy_smoke"); + public static final ParticleType.NonValued CAMPFIRE_SIGNAL_SMOKE = unvalued("campfire_signal_smoke"); + public static final ParticleType.NonValued COMPOSTER = unvalued("composter"); + public static final ParticleType.Valued FLASH = valued("flash"); + public static final ParticleType.NonValued FALLING_LAVA = unvalued("falling_lava"); + public static final ParticleType.NonValued LANDING_LAVA = unvalued("landing_lava"); + public static final ParticleType.NonValued FALLING_WATER = unvalued("falling_water"); + public static final ParticleType.NonValued DRIPPING_HONEY = unvalued("dripping_honey"); + public static final ParticleType.NonValued FALLING_HONEY = unvalued("falling_honey"); + public static final ParticleType.NonValued LANDING_HONEY = unvalued("landing_honey"); + public static final ParticleType.NonValued FALLING_NECTAR = unvalued("falling_nectar"); + public static final ParticleType.NonValued SOUL_FIRE_FLAME = unvalued("soul_fire_flame"); + public static final ParticleType.NonValued ASH = unvalued("ash"); + public static final ParticleType.NonValued CRIMSON_SPORE = unvalued("crimson_spore"); + public static final ParticleType.NonValued WARPED_SPORE = unvalued("warped_spore"); + public static final ParticleType.NonValued SOUL = unvalued("soul"); + public static final ParticleType.NonValued DRIPPING_OBSIDIAN_TEAR = unvalued("dripping_obsidian_tear"); + public static final ParticleType.NonValued FALLING_OBSIDIAN_TEAR = unvalued("falling_obsidian_tear"); + public static final ParticleType.NonValued LANDING_OBSIDIAN_TEAR = unvalued("landing_obsidian_tear"); + public static final ParticleType.NonValued REVERSE_PORTAL = unvalued("reverse_portal"); + public static final ParticleType.NonValued WHITE_ASH = unvalued("white_ash"); + public static final ParticleType.Valued DUST_COLOR_TRANSITION = valued("dust_color_transition"); + public static final ParticleType.Valued VIBRATION = valued("vibration"); + public static final ParticleType.NonValued FALLING_SPORE_BLOSSOM = unvalued("falling_spore_blossom"); + public static final ParticleType.NonValued SPORE_BLOSSOM_AIR = unvalued("spore_blossom_air"); + public static final ParticleType.NonValued SMALL_FLAME = unvalued("small_flame"); + public static final ParticleType.NonValued SNOWFLAKE = unvalued("snowflake"); + public static final ParticleType.NonValued DRIPPING_DRIPSTONE_LAVA = unvalued("dripping_dripstone_lava"); + public static final ParticleType.NonValued FALLING_DRIPSTONE_LAVA = unvalued("falling_dripstone_lava"); + public static final ParticleType.NonValued DRIPPING_DRIPSTONE_WATER = unvalued("dripping_dripstone_water"); + public static final ParticleType.NonValued FALLING_DRIPSTONE_WATER = unvalued("falling_dripstone_water"); + public static final ParticleType.NonValued GLOW_SQUID_INK = unvalued("glow_squid_ink"); + public static final ParticleType.NonValued GLOW = unvalued("glow"); + public static final ParticleType.NonValued WAX_ON = unvalued("wax_on"); + public static final ParticleType.NonValued WAX_OFF = unvalued("wax_off"); + public static final ParticleType.NonValued ELECTRIC_SPARK = unvalued("electric_spark"); + public static final ParticleType.NonValued SCRAPE = unvalued("scrape"); + public static final ParticleType.NonValued SONIC_BOOM = unvalued("sonic_boom"); + public static final ParticleType.NonValued SCULK_SOUL = unvalued("sculk_soul"); + public static final ParticleType.Valued SCULK_CHARGE = valued("sculk_charge"); + public static final ParticleType.NonValued SCULK_CHARGE_POP = unvalued("sculk_charge_pop"); + public static final ParticleType.Valued SHRIEK = valued("shriek"); + public static final ParticleType.NonValued CHERRY_LEAVES = unvalued("cherry_leaves"); + public static final ParticleType.NonValued PALE_OAK_LEAVES = unvalued("pale_oak_leaves"); + public static final ParticleType.Valued TINTED_LEAVES = valued("tinted_leaves"); + public static final ParticleType.NonValued EGG_CRACK = unvalued("egg_crack"); + public static final ParticleType.NonValued DUST_PLUME = unvalued("dust_plume"); + public static final ParticleType.NonValued WHITE_SMOKE = unvalued("white_smoke"); + public static final ParticleType.NonValued GUST = unvalued("gust"); + public static final ParticleType.NonValued SMALL_GUST = unvalued("small_gust"); + public static final ParticleType.NonValued GUST_EMITTER_LARGE = unvalued("gust_emitter_large"); + public static final ParticleType.NonValued GUST_EMITTER_SMALL = unvalued("gust_emitter_small"); + public static final ParticleType.NonValued TRIAL_SPAWNER_DETECTION = unvalued("trial_spawner_detection"); + public static final ParticleType.NonValued TRIAL_SPAWNER_DETECTION_OMINOUS = unvalued("trial_spawner_detection_ominous"); + public static final ParticleType.NonValued VAULT_CONNECTION = unvalued("vault_connection"); + public static final ParticleType.NonValued INFESTED = unvalued("infested"); + public static final ParticleType.NonValued ITEM_COBWEB = unvalued("item_cobweb"); + public static final ParticleType.Valued DUST_PILLAR = valued("dust_pillar"); + public static final ParticleType.Valued BLOCK_CRUMBLE = valued("block_crumble"); + public static final ParticleType.NonValued FIREFLY = unvalued("firefly"); + public static final ParticleType.Valued TRAIL = valued("trail"); + public static final ParticleType.NonValued OMINOUS_SPAWNING = unvalued("ominous_spawning"); + public static final ParticleType.NonValued RAID_OMEN = unvalued("raid_omen"); + public static final ParticleType.NonValued TRIAL_OMEN = unvalued("trial_omen"); + public static final ParticleType.Valued BLOCK_MARKER = valued("block_marker"); + public static final ParticleType.NonValued COPPER_FIRE_FLAME = unvalued("copper_fire_flame"); + + private static ParticleType.NonValued unvalued(final @KeyPattern.Value String name) { + final ParticleType memoryKey = Registry.PARTICLE_TYPE.getOrThrow(Key.key(Key.MINECRAFT_NAMESPACE, name)); + if (memoryKey instanceof ParticleType.NonValued) { + return (ParticleType.NonValued) memoryKey; + } + throw new IllegalStateException(name + " is not a valid unvalued type, it is a " + memoryKey.getClass().getTypeName()); + } + + @SuppressWarnings("unchecked") + private static ParticleType.Valued valued(final @KeyPattern.Value String name) { + final ParticleType memoryKey = Registry.PARTICLE_TYPE.getOrThrow(Key.key(Key.MINECRAFT_NAMESPACE, name)); + if (memoryKey instanceof ParticleType.Valued) { + return (ParticleType.Valued) memoryKey; + } + throw new IllegalStateException(name + " is not a valid valued type, it is a " + memoryKey.getClass().getTypeName()); + } + + private Particles() { + } +} diff --git a/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java b/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java index 66d3748a0985..60d1c6ece03b 100644 --- a/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java +++ b/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java @@ -2,6 +2,7 @@ import io.papermc.paper.datacomponent.DataComponentType; import io.papermc.paper.dialog.Dialog; +import io.papermc.paper.particle.ParticleType; import io.papermc.paper.registry.tag.TagKey; import io.papermc.paper.world.attribute.EnvironmentalAttributeType; import net.kyori.adventure.key.Key; @@ -13,7 +14,6 @@ import org.bukkit.GameRule; import org.bukkit.JukeboxSong; import org.bukkit.MusicInstrument; -import org.bukkit.Particle; import org.bukkit.Sound; import org.bukkit.attribute.Attribute; import org.bukkit.block.Biome; @@ -140,6 +140,11 @@ public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { */ @ApiStatus.Experimental RegistryKey> ENVIRONMENT_ATTRIBUTE = create("environment_attribute"); + /** + * Built-in registry for particle types. + * @see io.papermc.paper.registry.keys.ParticleTypeKeys + */ + RegistryKey PARTICLE_TYPE = create("particle_type"); /* ********************** * * Data-driven Registries * @@ -245,7 +250,6 @@ public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { * API-only Registries * * ******************* */ RegistryKey ENTITY_TYPE = create("entity_type"); - RegistryKey PARTICLE_TYPE = create("particle_type"); RegistryKey POTION = create("potion"); RegistryKey> MEMORY_MODULE_TYPE = create("memory_module_type"); diff --git a/paper-api/src/main/java/org/bukkit/Registry.java b/paper-api/src/main/java/org/bukkit/Registry.java index 3cfa4feae9b6..fa14a7257515 100644 --- a/paper-api/src/main/java/org/bukkit/Registry.java +++ b/paper-api/src/main/java/org/bukkit/Registry.java @@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import io.papermc.paper.datacomponent.DataComponentType; +import io.papermc.paper.particle.ParticleType; import io.papermc.paper.registry.RegistryAccess; import io.papermc.paper.registry.RegistryKey; import io.papermc.paper.registry.TypedKey; @@ -208,9 +209,9 @@ public Iterator iterator() { /** * Server particles. * - * @see Particle + * @see ParticleType */ - Registry PARTICLE_TYPE = registryFor(RegistryKey.PARTICLE_TYPE); // Paper + Registry PARTICLE_TYPE = registryFor(RegistryKey.PARTICLE_TYPE); // Paper /** * Server potions. * diff --git a/paper-api/src/main/java/org/bukkit/entity/Player.java b/paper-api/src/main/java/org/bukkit/entity/Player.java index 3eef8d533c2a..2a2c30aaf8ea 100644 --- a/paper-api/src/main/java/org/bukkit/entity/Player.java +++ b/paper-api/src/main/java/org/bukkit/entity/Player.java @@ -4,6 +4,7 @@ import io.papermc.paper.entity.LookAnchor; import io.papermc.paper.entity.PlayerGiveResult; import io.papermc.paper.math.Position; +import io.papermc.paper.particle.ParticleType; import java.net.InetAddress; import java.net.InetSocketAddress; import java.time.Duration; @@ -3333,6 +3334,10 @@ default void spawnParticle(Particle particle, Location location, int count, */ public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, @Nullable T data, boolean force); + void spawnParticle(ParticleType.NonValued particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, boolean force); + + void spawnParticle(ParticleType.Valued particleType, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, @Nullable T data, boolean force); + /** * Return the player's progression on the specified advancement. * diff --git a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java index 820637c42921..88b30dfcd8fb 100644 --- a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java +++ b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java @@ -4,6 +4,8 @@ import io.papermc.paper.datacomponent.DataComponentType; import io.papermc.paper.datacomponent.DataComponentTypes; import io.papermc.paper.dialog.Dialog; +import io.papermc.paper.particle.ParticleType; +import io.papermc.paper.particle.Particles; import io.papermc.paper.registry.data.BannerPatternRegistryEntry; import io.papermc.paper.registry.data.CatTypeRegistryEntry; import io.papermc.paper.registry.data.ChickenVariantRegistryEntry; @@ -36,7 +38,6 @@ import java.util.stream.Collectors; import net.minecraft.core.Registry; import net.minecraft.core.component.DataComponents; -import net.minecraft.core.particles.ParticleTypes; import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; import net.minecraft.server.dialog.Dialogs; @@ -78,7 +79,6 @@ import org.bukkit.JukeboxSong; import org.bukkit.Keyed; import org.bukkit.MusicInstrument; -import org.bukkit.Particle; import org.bukkit.Sound; import org.bukkit.attribute.Attribute; import org.bukkit.block.Biome; @@ -175,7 +175,8 @@ private static RegistryEntry inconsistentEntry(ResourceKey> DATA_DRIVEN = List.of( @@ -202,7 +203,6 @@ private static RegistryEntry inconsistentEntry(ResourceKey> API_ONLY = List.of( entry(Registries.ENTITY_TYPE, net.minecraft.world.entity.EntityType.class, EntityType.class), - entry(Registries.PARTICLE_TYPE, ParticleTypes.class, Particle.class), entry(Registries.POTION, Potions.class, PotionType.class), entry(Registries.MEMORY_MODULE_TYPE, MemoryModuleType.class, MemoryKey.class) ); diff --git a/paper-server/src/main/java/io/papermc/paper/particle/PaperParticleType.java b/paper-server/src/main/java/io/papermc/paper/particle/PaperParticleType.java new file mode 100644 index 000000000000..d30f32029d57 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/particle/PaperParticleType.java @@ -0,0 +1,285 @@ +package io.papermc.paper.particle; + +import io.papermc.paper.registry.HolderableBase; +import io.papermc.paper.registry.typed.PaperTypedDataAdapters; +import io.papermc.paper.registry.typed.PaperTypedDataCollector; +import io.papermc.paper.registry.typed.TypedDataCollector; +import io.papermc.paper.util.converter.Converter; +import io.papermc.paper.util.converter.Converters; +import java.util.function.Function; +import net.minecraft.core.Holder; +import net.minecraft.core.particles.BlockParticleOption; +import net.minecraft.core.particles.ColorParticleOption; +import net.minecraft.core.particles.DustColorTransitionOptions; +import net.minecraft.core.particles.DustParticleOptions; +import net.minecraft.core.particles.ItemParticleOption; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleType; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.core.particles.PowerParticleOption; +import net.minecraft.core.particles.SculkChargeParticleOptions; +import net.minecraft.core.particles.ShriekParticleOption; +import net.minecraft.core.particles.SpellParticleOption; +import net.minecraft.core.particles.TrailParticleOption; +import net.minecraft.core.particles.VibrationParticleOption; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.gameevent.BlockPositionSource; +import net.minecraft.world.level.gameevent.EntityPositionSource; +import net.minecraft.world.level.gameevent.PositionSource; +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.Vibration; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.CraftRegistry; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftLocation; +import org.bukkit.inventory.ItemStack; + +import static io.papermc.paper.util.converter.Converter.direct; + +public abstract class PaperParticleType extends HolderableBase> implements io.papermc.paper.particle.ParticleType { + + private static Function unsupportedOperation() { + final class Holder { + private static final Function UNSUPPORTED_OPERATION = $ -> { + throw new UnsupportedOperationException(); + }; + } + + //noinspection unchecked + return (Function) Holder.UNSUPPORTED_OPERATION; // todo we probably want to support this at some point in the future + } + + // this is a hack around generics limitations to prevent + // having to define generics on each register call as seen below, making collectors easier to read: + // collector.register(...) + private static void register(final TypedDataCollector> collector, final ParticleType type, Function, Converter> converter) { + collector.register(type, converter.apply(type).serializable(type.codec().codec())); + } + + @SuppressWarnings("RedundantTypeArguments") + private static final PaperTypedDataAdapters> ADAPTERS = PaperTypedDataAdapters., PaperTypedDataCollector>>create( + BuiltInRegistries.PARTICLE_TYPE, + PaperTypedDataCollector::new, + collector -> { + collector.dispatch($ -> Converters.unvalued()).add( + ParticleTypes.POOF, + ParticleTypes.EXPLOSION, + ParticleTypes.EXPLOSION_EMITTER, + ParticleTypes.FIREWORK, + ParticleTypes.BUBBLE, + ParticleTypes.SPLASH, + ParticleTypes.FISHING, + ParticleTypes.UNDERWATER, + ParticleTypes.CRIT, + ParticleTypes.ENCHANTED_HIT, + ParticleTypes.SMOKE, + ParticleTypes.LARGE_SMOKE, + ParticleTypes.WITCH, + ParticleTypes.DRIPPING_WATER, + ParticleTypes.DRIPPING_LAVA, + ParticleTypes.ANGRY_VILLAGER, + ParticleTypes.HAPPY_VILLAGER, + ParticleTypes.MYCELIUM, + ParticleTypes.NOTE, + ParticleTypes.PORTAL, + ParticleTypes.ENCHANT, + ParticleTypes.FLAME, + ParticleTypes.LAVA, + ParticleTypes.CLOUD, + ParticleTypes.ITEM_SNOWBALL, + ParticleTypes.ITEM_SLIME, + ParticleTypes.HEART, + ParticleTypes.RAIN, + ParticleTypes.ELDER_GUARDIAN, + ParticleTypes.END_ROD, + ParticleTypes.DAMAGE_INDICATOR, + ParticleTypes.SWEEP_ATTACK, + ParticleTypes.TOTEM_OF_UNDYING, + ParticleTypes.SPIT, + ParticleTypes.SQUID_INK, + ParticleTypes.BUBBLE_POP, + ParticleTypes.CURRENT_DOWN, + ParticleTypes.BUBBLE_COLUMN_UP, + ParticleTypes.NAUTILUS, + ParticleTypes.DOLPHIN, + ParticleTypes.SNEEZE, + ParticleTypes.CAMPFIRE_COSY_SMOKE, + ParticleTypes.CAMPFIRE_SIGNAL_SMOKE, + ParticleTypes.COMPOSTER, + ParticleTypes.FALLING_LAVA, + ParticleTypes.LANDING_LAVA, + ParticleTypes.FALLING_WATER, + ParticleTypes.DRIPPING_HONEY, + ParticleTypes.FALLING_HONEY, + ParticleTypes.LANDING_HONEY, + ParticleTypes.FALLING_NECTAR, + ParticleTypes.SOUL_FIRE_FLAME, + ParticleTypes.ASH, + ParticleTypes.CRIMSON_SPORE, + ParticleTypes.WARPED_SPORE, + ParticleTypes.SOUL, + ParticleTypes.DRIPPING_OBSIDIAN_TEAR, + ParticleTypes.FALLING_OBSIDIAN_TEAR, + ParticleTypes.LANDING_OBSIDIAN_TEAR, + ParticleTypes.REVERSE_PORTAL, + ParticleTypes.WHITE_ASH, + ParticleTypes.FALLING_SPORE_BLOSSOM, + ParticleTypes.SPORE_BLOSSOM_AIR, + ParticleTypes.SMALL_FLAME, + ParticleTypes.SNOWFLAKE, + ParticleTypes.DRIPPING_DRIPSTONE_LAVA, + ParticleTypes.FALLING_DRIPSTONE_LAVA, + ParticleTypes.DRIPPING_DRIPSTONE_WATER, + ParticleTypes.FALLING_DRIPSTONE_WATER, + ParticleTypes.GLOW_SQUID_INK, + ParticleTypes.GLOW, + ParticleTypes.WAX_ON, + ParticleTypes.WAX_OFF, + ParticleTypes.ELECTRIC_SPARK, + ParticleTypes.SCRAPE, + ParticleTypes.SONIC_BOOM, + ParticleTypes.SCULK_SOUL, + ParticleTypes.SCULK_CHARGE_POP, + ParticleTypes.CHERRY_LEAVES, + ParticleTypes.PALE_OAK_LEAVES, + ParticleTypes.EGG_CRACK, + ParticleTypes.DUST_PLUME, + ParticleTypes.WHITE_SMOKE, + ParticleTypes.GUST, + ParticleTypes.SMALL_GUST, + ParticleTypes.GUST_EMITTER_LARGE, + ParticleTypes.GUST_EMITTER_SMALL, + ParticleTypes.TRIAL_SPAWNER_DETECTED_PLAYER, + ParticleTypes.TRIAL_SPAWNER_DETECTED_PLAYER_OMINOUS, + ParticleTypes.VAULT_CONNECTION, + ParticleTypes.INFESTED, + ParticleTypes.ITEM_COBWEB, + ParticleTypes.FIREFLY, + ParticleTypes.OMINOUS_SPAWNING, + ParticleTypes.RAID_OMEN, + ParticleTypes.TRIAL_OMEN, + ParticleTypes.COPPER_FIRE_FLAME + ); + + interface ConverterGetter { + M forType(ParticleType type, A value); + + default Converter get(ParticleType type) { + return direct(unsupportedOperation(), value -> this.forType(type, value)); + } + } + + final ConverterGetter item = (type, value) -> { + return new ItemParticleOption(type, CraftItemStack.asNMSCopy(value)); + }; + final ConverterGetter block = (type, value) -> { + return new BlockParticleOption(type, ((CraftBlockData) value).getState()); + }; + final ConverterGetter power = PowerParticleOption::create; + final ConverterGetter spell = (type, value) -> { + return SpellParticleOption.create(type, value.getColor().asARGB(), value.getPower()); + }; + final ConverterGetter color = (type, value) -> ColorParticleOption.create(type, value.asARGB()); + final ConverterGetter dust = (type, value) -> { + return new DustParticleOptions(value.getColor().asRGB(), value.getSize()); + }; + final ConverterGetter dustTransition = (type, value) -> { + return new DustColorTransitionOptions(value.getColor().asRGB(), value.getToColor().asRGB(), value.getSize()); + }; + final ConverterGetter vibration = (type, value) -> { + final PositionSource source; + if (value.getDestination() instanceof Vibration.Destination.BlockDestination blockDestination) { + Location destination = blockDestination.getLocation(); + source = new BlockPositionSource(CraftLocation.toBlockPosition(destination)); + } else if (value.getDestination() instanceof Vibration.Destination.EntityDestination entityDestination) { + Entity destination = ((CraftEntity) entityDestination.getEntity()).getHandle(); + source = new EntityPositionSource(destination, destination.getEyeHeight()); + } else { + throw new IllegalStateException("Unknown vibration destination " + value.getDestination()); + } + + return new VibrationParticleOption(source, value.getArrivalTime()); + }; + final ConverterGetter sculkCharge = (type, value) -> new SculkChargeParticleOptions(value); + final ConverterGetter shriek = (type, value) -> new ShriekParticleOption(value); + final ConverterGetter trail = (type, value) -> { + return new TrailParticleOption(CraftLocation.toVec3(value.getTarget()), value.getColor().asRGB(), value.getDuration()); + }; + + register(collector, ParticleTypes.EFFECT, spell::get); + register(collector, ParticleTypes.INSTANT_EFFECT, spell::get); + register(collector, ParticleTypes.ENTITY_EFFECT, color::get); + register(collector, ParticleTypes.DUST, dust::get); + register(collector, ParticleTypes.ITEM, item::get); + register(collector, ParticleTypes.BLOCK, block::get); + register(collector, ParticleTypes.DRAGON_BREATH, power::get); + register(collector, ParticleTypes.FALLING_DUST, block::get); + register(collector, ParticleTypes.FLASH, color::get); + register(collector, ParticleTypes.DUST_COLOR_TRANSITION, dustTransition::get); + register(collector, ParticleTypes.VIBRATION, vibration::get); + register(collector, ParticleTypes.SCULK_CHARGE, sculkCharge::get); + register(collector, ParticleTypes.SHRIEK, shriek::get); + register(collector, ParticleTypes.TINTED_LEAVES, color::get); + register(collector, ParticleTypes.DUST_PILLAR, block::get); + register(collector, ParticleTypes.BLOCK_CRUMBLE, block::get); + register(collector, ParticleTypes.TRAIL, trail::get); + register(collector, ParticleTypes.BLOCK_MARKER, block::get); + } + ); + + public static ParticleType bukkitToMinecraft(final io.papermc.paper.particle.ParticleType type) { + return CraftRegistry.bukkitToMinecraft(type); + } + + public static io.papermc.paper.particle.ParticleType minecraftToBukkit(final ParticleType type) { + return CraftRegistry.minecraftToBukkit(type, Registries.PARTICLE_TYPE); + } + + private final Converter converter; + + private PaperParticleType(final Holder> holder, final Converter converter) { + super(holder); + this.converter = converter; + } + + public Converter getConverter() { + return this.converter; + } + + @SuppressWarnings("unchecked") + public static io.papermc.paper.particle.ParticleType of(final Holder holder) { + final Holder.Reference> reference = (Holder.Reference>) holder; + final Converter converter = PaperParticleType.ADAPTERS.get(reference.key()); + if (converter.equals(Converters.unvalued())) { + return new NonValuedImpl<>(reference, converter); + } else { + return new ValuedImpl<>(reference, converter); + } + } + + public static final class NonValuedImpl extends PaperParticleType implements NonValued { + + NonValuedImpl( + final Holder> holder, + final Converter adapter + ) { + super(holder, adapter); + } + } + + public static final class ValuedImpl extends PaperParticleType implements Valued { + + ValuedImpl( + final Holder> holder, + final Converter adapter + ) { + super(holder, adapter); + } + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java index 60d2b36f8262..85d7a9022c88 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java @@ -6,6 +6,8 @@ import io.papermc.paper.datacomponent.PaperDataComponentType; import io.papermc.paper.dialog.Dialog; import io.papermc.paper.dialog.PaperDialog; +import io.papermc.paper.particle.PaperParticleType; +import io.papermc.paper.particle.Particles; import io.papermc.paper.registry.data.PaperBannerPatternRegistryEntry; import io.papermc.paper.registry.data.PaperCatTypeRegistryEntry; import io.papermc.paper.registry.data.PaperChickenVariantRegistryEntry; @@ -124,6 +126,7 @@ public final class PaperRegistries { start(Registries.DATA_COMPONENT_TYPE, RegistryKey.DATA_COMPONENT_TYPE).craft(DataComponentTypes.class, PaperDataComponentType::of).build(), start(Registries.GAME_RULE, RegistryKey.GAME_RULE).craft(GameRule.class, CraftGameRule::new).build(), start(Registries.ENVIRONMENT_ATTRIBUTE, RegistryKey.ENVIRONMENT_ATTRIBUTE).craft(EnvironmentalAttributeTypes.class, PaperEnvironmentalAttributeType::of).build(), + start(Registries.PARTICLE_TYPE, RegistryKey.PARTICLE_TYPE).craft(Particles.class, PaperParticleType::of).build(), // data-driven start(Registries.BIOME, RegistryKey.BIOME).craft(Biome.class, CraftBiome::new).build().delayed(), @@ -148,7 +151,6 @@ public final class PaperRegistries { // api-only start(Registries.ENTITY_TYPE, RegistryKey.ENTITY_TYPE).apiOnly(PaperSimpleRegistry::entityType), - start(Registries.PARTICLE_TYPE, RegistryKey.PARTICLE_TYPE).apiOnly(PaperSimpleRegistry::particleType), start(Registries.POTION, RegistryKey.POTION).apiOnly(PaperSimpleRegistry::potion), start(Registries.MEMORY_MODULE_TYPE, RegistryKey.MEMORY_MODULE_TYPE).apiOnly(() -> org.bukkit.Registry.MEMORY_MODULE_TYPE) // End generate - RegistryDefinitions diff --git a/paper-server/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java b/paper-server/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java index 7c3fdfb46efb..aca3a3d25044 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java @@ -8,7 +8,6 @@ import net.minecraft.core.HolderSet; import net.minecraft.core.registries.BuiltInRegistries; import org.bukkit.Keyed; -import org.bukkit.Particle; import org.bukkit.Registry; import org.bukkit.entity.EntityType; import org.bukkit.potion.PotionType; @@ -21,10 +20,6 @@ static Registry entityType() { return new PaperSimpleRegistry<>(EntityType.class, entity -> entity != EntityType.UNKNOWN, BuiltInRegistries.ENTITY_TYPE); } - static Registry particleType() { - return new PaperSimpleRegistry<>(Particle.class, BuiltInRegistries.PARTICLE_TYPE); - } - static Registry potion() { return new PaperSimpleRegistry<>(PotionType.class, BuiltInRegistries.POTION); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftParticle.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftParticle.java index 3f940a89a336..f8d0319c520b 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftParticle.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftParticle.java @@ -45,14 +45,15 @@ public abstract class CraftParticle implements Keyed { private static final Registry> CRAFT_PARTICLE_REGISTRY = new CraftParticleRegistry(CraftRegistry.getMinecraftRegistry(Registries.PARTICLE_TYPE)); public static Particle minecraftToBukkit(net.minecraft.core.particles.ParticleType minecraft) { - Preconditions.checkArgument(minecraft != null); + /*Preconditions.checkArgument(minecraft != null); net.minecraft.core.Registry> registry = CraftRegistry.getMinecraftRegistry(Registries.PARTICLE_TYPE); Particle bukkit = Registry.PARTICLE_TYPE.get(CraftNamespacedKey.fromMinecraft(registry.getResourceKey(minecraft).orElseThrow().identifier())); Preconditions.checkArgument(bukkit != null); - return bukkit; + return bukkit;*/ + throw new UnsupportedOperationException(); // todo } public static net.minecraft.core.particles.ParticleType bukkitToMinecraft(Particle bukkit) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index d86ebc4cd182..6307f07e28cb 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -19,7 +19,11 @@ import io.papermc.paper.entity.PaperPlayerGiveResult; import io.papermc.paper.entity.PlayerGiveResult; import io.papermc.paper.math.Position; +import io.papermc.paper.particle.PaperParticleType; +import io.papermc.paper.particle.ParticleType; import io.papermc.paper.util.MCUtil; +import io.papermc.paper.util.converter.CodecConverter; +import io.papermc.paper.util.converter.Converter; import it.unimi.dsi.fastutil.shorts.ShortArraySet; import it.unimi.dsi.fastutil.shorts.ShortSet; import java.io.ByteArrayOutputStream; @@ -58,6 +62,8 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.SectionPos; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.SimpleParticleType; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.PlayerChatMessage; @@ -2676,6 +2682,29 @@ public void spawnParticle(Particle particle, double x, double y, double z, i this.getHandle().connection.send(packet); } + @Override + public void spawnParticle(ParticleType.NonValued particleType, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, boolean force) { + ClientboundLevelParticlesPacket packet = new ClientboundLevelParticlesPacket((SimpleParticleType) PaperParticleType.bukkitToMinecraft(particleType), force, false, x, y, z, (float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, count); + this.getHandle().connection.send(packet); + } + + @Override + public void spawnParticle(ParticleType.Valued particleType, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data, boolean force) { + final PaperParticleType type = (PaperParticleType) particleType; + final Converter converter = type.getConverter(); + final ParticleOptions particle = converter.toVanilla(data); + if (converter instanceof CodecConverter codecConverter) { + // todo should be done in the data structure themself + // this is only useful for identity but since no particle have direct types it should be removed + // especially since some particle like scalable clamp the data themself so plugins have no way to know they are doing something wrong + codecConverter.validate(particle, true).ifPresent(message -> { + throw new IllegalArgumentException("Failed to encode particle of %s (%s)".formatted(type.getKey().asString(), message)); + }); + } + ClientboundLevelParticlesPacket packet = new ClientboundLevelParticlesPacket(particle, force, false, x, y, z, (float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, count); + this.getHandle().connection.send(packet); + } + @Override public org.bukkit.advancement.AdvancementProgress getAdvancementProgress(org.bukkit.advancement.Advancement advancement) { Preconditions.checkArgument(advancement != null, "advancement"); diff --git a/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java b/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java index 6e85565ab378..bb3bcc788a74 100644 --- a/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java +++ b/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java @@ -4,13 +4,16 @@ import io.papermc.paper.datacomponent.DataComponentTypes; import io.papermc.paper.dialog.Dialog; import io.papermc.paper.dialog.PaperDialog; +import io.papermc.paper.particle.PaperParticleType; +import io.papermc.paper.particle.ParticleType; +import io.papermc.paper.particle.Particles; import io.papermc.paper.registry.PaperRegistries; import io.papermc.paper.registry.RegistryKey; import io.papermc.paper.world.attribute.EnvironmentalAttributeType; import io.papermc.paper.world.attribute.EnvironmentalAttributeTypes; +import io.papermc.paper.world.attribute.PaperEnvironmentalAttributeType; import java.util.List; import java.util.stream.Stream; -import io.papermc.paper.world.attribute.PaperEnvironmentalAttributeType; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; @@ -154,6 +157,7 @@ public Object[] get() { register(Registries.DIALOG, Dialog.class, PaperDialog.class, net.minecraft.server.dialog.Dialog.class); register(Registries.GAME_RULE, GameRule.class, GameRules.class, CraftGameRule.class, net.minecraft.world.level.gamerules.GameRule.class); register(Registries.ENVIRONMENT_ATTRIBUTE, EnvironmentalAttributeType.class, EnvironmentalAttributeTypes.class, PaperEnvironmentalAttributeType.class, EnvironmentAttribute.class); + register(Registries.PARTICLE_TYPE, ParticleType.class, Particles.class, PaperParticleType.class, net.minecraft.core.particles.ParticleType.class); } private static void register(ResourceKey> registryKey, Class api, Class impl, Class internal) {