diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/EnvironmentalAttributeTypeKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/EnvironmentalAttributeTypeKeys.java new file mode 100644 index 000000000000..5dd4bb5ae1a8 --- /dev/null +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/EnvironmentalAttributeTypeKeys.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 EnvironmentalAttributeTypeKeys { + /** + * {@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 EnvironmentalAttributeTypeKeys() { + } + + private static TypedKey> create(final Key key) { + return TypedKey.create(RegistryKey.ENVIRONMENT_ATTRIBUTE, key); + } +} 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/InternalAPIBridge.java b/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java index 7031a6bc9e60..8abe18b14b46 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.Set; @@ -104,4 +105,6 @@ class Holder { GameRule legacyGameRuleBridge(GameRule rule, Function fromLegacyToModern, Function toLegacyFromModern, Class legacyClass); Set validMannequinPoses(); + + EnvironmentalAttributeContext.Builder environmentalAttributeContextBuilder(); } 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-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 dcee3d88f5b7..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,7 +2,9 @@ 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; import net.kyori.adventure.key.KeyPattern; import net.kyori.adventure.key.Keyed; @@ -12,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; @@ -39,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; @@ -132,6 +134,17 @@ 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.EnvironmentalAttributeTypeKeys + */ + @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 * @@ -237,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/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..2d7101423c55 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttribute.java @@ -0,0 +1,25 @@ +package io.papermc.paper.world.attribute; + +import io.papermc.paper.math.Position; +import java.util.function.UnaryOperator; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Experimental +@ApiStatus.NonExtendable +public interface EnvironmentalAttribute { + + T getGlobal(); + + T getPositioned(Position position); + + default T getTimed(long time) { + 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 new file mode 100644 index 000000000000..dfd0073d2ff2 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeContext.java @@ -0,0 +1,42 @@ +package io.papermc.paper.world.attribute; + +import io.papermc.paper.InternalAPIBridge; +import io.papermc.paper.math.Position; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.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 new file mode 100644 index 000000000000..18197a02299e --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeType.java @@ -0,0 +1,12 @@ +package io.papermc.paper.world.attribute; + +import org.bukkit.Keyed; +import org.jetbrains.annotations.ApiStatus; + +@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..c3ff32b1858f --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/world/attribute/EnvironmentalAttributeTypes.java @@ -0,0 +1,121 @@ +package io.papermc.paper.world.attribute; + +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.bukkit.Color; +import org.bukkit.Registry; + +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 @KeyPattern.Value String key) { + return (EnvironmentalAttributeType) Registry.ENVIRONMENT_ATTRIBUTE.getOrThrow(Key.key(Key.MINECRAFT_NAMESPACE, key)); + } +} 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/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/Registry.java b/paper-api/src/main/java/org/bukkit/Registry.java index 0859653089ac..fa14a7257515 100644 --- a/paper-api/src/main/java/org/bukkit/Registry.java +++ b/paper-api/src/main/java/org/bukkit/Registry.java @@ -5,11 +5,13 @@ 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; 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; @@ -207,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. * @@ -355,6 +357,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/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-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/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-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java index 0a9f1e9a68f7..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; @@ -20,6 +22,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; @@ -34,21 +38,21 @@ 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; 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; 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; @@ -75,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; @@ -153,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( @@ -170,7 +174,9 @@ private static RegistryEntry inconsistentEntry(ResourceKey> DATA_DRIVEN = List.of( @@ -197,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/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..199883fed4f0 --- /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 +@@ -67,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 7435a9ebb62f..723142850c45 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; @@ -124,4 +126,9 @@ public GameRule legacyGameRuleBridge(GameRule r public Set validMannequinPoses() { return CraftMannequin.VALID_POSES; } + + @Override + public EnvironmentalAttributeContext.Builder environmentalAttributeContextBuilder() { + return new PaperEnvironmentalAttributeContext.PaperBuilder(); + } } 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/datacomponent/DataComponentAdapter.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/DataComponentAdapter.java deleted file mode 100644 index 15a96abb2ac7..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/DataComponentAdapter.java +++ /dev/null @@ -1,43 +0,0 @@ -package io.papermc.paper.datacomponent; - -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; - -public record DataComponentAdapter( - Function apiToVanilla, - Function vanillaToApi, - boolean codecValidation -) { - 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.codecValidation && !type.value().isTransient()) { - type.value().codecOrThrow().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/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..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 @@ -1,21 +1,223 @@ 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.item.MapPostProcessing; 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.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; +import java.util.function.Function; 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.ProvidesTrimMaterial; +import org.bukkit.DyeColor; +import org.bukkit.craftbukkit.CraftMusicInstrument; import org.bukkit.craftbukkit.CraftRegistry; +import org.bukkit.craftbukkit.damage.CraftDamageType; +import org.bukkit.craftbukkit.entity.CraftChicken; +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; -public abstract class PaperDataComponentType extends HolderableBase> implements DataComponentType { +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; - static { - DataComponentAdapters.bootstrap(); +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 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., PaperTypedDataCollector>>create( + BuiltInRegistries.DATA_COMPONENT_TYPE, + 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, + DataComponents.DAMAGE, + DataComponents.POTION_DURATION_SCALE, + DataComponents.MINIMUM_ATTACK_CHARGE, + DataComponents.REPAIR_COST, + DataComponents.ENCHANTMENT_GLINT_OVERRIDE + ); + 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)); + 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)); + 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, net.minecraft.world.item.component.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 + 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, 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, 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, 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); + } + ); + public static net.minecraft.core.component.DataComponentType bukkitToMinecraft(final DataComponentType type) { return CraftRegistry.bukkitToMinecraft(type); } @@ -38,14 +240,14 @@ public static Set minecraftToBukkit(final Set adapter; + private final Converter converter; - private PaperDataComponentType(final Holder> holder, final DataComponentAdapter adapter) { + private PaperDataComponentType(final Holder> holder, final Converter converter) { super(holder); - this.adapter = adapter; + this.converter = converter; } @Override @@ -53,52 +255,50 @@ public boolean isPersistent() { return !this.getHandle().isTransient(); } - public DataComponentAdapter getAdapter() { - return this.adapter; + public Converter getConverter() { + return this.converter; } - @SuppressWarnings({"unchecked"}) - public static DataComponentType of(final Holder holder) { - final DataComponentAdapter adapter = (DataComponentAdapter) DataComponentAdapters.ADAPTERS.get(holder.unwrapKey().orElseThrow()); - if (adapter == null) { - throw new IllegalArgumentException("No adapter found for " + holder); - } - if (adapter.isUnimplemented()) { - return new Unimplemented<>((Holder>) holder, adapter); - } else if (adapter.isValued()) { - return new ValuedImpl<>((Holder>) holder, adapter); + @SuppressWarnings("unchecked") + 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<>(reference, converter); + } else if (converter == Converters.unvalued()) { + return new NonValuedImpl<>(reference, converter); } else { - return new NonValuedImpl<>((Holder>) holder, adapter); + return new ValuedImpl<>(reference, converter); } } - public static final class NonValuedImpl extends PaperDataComponentType implements NonValued { + public static final class NonValuedImpl extends PaperDataComponentType implements NonValued { NonValuedImpl( - final Holder> holder, - final DataComponentAdapter 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 DataComponentAdapter 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 DataComponentAdapter 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/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/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 121babcfdda5..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; @@ -25,6 +27,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.EnvironmentalAttributeTypes; +import io.papermc.paper.world.attribute.PaperEnvironmentalAttributeType; import java.util.Collections; import java.util.IdentityHashMap; import java.util.List; @@ -121,6 +125,8 @@ 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(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(), @@ -145,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/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..6d8f9c3ac0b7 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataAdapters.java @@ -0,0 +1,36 @@ +package io.papermc.paper.registry.typed; + +import io.papermc.paper.util.converter.Converter; +import io.papermc.paper.util.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 { + + private final Map, Converter> converters; + + private PaperTypedDataAdapters(final Map, Converter> converters) { + this.converters = converters; + } + + public static > PaperTypedDataAdapters create( + final Registry registry, + final TypedDataCollector.Factory collectorFactory, + final Consumer consumer + ) { + final Map, Converter> converters = new IdentityHashMap<>(); + final C collector = collectorFactory.create(registry, converters); + + consumer.accept(collector); + + return new PaperTypedDataAdapters<>(converters); + } + + @SuppressWarnings("unchecked") + 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 new file mode 100644 index 000000000000..67f5866dc094 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/PaperTypedDataCollector.java @@ -0,0 +1,109 @@ +package io.papermc.paper.registry.typed; + +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.Registry; +import net.minecraft.resources.ResourceKey; + +public class PaperTypedDataCollector implements TypedDataCollector { + + private final Registry registry; + private final Map, Converter> converters; + + public PaperTypedDataCollector( + 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 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)); + } + } + }; + } + + @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)); + } + }; + } + + 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 new file mode 100644 index 000000000000..561f5fb43904 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/TypedDataCollector.java @@ -0,0 +1,56 @@ +package io.papermc.paper.registry.typed; + +import io.papermc.paper.util.converter.Converter; +import java.lang.reflect.Field; +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 interface TypedDataCollector { + + 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); + } + + void register(ResourceKey type, Function vanillaToApi, Function apiToVanilla); + + void register(T type, Converter converter); + + default void register(final Holder.Reference type, final Converter converter) { + this.register(type.key(), converter); + } + + void register(ResourceKey type, Converter converter); + + Dispatcher dispatch(Function> converter); + + ClassDispatcher dispatchClass(Function> converter); + + interface Factory> { + + C create(Registry registry, Map, Converter> adapters); + } + + interface Dispatcher { + + void add(Iterable types); + + void add(T type, T... types); + } + + interface ClassDispatcher { + + 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/package-info.java b/paper-server/src/main/java/io/papermc/paper/registry/typed/package-info.java new file mode 100644 index 000000000000..c1a24cf2d68d --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/typed/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.papermc.paper.registry.typed; + +import org.jspecify.annotations.NullMarked; 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/util/converter/CodecConverter.java b/paper-server/src/main/java/io/papermc/paper/util/converter/CodecConverter.java new file mode 100644 index 000000000000..f6fc4f539017 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/util/converter/CodecConverter.java @@ -0,0 +1,33 @@ +package io.papermc.paper.util.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/util/converter/Converter.java b/paper-server/src/main/java/io/papermc/paper/util/converter/Converter.java new file mode 100644 index 000000000000..15d1b2a2f068 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/util/converter/Converter.java @@ -0,0 +1,83 @@ +package io.papermc.paper.util.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 org.jspecify.annotations.Nullable; + +import static io.papermc.paper.util.MCUtil.transformUnmodifiable; + +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 @Nullable Encoder serializer) { + final Converter i = identity(); + if (serializer == null) { + return i; + } + return i.serializable(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( + list -> transformUnmodifiable(list, this::fromVanilla), + list -> transformUnmodifiable(list, 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/util/converter/Converters.java b/paper-server/src/main/java/io/papermc/paper/util/converter/Converters.java new file mode 100644 index 000000000000..d915673026dd --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/util/converter/Converters.java @@ -0,0 +1,97 @@ +package io.papermc.paper.util.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 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; + +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); + } + + 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"); + }, $ -> { + 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/util/converter/package-info.java b/paper-server/src/main/java/io/papermc/paper/util/converter/package-info.java new file mode 100644 index 000000000000..107361ad57aa --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/util/converter/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +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 new file mode 100644 index 000000000000..442136e9a38c --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttribute.java @@ -0,0 +1,56 @@ +package io.papermc.paper.world.attribute; + +import io.papermc.paper.math.Position; +import io.papermc.paper.util.MCUtil; +import io.papermc.paper.util.converter.Converter; +import net.minecraft.core.BlockPos; +import net.minecraft.world.attribute.EnvironmentAttributeSystem; + +public class PaperEnvironmentalAttribute implements EnvironmentalAttribute { + + private final EnvironmentAttributeSystem attributeSystem; + private final PaperEnvironmentalAttributeType type; + private final Converter converter; + + public PaperEnvironmentalAttribute(final EnvironmentAttributeSystem attributeSystem, final PaperEnvironmentalAttributeType type) { + this.attributeSystem = attributeSystem; + this.type = type; + this.converter = type.getConverter(); + } + + @Override + public A getGlobal() { + return this.converter.fromVanilla(this.attributeSystem.getDimensionValue(this.type.getHandle())); + } + + @Override + public A getPositioned(final Position position) { + return this.converter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), MCUtil.toVec3(position))); + } + + public A getPositioned(final BlockPos pos) { + return this.converter.fromVanilla(this.attributeSystem.getValue(this.type.getHandle(), pos)); + } + + @Override + 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(); + } + + 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); + 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.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/PaperEnvironmentalAttributeContext.java b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeContext.java new file mode 100644 index 000000000000..19c86f455539 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeContext.java @@ -0,0 +1,80 @@ +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.jspecify.annotations.Nullable; + +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 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(final @Nullable Long time) { + this.time = time; + return this; + } + + @Override + public Builder position(final @Nullable Position position) { + this.position = position; + return this; + } + + @Override + public Builder rainLevel(final @Nullable 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(final @Nullable 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 new file mode 100644 index 000000000000..34a76774be55 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/world/attribute/PaperEnvironmentalAttributeType.java @@ -0,0 +1,130 @@ +package io.papermc.paper.world.attribute; + +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.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; +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; + +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., PaperTypedDataCollector>>create( + BuiltInRegistries.ENVIRONMENT_ATTRIBUTE, + PaperTypedDataCollector::new, + collector -> { + 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 = sameOrder(io.papermc.paper.world.MoonPhase.class, MoonPhase.class); + + 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); + }); + + 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 Converter converter; + + private PaperEnvironmentalAttributeType(final Holder> holder, final Converter converter) { + super(holder); + this.converter = converter; + } + + @SuppressWarnings("unchecked") + public static EnvironmentalAttributeType of(final Holder holder) { + final Holder.Reference> reference = (Holder.Reference>) holder; + 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 + public A getDefaultValue() { + return this.getConverter().fromVanilla(this.getHandle().defaultValue()); + } + + public Converter getConverter() { + return this.converter; + } +} 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/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/CraftRegionAccessor.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java index 21d594a39d09..52393f9772f2 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,9 @@ 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) { + return new PaperEnvironmentalAttribute<>(this.getHandle().getLevel().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..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 @@ -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; @@ -746,4 +747,9 @@ public void randomTick() { this.getNMS().randomTick(level, this.position, level.random); } // Paper end + + @Override + 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/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/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java index 002682049fe8..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 @@ -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.util.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,8 +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, type.getHolder())); + 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 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..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,21 +4,28 @@ 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 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 +156,8 @@ 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); + 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) {