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/MemoryModuleTypeKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/MemoryModuleTypeKeys.java new file mode 100644 index 000000000000..fea66c843740 --- /dev/null +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/MemoryModuleTypeKeys.java @@ -0,0 +1,853 @@ +package io.papermc.paper.registry.keys; + +import static net.kyori.adventure.key.Key.key; + +import io.papermc.paper.annotation.GeneratedClass; +import io.papermc.paper.entity.ai.MemoryKey; +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#MEMORY_MODULE_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 MemoryModuleTypeKeys { + /** + * {@code minecraft:admiring_disabled} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ADMIRING_DISABLED = create(key("admiring_disabled")); + + /** + * {@code minecraft:admiring_item} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ADMIRING_ITEM = create(key("admiring_item")); + + /** + * {@code minecraft:angry_at} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ANGRY_AT = create(key("angry_at")); + + /** + * {@code minecraft:ate_recently} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ATE_RECENTLY = create(key("ate_recently")); + + /** + * {@code minecraft:attack_cooling_down} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ATTACK_COOLING_DOWN = create(key("attack_cooling_down")); + + /** + * {@code minecraft:attack_target} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ATTACK_TARGET = create(key("attack_target")); + + /** + * {@code minecraft:attack_target_cooldown} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ATTACK_TARGET_COOLDOWN = create(key("attack_target_cooldown")); + + /** + * {@code minecraft:avoid_target} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey AVOID_TARGET = create(key("avoid_target")); + + /** + * {@code minecraft:breed_target} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BREED_TARGET = create(key("breed_target")); + + /** + * {@code minecraft:breeze_jump_cooldown} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BREEZE_JUMP_COOLDOWN = create(key("breeze_jump_cooldown")); + + /** + * {@code minecraft:breeze_jump_inhaling} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BREEZE_JUMP_INHALING = create(key("breeze_jump_inhaling")); + + /** + * {@code minecraft:breeze_jump_target} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BREEZE_JUMP_TARGET = create(key("breeze_jump_target")); + + /** + * {@code minecraft:breeze_leaving_water} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BREEZE_LEAVING_WATER = create(key("breeze_leaving_water")); + + /** + * {@code minecraft:breeze_shoot} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BREEZE_SHOOT = create(key("breeze_shoot")); + + /** + * {@code minecraft:breeze_shoot_charging} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BREEZE_SHOOT_CHARGING = create(key("breeze_shoot_charging")); + + /** + * {@code minecraft:breeze_shoot_cooldown} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BREEZE_SHOOT_COOLDOWN = create(key("breeze_shoot_cooldown")); + + /** + * {@code minecraft:breeze_shoot_recover} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BREEZE_SHOOT_RECOVER = create(key("breeze_shoot_recover")); + + /** + * {@code minecraft:cant_reach_walk_target_since} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey CANT_REACH_WALK_TARGET_SINCE = create(key("cant_reach_walk_target_since")); + + /** + * {@code minecraft:celebrate_location} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey CELEBRATE_LOCATION = create(key("celebrate_location")); + + /** + * {@code minecraft:charge_cooldown_ticks} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey CHARGE_COOLDOWN_TICKS = create(key("charge_cooldown_ticks")); + + /** + * {@code minecraft:dancing} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DANCING = create(key("dancing")); + + /** + * {@code minecraft:danger_detected_recently} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DANGER_DETECTED_RECENTLY = create(key("danger_detected_recently")); + + /** + * {@code minecraft:dig_cooldown} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DIG_COOLDOWN = create(key("dig_cooldown")); + + /** + * {@code minecraft:disable_walk_to_admire_item} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DISABLE_WALK_TO_ADMIRE_ITEM = create(key("disable_walk_to_admire_item")); + + /** + * {@code minecraft:disturbance_location} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DISTURBANCE_LOCATION = create(key("disturbance_location")); + + /** + * {@code minecraft:doors_to_close} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DOORS_TO_CLOSE = create(key("doors_to_close")); + + /** + * {@code minecraft:dummy} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DUMMY = create(key("dummy")); + + /** + * {@code minecraft:gaze_cooldown_ticks} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey GAZE_COOLDOWN_TICKS = create(key("gaze_cooldown_ticks")); + + /** + * {@code minecraft:golem_detected_recently} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey GOLEM_DETECTED_RECENTLY = create(key("golem_detected_recently")); + + /** + * {@code minecraft:has_hunting_cooldown} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey HAS_HUNTING_COOLDOWN = create(key("has_hunting_cooldown")); + + /** + * {@code minecraft:heard_bell_time} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey HEARD_BELL_TIME = create(key("heard_bell_time")); + + /** + * {@code minecraft:hiding_place} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey HIDING_PLACE = create(key("hiding_place")); + + /** + * {@code minecraft:home} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey HOME = create(key("home")); + + /** + * {@code minecraft:hunted_recently} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey HUNTED_RECENTLY = create(key("hunted_recently")); + + /** + * {@code minecraft:hurt_by} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey HURT_BY = create(key("hurt_by")); + + /** + * {@code minecraft:hurt_by_entity} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey HURT_BY_ENTITY = create(key("hurt_by_entity")); + + /** + * {@code minecraft:interactable_doors} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey INTERACTABLE_DOORS = create(key("interactable_doors")); + + /** + * {@code minecraft:interaction_target} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey INTERACTION_TARGET = create(key("interaction_target")); + + /** + * {@code minecraft:is_emerging} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey IS_EMERGING = create(key("is_emerging")); + + /** + * {@code minecraft:is_in_water} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey IS_IN_WATER = create(key("is_in_water")); + + /** + * {@code minecraft:is_panicking} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey IS_PANICKING = create(key("is_panicking")); + + /** + * {@code minecraft:is_pregnant} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey IS_PREGNANT = create(key("is_pregnant")); + + /** + * {@code minecraft:is_sniffing} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey IS_SNIFFING = create(key("is_sniffing")); + + /** + * {@code minecraft:is_tempted} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey IS_TEMPTED = create(key("is_tempted")); + + /** + * {@code minecraft:item_pickup_cooldown_ticks} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ITEM_PICKUP_COOLDOWN_TICKS = create(key("item_pickup_cooldown_ticks")); + + /** + * {@code minecraft:job_site} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey JOB_SITE = create(key("job_site")); + + /** + * {@code minecraft:last_slept} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LAST_SLEPT = create(key("last_slept")); + + /** + * {@code minecraft:last_woken} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LAST_WOKEN = create(key("last_woken")); + + /** + * {@code minecraft:last_worked_at_poi} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LAST_WORKED_AT_POI = create(key("last_worked_at_poi")); + + /** + * {@code minecraft:liked_noteblock} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LIKED_NOTEBLOCK = create(key("liked_noteblock")); + + /** + * {@code minecraft:liked_noteblock_cooldown_ticks} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LIKED_NOTEBLOCK_COOLDOWN_TICKS = create(key("liked_noteblock_cooldown_ticks")); + + /** + * {@code minecraft:liked_player} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LIKED_PLAYER = create(key("liked_player")); + + /** + * {@code minecraft:long_jump_cooling_down} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LONG_JUMP_COOLING_DOWN = create(key("long_jump_cooling_down")); + + /** + * {@code minecraft:long_jump_mid_jump} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LONG_JUMP_MID_JUMP = create(key("long_jump_mid_jump")); + + /** + * {@code minecraft:look_target} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LOOK_TARGET = create(key("look_target")); + + /** + * {@code minecraft:meeting_point} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey MEETING_POINT = create(key("meeting_point")); + + /** + * {@code minecraft:mobs} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey MOBS = create(key("mobs")); + + /** + * {@code minecraft:nearby_adult_piglins} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEARBY_ADULT_PIGLINS = create(key("nearby_adult_piglins")); + + /** + * {@code minecraft:nearest_attackable} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_ATTACKABLE = create(key("nearest_attackable")); + + /** + * {@code minecraft:nearest_bed} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_BED = create(key("nearest_bed")); + + /** + * {@code minecraft:nearest_hostile} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_HOSTILE = create(key("nearest_hostile")); + + /** + * {@code minecraft:nearest_player_holding_wanted_item} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_PLAYER_HOLDING_WANTED_ITEM = create(key("nearest_player_holding_wanted_item")); + + /** + * {@code minecraft:nearest_players} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_PLAYERS = create(key("nearest_players")); + + /** + * {@code minecraft:nearest_repellent} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_REPELLENT = create(key("nearest_repellent")); + + /** + * {@code minecraft:nearest_targetable_player_not_wearing_gold} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_TARGETABLE_PLAYER_NOT_WEARING_GOLD = create(key("nearest_targetable_player_not_wearing_gold")); + + /** + * {@code minecraft:nearest_visible_adult} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_VISIBLE_ADULT = create(key("nearest_visible_adult")); + + /** + * {@code minecraft:nearest_visible_adult_hoglins} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_VISIBLE_ADULT_HOGLINS = create(key("nearest_visible_adult_hoglins")); + + /** + * {@code minecraft:nearest_visible_adult_piglin} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_VISIBLE_ADULT_PIGLIN = create(key("nearest_visible_adult_piglin")); + + /** + * {@code minecraft:nearest_visible_adult_piglins} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_VISIBLE_ADULT_PIGLINS = create(key("nearest_visible_adult_piglins")); + + /** + * {@code minecraft:nearest_visible_baby_hoglin} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_VISIBLE_BABY_HOGLIN = create(key("nearest_visible_baby_hoglin")); + + /** + * {@code minecraft:nearest_visible_huntable_hoglin} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_VISIBLE_HUNTABLE_HOGLIN = create(key("nearest_visible_huntable_hoglin")); + + /** + * {@code minecraft:nearest_visible_nemesis} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_VISIBLE_NEMESIS = create(key("nearest_visible_nemesis")); + + /** + * {@code minecraft:nearest_visible_player} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_VISIBLE_PLAYER = create(key("nearest_visible_player")); + + /** + * {@code minecraft:nearest_visible_targetable_player} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_VISIBLE_TARGETABLE_PLAYER = create(key("nearest_visible_targetable_player")); + + /** + * {@code minecraft:nearest_visible_targetable_players} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_VISIBLE_TARGETABLE_PLAYERS = create(key("nearest_visible_targetable_players")); + + /** + * {@code minecraft:nearest_visible_wanted_item} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_VISIBLE_WANTED_ITEM = create(key("nearest_visible_wanted_item")); + + /** + * {@code minecraft:nearest_visible_zombified} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NEAREST_VISIBLE_ZOMBIFIED = create(key("nearest_visible_zombified")); + + /** + * {@code minecraft:pacified} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey PACIFIED = create(key("pacified")); + + /** + * {@code minecraft:path} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey PATH = create(key("path")); + + /** + * {@code minecraft:play_dead_ticks} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey PLAY_DEAD_TICKS = create(key("play_dead_ticks")); + + /** + * {@code minecraft:potential_job_site} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey POTENTIAL_JOB_SITE = create(key("potential_job_site")); + + /** + * {@code minecraft:ram_cooldown_ticks} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey RAM_COOLDOWN_TICKS = create(key("ram_cooldown_ticks")); + + /** + * {@code minecraft:ram_target} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey RAM_TARGET = create(key("ram_target")); + + /** + * {@code minecraft:recent_projectile} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey RECENT_PROJECTILE = create(key("recent_projectile")); + + /** + * {@code minecraft:ride_target} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey RIDE_TARGET = create(key("ride_target")); + + /** + * {@code minecraft:roar_sound_cooldown} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ROAR_SOUND_COOLDOWN = create(key("roar_sound_cooldown")); + + /** + * {@code minecraft:roar_sound_delay} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ROAR_SOUND_DELAY = create(key("roar_sound_delay")); + + /** + * {@code minecraft:roar_target} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ROAR_TARGET = create(key("roar_target")); + + /** + * {@code minecraft:secondary_job_site} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SECONDARY_JOB_SITE = create(key("secondary_job_site")); + + /** + * {@code minecraft:sniff_cooldown} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SNIFF_COOLDOWN = create(key("sniff_cooldown")); + + /** + * {@code minecraft:sniffer_digging} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SNIFFER_DIGGING = create(key("sniffer_digging")); + + /** + * {@code minecraft:sniffer_explored_positions} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SNIFFER_EXPLORED_POSITIONS = create(key("sniffer_explored_positions")); + + /** + * {@code minecraft:sniffer_happy} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SNIFFER_HAPPY = create(key("sniffer_happy")); + + /** + * {@code minecraft:sniffer_sniffing_target} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SNIFFER_SNIFFING_TARGET = create(key("sniffer_sniffing_target")); + + /** + * {@code minecraft:sonic_boom_cooldown} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SONIC_BOOM_COOLDOWN = create(key("sonic_boom_cooldown")); + + /** + * {@code minecraft:sonic_boom_sound_cooldown} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SONIC_BOOM_SOUND_COOLDOWN = create(key("sonic_boom_sound_cooldown")); + + /** + * {@code minecraft:sonic_boom_sound_delay} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SONIC_BOOM_SOUND_DELAY = create(key("sonic_boom_sound_delay")); + + /** + * {@code minecraft:spear_charge_position} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SPEAR_CHARGE_POSITION = create(key("spear_charge_position")); + + /** + * {@code minecraft:spear_engage_time} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SPEAR_ENGAGE_TIME = create(key("spear_engage_time")); + + /** + * {@code minecraft:spear_fleeing_position} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SPEAR_FLEEING_POSITION = create(key("spear_fleeing_position")); + + /** + * {@code minecraft:spear_fleeing_time} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SPEAR_FLEEING_TIME = create(key("spear_fleeing_time")); + + /** + * {@code minecraft:spear_status} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SPEAR_STATUS = create(key("spear_status")); + + /** + * {@code minecraft:temptation_cooldown_ticks} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey TEMPTATION_COOLDOWN_TICKS = create(key("temptation_cooldown_ticks")); + + /** + * {@code minecraft:tempting_player} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey TEMPTING_PLAYER = create(key("tempting_player")); + + /** + * {@code minecraft:time_trying_to_reach_admire_item} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey TIME_TRYING_TO_REACH_ADMIRE_ITEM = create(key("time_trying_to_reach_admire_item")); + + /** + * {@code minecraft:touch_cooldown} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey TOUCH_COOLDOWN = create(key("touch_cooldown")); + + /** + * {@code minecraft:transport_items_cooldown_ticks} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey TRANSPORT_ITEMS_COOLDOWN_TICKS = create(key("transport_items_cooldown_ticks")); + + /** + * {@code minecraft:universal_anger} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey UNIVERSAL_ANGER = create(key("universal_anger")); + + /** + * {@code minecraft:unreachable_tongue_targets} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey UNREACHABLE_TONGUE_TARGETS = create(key("unreachable_tongue_targets")); + + /** + * {@code minecraft:unreachable_transport_block_positions} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey UNREACHABLE_TRANSPORT_BLOCK_POSITIONS = create(key("unreachable_transport_block_positions")); + + /** + * {@code minecraft:vibration_cooldown} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey VIBRATION_COOLDOWN = create(key("vibration_cooldown")); + + /** + * {@code minecraft:visible_adult_hoglin_count} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey VISIBLE_ADULT_HOGLIN_COUNT = create(key("visible_adult_hoglin_count")); + + /** + * {@code minecraft:visible_adult_piglin_count} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey VISIBLE_ADULT_PIGLIN_COUNT = create(key("visible_adult_piglin_count")); + + /** + * {@code minecraft:visible_mobs} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey VISIBLE_MOBS = create(key("visible_mobs")); + + /** + * {@code minecraft:visible_villager_babies} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey VISIBLE_VILLAGER_BABIES = create(key("visible_villager_babies")); + + /** + * {@code minecraft:visited_block_positions} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey VISITED_BLOCK_POSITIONS = create(key("visited_block_positions")); + + /** + * {@code minecraft:walk_target} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey WALK_TARGET = create(key("walk_target")); + + private MemoryModuleTypeKeys() { + } + + private static TypedKey create(final Key key) { + return TypedKey.create(RegistryKey.MEMORY_MODULE_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/entity/ai/MemoryKey.java b/paper-api/src/main/java/io/papermc/paper/entity/ai/MemoryKey.java new file mode 100644 index 000000000000..2aaea8a13266 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/entity/ai/MemoryKey.java @@ -0,0 +1,18 @@ +package io.papermc.paper.entity.ai; + +import org.bukkit.Keyed; +import org.jetbrains.annotations.ApiStatus; + +public interface MemoryKey extends Keyed { // todo migrate on top of existing api? + + @SuppressWarnings("unused") + @ApiStatus.NonExtendable + interface Valued extends MemoryKey { + + } + + @ApiStatus.NonExtendable + interface NonValued extends MemoryKey { + + } +} diff --git a/paper-api/src/main/java/io/papermc/paper/entity/ai/MemoryKeys.java b/paper-api/src/main/java/io/papermc/paper/entity/ai/MemoryKeys.java new file mode 100644 index 000000000000..07206b817d7b --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/entity/ai/MemoryKeys.java @@ -0,0 +1,161 @@ +package io.papermc.paper.entity.ai; + +import com.destroystokyo.paper.entity.Pathfinder; +import io.papermc.paper.math.BlockPosition; +import io.papermc.paper.math.Position; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.key.KeyPattern; +import org.bukkit.Location; +import org.bukkit.Registry; +import org.bukkit.damage.DamageSource; +import org.bukkit.entity.Ageable; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Hoglin; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Item; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Mob; +import org.bukkit.entity.PiglinAbstract; + +public final class MemoryKeys { + + public static final MemoryKey.Valued HOME = valued("home"); + public static final MemoryKey.Valued JOB_SITE = valued("job_site"); + public static final MemoryKey.Valued POTENTIAL_JOB_SITE = valued("potential_job_site"); + public static final MemoryKey.Valued MEETING_POINT = valued("meeting_point"); + public static final MemoryKey.Valued> SECONDARY_JOB_SITE = valued("secondary_job_site"); + public static final MemoryKey.Valued> NEAREST_LIVING_ENTITIES = valued("mobs"); + //public static final MemoryKey.Valued NEAREST_VISIBLE_LIVING_ENTITIES = valued("visible_mobs"); + public static final MemoryKey.Valued> VISIBLE_VILLAGER_BABIES = valued("visible_villager_babies"); + public static final MemoryKey.Valued> NEAREST_PLAYERS = valued("nearest_players"); + public static final MemoryKey.Valued NEAREST_VISIBLE_PLAYER = valued("nearest_visible_player"); + public static final MemoryKey.Valued NEAREST_VISIBLE_ATTACKABLE_PLAYER = valued("nearest_visible_targetable_player"); + public static final MemoryKey.Valued> NEAREST_VISIBLE_ATTACKABLE_PLAYERS = valued("nearest_visible_targetable_players"); + //public static final MemoryKey.Valued WALK_TARGET = valued("walk_target"); + //public static final MemoryKey.Valued LOOK_TARGET = valued("look_target"); + public static final MemoryKey.Valued ATTACK_TARGET = valued("attack_target"); + public static final MemoryKey.Valued ATTACK_COOLING_DOWN = valued("attack_cooling_down"); + public static final MemoryKey.Valued INTERACTION_TARGET = valued("interaction_target"); + public static final MemoryKey.Valued BREED_TARGET = valued("breed_target"); + public static final MemoryKey.Valued RIDE_TARGET = valued("ride_target"); + public static final MemoryKey.Valued PATH = valued("path"); + public static final MemoryKey.Valued> INTERACTABLE_DOORS = valued("interactable_doors"); + public static final MemoryKey.Valued> DOORS_TO_CLOSE = valued("doors_to_close"); + public static final MemoryKey.Valued NEAREST_BED = valued("nearest_bed"); + public static final MemoryKey.Valued HURT_BY = valued("hurt_by"); + public static final MemoryKey.Valued HURT_BY_ENTITY = valued("hurt_by_entity"); + public static final MemoryKey.Valued AVOID_TARGET = valued("avoid_target"); + public static final MemoryKey.Valued NEAREST_HOSTILE = valued("nearest_hostile"); + public static final MemoryKey.Valued NEAREST_ATTACKABLE = valued("nearest_attackable"); + public static final MemoryKey.Valued HIDING_PLACE = valued("hiding_place"); + public static final MemoryKey.Valued HEARD_BELL_TIME = valued("heard_bell_time"); + public static final MemoryKey.Valued CANT_REACH_WALK_TARGET_SINCE = valued("cant_reach_walk_target_since"); + public static final MemoryKey.Valued GOLEM_DETECTED_RECENTLY = valued("golem_detected_recently"); + public static final MemoryKey.Valued DANGER_DETECTED_RECENTLY = valued("danger_detected_recently"); + public static final MemoryKey.Valued LAST_SLEPT = valued("last_slept"); + public static final MemoryKey.Valued LAST_WOKEN = valued("last_woken"); + public static final MemoryKey.Valued LAST_WORKED_AT_POI = valued("last_worked_at_poi"); + public static final MemoryKey.Valued NEAREST_VISIBLE_ADULT = valued("nearest_visible_adult"); + public static final MemoryKey.Valued NEAREST_VISIBLE_WANTED_ITEM = valued("nearest_visible_wanted_item"); + public static final MemoryKey.Valued NEAREST_VISIBLE_NEMESIS = valued("nearest_visible_nemesis"); + public static final MemoryKey.Valued PLAY_DEAD_TICKS = valued("play_dead_ticks"); + public static final MemoryKey.Valued TEMPTING_PLAYER = valued("tempting_player"); + public static final MemoryKey.Valued TEMPTATION_COOLDOWN_TICKS = valued("temptation_cooldown_ticks"); + public static final MemoryKey.Valued GAZE_COOLDOWN_TICKS = valued("gaze_cooldown_ticks"); + public static final MemoryKey.Valued IS_TEMPTED = valued("is_tempted"); + public static final MemoryKey.Valued LONG_JUMP_COOLDOWN_TICKS = valued("long_jump_cooling_down"); + public static final MemoryKey.Valued LONG_JUMP_MID_JUMP = valued("long_jump_mid_jump"); + public static final MemoryKey.Valued HAS_HUNTING_COOLDOWN = valued("has_hunting_cooldown"); + public static final MemoryKey.Valued RAM_COOLDOWN_TICKS = valued("ram_cooldown_ticks"); + public static final MemoryKey.Valued RAM_TARGET = valued("ram_target"); + public static final MemoryKey.NonValued IS_IN_WATER = unvalued("is_in_water"); + public static final MemoryKey.NonValued IS_PREGNANT = unvalued("is_pregnant"); + public static final MemoryKey.Valued IS_PANICKING = valued("is_panicking"); + public static final MemoryKey.Valued> UNREACHABLE_TONGUE_TARGETS = valued("unreachable_tongue_targets"); + public static final MemoryKey.Valued> VISITED_BLOCK_POSITIONS = valued("visited_block_positions"); + public static final MemoryKey.Valued> UNREACHABLE_TRANSPORT_BLOCK_POSITIONS = valued("unreachable_transport_block_positions"); + public static final MemoryKey.Valued TRANSPORT_ITEMS_COOLDOWN_TICKS = valued("transport_items_cooldown_ticks"); + public static final MemoryKey.Valued CHARGE_COOLDOWN_TICKS = valued("charge_cooldown_ticks"); + public static final MemoryKey.Valued ATTACK_TARGET_COOLDOWN = valued("attack_target_cooldown"); + public static final MemoryKey.Valued SPEAR_FLEEING_TIME = valued("spear_fleeing_time"); + public static final MemoryKey.Valued SPEAR_FLEEING_POSITION = valued("spear_fleeing_position"); + public static final MemoryKey.Valued SPEAR_CHARGE_POSITION = valued("spear_charge_position"); + public static final MemoryKey.Valued SPEAR_ENGAGE_TIME = valued("spear_engage_time"); + //public static final MemoryKey.Valued SPEAR_STATUS = valued("spear_status"); + public static final MemoryKey.Valued ANGRY_AT = valued("angry_at"); + public static final MemoryKey.Valued UNIVERSAL_ANGER = valued("universal_anger"); + public static final MemoryKey.Valued ADMIRING_ITEM = valued("admiring_item"); + public static final MemoryKey.Valued TIME_TRYING_TO_REACH_ADMIRE_ITEM = valued("time_trying_to_reach_admire_item"); + public static final MemoryKey.Valued DISABLE_WALK_TO_ADMIRE_ITEM = valued("disable_walk_to_admire_item"); + public static final MemoryKey.Valued ADMIRING_DISABLED = valued("admiring_disabled"); + public static final MemoryKey.Valued HUNTED_RECENTLY = valued("hunted_recently"); + public static final MemoryKey.Valued CELEBRATE_LOCATION = valued("celebrate_location"); + public static final MemoryKey.Valued DANCING = valued("dancing"); + public static final MemoryKey.Valued NEAREST_VISIBLE_HUNTABLE_HOGLIN = valued("nearest_visible_huntable_hoglin"); + public static final MemoryKey.Valued NEAREST_VISIBLE_BABY_HOGLIN = valued("nearest_visible_baby_hoglin"); + public static final MemoryKey.Valued NEAREST_TARGETABLE_PLAYER_NOT_WEARING_GOLD = valued("nearest_targetable_player_not_wearing_gold"); + public static final MemoryKey.Valued> NEARBY_ADULT_PIGLINS = valued("nearby_adult_piglins"); + public static final MemoryKey.Valued> NEAREST_VISIBLE_ADULT_PIGLINS = valued("nearest_visible_adult_piglins"); + public static final MemoryKey.Valued> NEAREST_VISIBLE_ADULT_HOGLINS = valued("nearest_visible_adult_hoglins"); + public static final MemoryKey.Valued NEAREST_VISIBLE_ADULT_PIGLIN = valued("nearest_visible_adult_piglin"); + public static final MemoryKey.Valued NEAREST_VISIBLE_ZOMBIFIED = valued("nearest_visible_zombified"); + public static final MemoryKey.Valued VISIBLE_ADULT_PIGLIN_COUNT = valued("visible_adult_piglin_count"); + public static final MemoryKey.Valued VISIBLE_ADULT_HOGLIN_COUNT = valued("visible_adult_hoglin_count"); + public static final MemoryKey.Valued NEAREST_PLAYER_HOLDING_WANTED_ITEM = valued("nearest_player_holding_wanted_item"); + public static final MemoryKey.Valued ATE_RECENTLY = valued("ate_recently"); + public static final MemoryKey.Valued NEAREST_REPELLENT = valued("nearest_repellent"); + public static final MemoryKey.Valued PACIFIED = valued("pacified"); + public static final MemoryKey.Valued ROAR_TARGET = valued("roar_target"); + public static final MemoryKey.Valued DISTURBANCE_LOCATION = valued("disturbance_location"); + public static final MemoryKey.NonValued RECENT_PROJECTILE = unvalued("recent_projectile"); + public static final MemoryKey.NonValued IS_SNIFFING = unvalued("is_sniffing"); + public static final MemoryKey.NonValued IS_EMERGING = unvalued("is_emerging"); + public static final MemoryKey.NonValued ROAR_SOUND_DELAY = unvalued("roar_sound_delay"); + public static final MemoryKey.NonValued DIG_COOLDOWN = unvalued("dig_cooldown"); + public static final MemoryKey.NonValued ROAR_SOUND_COOLDOWN = unvalued("roar_sound_cooldown"); + public static final MemoryKey.NonValued SNIFF_COOLDOWN = unvalued("sniff_cooldown"); + public static final MemoryKey.NonValued TOUCH_COOLDOWN = unvalued("touch_cooldown"); + public static final MemoryKey.NonValued VIBRATION_COOLDOWN = unvalued("vibration_cooldown"); + public static final MemoryKey.NonValued SONIC_BOOM_COOLDOWN = unvalued("sonic_boom_cooldown"); + public static final MemoryKey.NonValued SONIC_BOOM_SOUND_COOLDOWN = unvalued("sonic_boom_sound_cooldown"); + public static final MemoryKey.NonValued SONIC_BOOM_SOUND_DELAY = unvalued("sonic_boom_sound_delay"); + public static final MemoryKey.Valued LIKED_PLAYER = valued("liked_player"); + public static final MemoryKey.Valued LIKED_NOTEBLOCK_POSITION = valued("liked_noteblock"); + public static final MemoryKey.Valued LIKED_NOTEBLOCK_COOLDOWN_TICKS = valued("liked_noteblock_cooldown_ticks"); + public static final MemoryKey.Valued ITEM_PICKUP_COOLDOWN_TICKS = valued("item_pickup_cooldown_ticks"); + public static final MemoryKey.Valued> SNIFFER_EXPLORED_POSITIONS = valued("sniffer_explored_positions"); + public static final MemoryKey.Valued SNIFFER_SNIFFING_TARGET = valued("sniffer_sniffing_target"); + public static final MemoryKey.Valued SNIFFER_DIGGING = valued("sniffer_digging"); + public static final MemoryKey.Valued SNIFFER_HAPPY = valued("sniffer_happy"); + public static final MemoryKey.NonValued BREEZE_JUMP_COOLDOWN = unvalued("breeze_jump_cooldown"); + public static final MemoryKey.NonValued BREEZE_SHOOT = unvalued("breeze_shoot"); + public static final MemoryKey.NonValued BREEZE_SHOOT_CHARGING = unvalued("breeze_shoot_charging"); + public static final MemoryKey.NonValued BREEZE_SHOOT_RECOVERING = unvalued("breeze_shoot_recover"); + public static final MemoryKey.NonValued BREEZE_SHOOT_COOLDOWN = unvalued("breeze_shoot_cooldown"); + public static final MemoryKey.NonValued BREEZE_JUMP_INHALING = unvalued("breeze_jump_inhaling"); + public static final MemoryKey.Valued BREEZE_JUMP_TARGET = valued("breeze_jump_target"); + public static final MemoryKey.NonValued BREEZE_LEAVING_WATER = unvalued("breeze_leaving_water"); + + private static MemoryKey.NonValued unvalued(final @KeyPattern.Value String name) { + final MemoryKey memoryKey = Registry.MEMORY_KEY.getOrThrow(Key.key(Key.MINECRAFT_NAMESPACE, name)); + if (memoryKey instanceof MemoryKey.NonValued) { + return (MemoryKey.NonValued) memoryKey; + } + throw new IllegalStateException(name + " is not a valid unvalued type, it is a " + memoryKey.getClass().getTypeName()); + } + + @SuppressWarnings("unchecked") + private static MemoryKey.Valued valued(final @KeyPattern.Value String name) { + final MemoryKey memoryKey = Registry.MEMORY_KEY.getOrThrow(Key.key(Key.MINECRAFT_NAMESPACE, name)); + if (memoryKey instanceof MemoryKey.Valued) { + return (MemoryKey.Valued) memoryKey; + } + throw new IllegalStateException(name + " is not a valid valued type, it is a " + memoryKey.getClass().getTypeName()); + } + + private MemoryKeys() { + } +} 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/registry/RegistryKey.java b/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java index dcee3d88f5b7..97f991f2fd93 100644 --- a/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java +++ b/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java @@ -3,6 +3,7 @@ import io.papermc.paper.datacomponent.DataComponentType; import io.papermc.paper.dialog.Dialog; import io.papermc.paper.registry.tag.TagKey; +import io.papermc.paper.world.attribute.EnvironmentalAttributeType; import net.kyori.adventure.key.Key; import net.kyori.adventure.key.KeyPattern; import net.kyori.adventure.key.Keyed; @@ -29,7 +30,6 @@ import org.bukkit.entity.Villager; import org.bukkit.entity.Wolf; import org.bukkit.entity.ZombieNautilus; -import org.bukkit.entity.memory.MemoryKey; import org.bukkit.generator.structure.Structure; import org.bukkit.generator.structure.StructureType; import org.bukkit.inventory.ItemType; @@ -39,6 +39,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 +133,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 memory keys. + * @see io.papermc.paper.registry.keys.MemoryModuleTypeKeys + */ + RegistryKey MEMORY_MODULE_TYPE = create("memory_module_type"); /* ********************** * * Data-driven Registries * @@ -239,7 +251,6 @@ public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { RegistryKey ENTITY_TYPE = create("entity_type"); RegistryKey PARTICLE_TYPE = create("particle_type"); RegistryKey POTION = create("potion"); - RegistryKey> MEMORY_MODULE_TYPE = create("memory_module_type"); /** * Constructs a new {@link TypedKey} for this registry given the typed key's key. 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..0ec3ebaf187f 100644 --- a/paper-api/src/main/java/org/bukkit/Registry.java +++ b/paper-api/src/main/java/org/bukkit/Registry.java @@ -10,6 +10,7 @@ import io.papermc.paper.registry.TypedKey; import io.papermc.paper.registry.tag.Tag; import io.papermc.paper.registry.tag.TagKey; +import io.papermc.paper.world.attribute.EnvironmentalAttributeType; import java.util.Collection; import java.util.Iterator; import java.util.Locale; @@ -290,7 +291,9 @@ public Iterator iterator() { * Memory Keys. * * @see MemoryKey + * @deprecated use {@link #MEMORY_KEY} */ + @Deprecated(since = "1.21.11", forRemoval = true) Registry> MEMORY_MODULE_TYPE = new NotARegistry<>() { @Override @@ -355,7 +358,19 @@ 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); + /** + * Memory Keys. + * + * @see io.papermc.paper.entity.ai.MemoryKey + */ + Registry MEMORY_KEY = registryFor(RegistryKey.MEMORY_MODULE_TYPE); // /** * @apiNote use {@link #MOB_EFFECT} instead 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/LivingEntity.java b/paper-api/src/main/java/org/bukkit/entity/LivingEntity.java index 19a48dce7c2f..c2d8040d00e2 100644 --- a/paper-api/src/main/java/org/bukkit/entity/LivingEntity.java +++ b/paper-api/src/main/java/org/bukkit/entity/LivingEntity.java @@ -1,17 +1,15 @@ package org.bukkit.entity; +import io.papermc.paper.world.damagesource.CombatTracker; import java.util.Collection; import java.util.List; import java.util.Set; import java.util.UUID; -import io.papermc.paper.world.damagesource.CombatTracker; -import io.papermc.paper.world.damagesource.FallLocationType; import net.kyori.adventure.key.Key; import org.bukkit.Color; import org.bukkit.FluidCollisionMode; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.NamespacedKey; import org.bukkit.Sound; import org.bukkit.World; import org.bukkit.attribute.Attributable; @@ -30,6 +28,7 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Unmodifiable; /** * Represents a living entity, such as a monster or player @@ -994,6 +993,99 @@ default boolean addPotionEffect(@NotNull PotionEffect effect) { */ void setMemory(@NotNull MemoryKey memoryKey, @Nullable T memoryValue); + /** + * Gets a collection of all the memories this entity can get. + *

+ * If a {@link io.papermc.paper.entity.ai.MemoryKey} is not in this + * collection, the setters will have no effect. + * + * @return an unmodifiable collection of the memories + */ + @Unmodifiable @NotNull Collection getAvailableMemories(); + + /** + * Checks the existence of the memory specified. + * + * @param memoryKey memory to access + * @return the existence status + */ + boolean hasMemory(@NotNull io.papermc.paper.entity.ai.MemoryKey memoryKey); + + /** + * Returns the value of the memory specified. + *

+ * Note that the value is null when the specific entity does not have that + * value by default. + *

+ * Any collection that is returned will be immutable. + * + * @param memoryKey memory to access + * @param the type of the return value + * @return the value or null if not present + */ + @Nullable T getMemory(@NotNull io.papermc.paper.entity.ai.MemoryKey.Valued memoryKey); + + /** + * Gets the remaining time of the associated memory. + * + * @param memoryKey memory to access + * @return the time remaining (in ticks) + */ + long getTimeRemaining(@NotNull io.papermc.paper.entity.ai.MemoryKey memoryKey); + + /** + * Sets the value of the memory specified. + *

+ * Note that the value will not be persisted when the specific entity does + * not have that value by default. + * + * @param memoryKey the memory to access + */ + void setMemory(@NotNull io.papermc.paper.entity.ai.MemoryKey.NonValued memoryKey); + + /** + * Sets the value of the memory specified. + *

+ * Note that the value will not be persisted when the specific entity does + * not have that value by default. + * + * @param memoryKey the memory to access + * @param expirationTime the expiration time: ttl (in ticks) + */ + void setMemory(@NotNull io.papermc.paper.entity.ai.MemoryKey.NonValued memoryKey, long expirationTime); + + /** + * Sets the value of the memory specified. + *

+ * Note that the value will not be persisted when the specific entity does + * not have that value by default. + * + * @param memoryKey the memory to access + * @param value a typed memory value + * @param the type of the passed value + */ + void setMemory(@NotNull io.papermc.paper.entity.ai.MemoryKey.Valued memoryKey, @NotNull T value); + + /** + * Sets the value of the memory specified. + *

+ * Note that the value will not be persisted when the specific entity does + * not have that value by default. + * + * @param memoryKey the memory to access + * @param value a typed memory value + * @param expirationTime the expiration time: ttl (in ticks) + * @param the type of the passed value + */ + void setMemory(@NotNull io.papermc.paper.entity.ai.MemoryKey.Valued memoryKey, @NotNull T value, long expirationTime); + + /** + * Removes the memory specified from the entity's brain. + * + * @param memoryKey the memory to access + */ + void forgetMemory(@NotNull io.papermc.paper.entity.ai.MemoryKey memoryKey); + /** * Get the {@link Sound} this entity will make when damaged. * 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..47117ebbc6e3 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.entity.ai.MemoryKey; +import io.papermc.paper.entity.ai.MemoryKeys; 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; @@ -39,16 +43,17 @@ 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; @@ -92,7 +97,6 @@ import org.bukkit.entity.Villager; import org.bukkit.entity.Wolf; import org.bukkit.entity.ZombieNautilus; -import org.bukkit.entity.memory.MemoryKey; import org.bukkit.generator.structure.Structure; import org.bukkit.generator.structure.StructureType; import org.bukkit.inventory.ItemType; @@ -153,7 +157,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 +175,9 @@ private static RegistryEntry inconsistentEntry(ResourceKey> DATA_DRIVEN = List.of( @@ -198,8 +205,7 @@ 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) + entry(Registries.POTION, Potions.class, PotionType.class) ); public static final Map>, RegistryEntry> BY_REGISTRY_KEY; 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/entity/ai/Brain.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/Brain.java.patch new file mode 100644 index 000000000000..9b17241bc07c --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/Brain.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/ai/Brain.java ++++ b/net/minecraft/world/entity/ai/Brain.java +@@ -208,7 +_,7 @@ + + public long getTimeUntilExpiry(MemoryModuleType memoryType) { + Optional> optional = this.memories.get(memoryType); +- return optional.map(ExpirableValue::getTimeToLive).orElse(0L); ++ return optional == null ? 0L : optional.map(ExpirableValue::getTimeToLive).orElse(0L); // Paper + } + + @Deprecated 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/com/destroystokyo/paper/entity/PaperPathfinder.java b/paper-server/src/main/java/com/destroystokyo/paper/entity/PaperPathfinder.java index 25779c87106a..7776c6d15c08 100644 --- a/paper-server/src/main/java/com/destroystokyo/paper/entity/PaperPathfinder.java +++ b/paper-server/src/main/java/com/destroystokyo/paper/entity/PaperPathfinder.java @@ -8,6 +8,7 @@ import net.minecraft.world.level.pathfinder.Node; import net.minecraft.world.level.pathfinder.Path; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.craftbukkit.entity.CraftLivingEntity; import org.bukkit.craftbukkit.util.CraftLocation; import org.bukkit.entity.LivingEntity; @@ -44,7 +45,7 @@ public boolean hasPath() { @Override public PathResult getCurrentPath() { Path path = this.entity.getNavigation().getPath(); - return path != null && !path.isDone() ? new PaperPathResult(path) : null; + return path != null && !path.isDone() ? new PaperPathResult(path, this.entity.level().getWorld()) : null; } @Nullable @@ -52,7 +53,7 @@ public PathResult getCurrentPath() { public PathResult findPath(Location loc) { Preconditions.checkArgument(loc != null, "Location can not be null"); Path path = this.entity.getNavigation().createPath(loc.getX(), loc.getY(), loc.getZ(), 0); - return path != null ? new PaperPathResult(path) : null; + return path != null ? new PaperPathResult(path, this.entity.level().getWorld()) : null; } @Nullable @@ -60,7 +61,7 @@ public PathResult findPath(Location loc) { public PathResult findPath(LivingEntity target) { Preconditions.checkArgument(target != null, "Target can not be null"); Path path = this.entity.getNavigation().createPath(((CraftLivingEntity) target).getHandle(), 0); - return path != null ? new PaperPathResult(path) : null; + return path != null ? new PaperPathResult(path, this.entity.level().getWorld()) : null; } @Override @@ -100,19 +101,27 @@ public void setCanFloat(boolean canFloat) { this.entity.getNavigation().pathFinder.nodeEvaluator.setCanFloat(canFloat); } - public class PaperPathResult implements com.destroystokyo.paper.entity.PaperPathfinder.PathResult { + public static class PaperPathResult implements com.destroystokyo.paper.entity.PaperPathfinder.PathResult { private final Path path; + @Nullable + private final World world; - PaperPathResult(Path path) { + // todo remove world and migrate Location to Position, in some context like memory key the world is not available + public PaperPathResult(Path path, @Nullable World world) { this.path = path; + this.world = world; + } + + public Path getHandle() { + return this.path; } @Nullable @Override public Location getFinalPoint() { Node point = this.path.getEndNode(); - return point != null ? CraftLocation.toBukkit(point, PaperPathfinder.this.entity.level()) : null; + return point != null ? CraftLocation.toBukkit(point, this.world) : null; } @Override @@ -124,7 +133,7 @@ public boolean canReachFinalPoint() { public List getPoints() { List points = new ArrayList<>(); for (Node point : this.path.nodes) { - points.add(CraftLocation.toBukkit(point, PaperPathfinder.this.entity.level())); + points.add(CraftLocation.toBukkit(point, this.world)); } return points; } @@ -140,7 +149,7 @@ public Location getNextPoint() { if (this.path.isDone()) { return null; } - return CraftLocation.toBukkit(this.path.nodes.get(this.path.getNextNodeIndex()), PaperPathfinder.this.entity.level()); + return CraftLocation.toBukkit(this.path.nodes.get(this.path.getNextNodeIndex()), this.world); } } } 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/entity/ai/PaperMemoryKey.java b/paper-server/src/main/java/io/papermc/paper/entity/ai/PaperMemoryKey.java new file mode 100644 index 000000000000..1460f9a58531 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/entity/ai/PaperMemoryKey.java @@ -0,0 +1,211 @@ +package io.papermc.paper.entity.ai; + +import com.destroystokyo.paper.entity.PaperPathfinder; +import com.google.common.primitives.Primitives; +import io.leangen.geantyref.GenericTypeReflector; +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.MCUtil; +import io.papermc.paper.util.converter.Converter; +import io.papermc.paper.util.converter.Converters; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import net.minecraft.core.BlockPos; +import net.minecraft.core.GlobalPos; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.util.Unit; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.AgeableMob; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.memory.MemoryModuleType; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.monster.hoglin.Hoglin; +import net.minecraft.world.entity.monster.piglin.AbstractPiglin; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.pathfinder.Path; +import net.minecraft.world.phys.Vec3; +import org.bukkit.craftbukkit.CraftRegistry; +import org.bukkit.craftbukkit.damage.CraftDamageSource; +import org.bukkit.craftbukkit.entity.CraftAgeable; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftHoglin; +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.entity.CraftItem; +import org.bukkit.craftbukkit.entity.CraftLivingEntity; +import org.bukkit.craftbukkit.entity.CraftMob; +import org.bukkit.craftbukkit.entity.CraftPiglinAbstract; +import org.bukkit.craftbukkit.util.CraftLocation; + +import static io.papermc.paper.util.converter.Converter.direct; +import static io.papermc.paper.util.converter.Converters.entity; +import static io.papermc.paper.util.converter.Converters.wrapper; + +public class PaperMemoryKey extends HolderableBase> implements MemoryKey { + + @SuppressWarnings("RedundantTypeArguments") + private static final PaperTypedDataAdapters> ADAPTERS = PaperTypedDataAdapters., PaperTypedDataCollector>>create( + BuiltInRegistries.MEMORY_MODULE_TYPE, + PaperTypedDataCollector::new, + collector -> { + final ClassValue> converters = new ClassValue<>() { + @Override + protected Converter computeValue(final Class type) { + if (Primitives.isWrapperType(type) || type == UUID.class) { + return Converter.identity(); + } + if (type == Unit.class) { + return Converters.unvalued(); + } + if (type == GlobalPos.class) { + return direct(CraftLocation::fromGlobalPos, CraftLocation::toGlobalPos); + } + if (type == Entity.class) { + return entity(Entity.class, CraftEntity.class); + } + if (type == LivingEntity.class) { + return entity(LivingEntity.class, CraftLivingEntity.class); + } + if (type == Mob.class) { + return entity(Mob.class, CraftMob.class); + } + if (type == AgeableMob.class) { + return entity(AgeableMob.class, CraftAgeable.class); + } + if (type == ItemEntity.class) { + return entity(ItemEntity.class, CraftItem.class); + } + if (type == Hoglin.class) { + return entity(Hoglin.class, CraftHoglin.class); + } + if (type == AbstractPiglin.class) { + return entity(AbstractPiglin.class, CraftPiglinAbstract.class); + } + if (type == Player.class) { + return entity(Player.class, CraftHumanEntity.class); + } + if (type == Path.class) { + return direct( + path -> new PaperPathfinder.PaperPathResult(path, null), + PaperPathfinder.PaperPathResult::getHandle + ); + } + if (type == BlockPos.class) { + return direct(MCUtil::toPosition, MCUtil::toBlockPos); + } + if (type == DamageSource.class) { + return wrapper(CraftDamageSource::new); + } + if (type == Vec3.class) { + return direct(MCUtil::toPosition, MCUtil::toVec3); + } + return null; + } + }; + + collector.dispatchClass(valueType -> { + final Class valueClass = GenericTypeReflector.erase(valueType); + if (valueType instanceof ParameterizedType paramType) { + Converter elementConverter = converters.get((Class) paramType.getActualTypeArguments()[0]); + if (elementConverter == null) { + return Converters.unimplemented(); + } + if (List.class.isAssignableFrom(valueClass)) { + return elementConverter.list(); + } + if (Set.class.isAssignableFrom(valueClass)) { + return elementConverter.set(); + } + if (Collection.class.isAssignableFrom(valueClass)) { + return elementConverter.collection(); + } + } + + return Objects.requireNonNullElseGet(converters.get(valueClass), Converters::unimplemented); + }).scanConstants(MemoryModuleType.class, field -> (MemoryModuleType) field.get(null), (type, field) -> { + if (field.getGenericType() instanceof ParameterizedType paramType) { + Type[] args = paramType.getActualTypeArguments(); + if (args.length == 1) { + return args[0]; + } + } + return null; + }); + //collector.register(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, fromApi, toApi); + //collector.register(MemoryModuleType.WALK_TARGET, fromApi, toApi); + //collector.register(MemoryModuleType.LOOK_TARGET, fromApi, toApi); + //collector.register(MemoryModuleType.SPEAR_STATUS, fromApi, toApi); + } + ); + + private final Converter converter; + + private PaperMemoryKey(final Holder> holder, final Converter converter) { + super(holder); + this.converter = converter; + } + + public Converter getConverter() { + return this.converter; + } + + @SuppressWarnings("unchecked") + public static MemoryKey of(final Holder holder) { + final Holder.Reference> reference = (Holder.Reference>) holder; + final Converter converter = PaperMemoryKey.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 ValuedImpl<>(reference, converter); + } + } + + public static final class NonValuedImpl extends PaperMemoryKey implements MemoryKey.NonValued { + + NonValuedImpl( + final Holder> holder, + final Converter converter + ) { + super(holder, converter); + } + } + + public static final class ValuedImpl extends PaperMemoryKey implements MemoryKey.Valued { + + ValuedImpl( + final Holder> holder, + final Converter converter + ) { + super(holder, converter); + } + } + + public static final class Unimplemented extends PaperMemoryKey { + + public Unimplemented( + final Holder> holder, + final Converter converter + ) { + super(holder, converter); + } + } + + public static MemoryKey minecraftToBukkit(MemoryModuleType minecraft) { + return CraftRegistry.minecraftToBukkit(minecraft, Registries.MEMORY_MODULE_TYPE); + } + + public static MemoryModuleType bukkitToMinecraft(MemoryKey bukkit) { + return CraftRegistry.bukkitToMinecraft(bukkit); + } +} 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..02b74d3b7d6f 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.entity.ai.MemoryKeys; +import io.papermc.paper.entity.ai.PaperMemoryKey; 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.MEMORY_MODULE_TYPE, RegistryKey.MEMORY_MODULE_TYPE).craft(MemoryKeys.class, PaperMemoryKey::of).build(), // data-driven start(Registries.BIOME, RegistryKey.BIOME).craft(Biome.class, CraftBiome::new).build().delayed(), @@ -146,8 +152,7 @@ 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) + start(Registries.POTION, RegistryKey.POTION).apiOnly(PaperSimpleRegistry::potion) // End generate - RegistryDefinitions ); final Map, RegistryEntry> byRegistryKey = new IdentityHashMap<>(REGISTRY_ENTRIES.size()); 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/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/damage/CraftDamageSource.java b/paper-server/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSource.java index 3bec2e656f2e..3867844990c7 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSource.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/damage/CraftDamageSource.java @@ -7,11 +7,12 @@ import org.bukkit.World; import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.util.CraftLocation; +import org.bukkit.craftbukkit.util.Handleable; import org.bukkit.damage.DamageSource; import org.bukkit.damage.DamageType; import org.bukkit.entity.Entity; -public class CraftDamageSource implements DamageSource { +public class CraftDamageSource implements DamageSource, Handleable { private final net.minecraft.world.damagesource.DamageSource damageSource; private final DamageType damageType; @@ -21,6 +22,7 @@ public CraftDamageSource(net.minecraft.world.damagesource.DamageSource damageSou this.damageType = CraftDamageType.minecraftHolderToBukkit(damageSource.typeHolder()); } + @Override public net.minecraft.world.damagesource.DamageSource getHandle() { return this.damageSource; } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java index b0987314d263..4d0cc327e8c7 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java @@ -2,18 +2,22 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Sets; +import io.papermc.paper.adventure.PaperAdventure; +import io.papermc.paper.entity.ai.MemoryKeys; +import io.papermc.paper.entity.ai.PaperMemoryKey; +import io.papermc.paper.util.MCUtil; +import io.papermc.paper.world.damagesource.CombatTracker; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.OptionalLong; import java.util.Set; import java.util.UUID; -import io.papermc.paper.adventure.PaperAdventure; import net.kyori.adventure.key.Key; import net.minecraft.Optionull; -import io.papermc.paper.world.damagesource.CombatTracker; import net.minecraft.core.component.DataComponents; import net.minecraft.network.protocol.game.ClientboundHurtAnimationPacket; import net.minecraft.resources.ResourceKey; @@ -32,12 +36,12 @@ import net.minecraft.world.entity.decoration.Mannequin; import net.minecraft.world.entity.projectile.FireworkRocketEntity; import net.minecraft.world.entity.projectile.FishingHook; -import net.minecraft.world.entity.projectile.hurtingprojectile.LargeFireball; import net.minecraft.world.entity.projectile.ThrowableProjectile; +import net.minecraft.world.entity.projectile.arrow.ThrownTrident; +import net.minecraft.world.entity.projectile.hurtingprojectile.LargeFireball; import net.minecraft.world.entity.projectile.throwableitemprojectile.ThrownEgg; import net.minecraft.world.entity.projectile.throwableitemprojectile.ThrownEnderpearl; import net.minecraft.world.entity.projectile.throwableitemprojectile.ThrownExperienceBottle; -import net.minecraft.world.entity.projectile.arrow.ThrownTrident; import net.minecraft.world.item.Items; import net.minecraft.world.item.component.Consumable; import net.minecraft.world.phys.Vec3; @@ -98,6 +102,7 @@ import org.bukkit.util.BlockIterator; import org.bukkit.util.RayTraceResult; import org.bukkit.util.Vector; +import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.NonNull; public class CraftLivingEntity extends CraftEntity implements LivingEntity { @@ -864,6 +869,64 @@ public void setMemory(MemoryKey memoryKey, T t) { this.getHandle().getBrain().setMemory(CraftMemoryKey.bukkitToMinecraft(memoryKey), CraftMemoryMapper.toNms(t)); } + @Override + public @Unmodifiable Collection getAvailableMemories() { + return MCUtil.transformUnmodifiable(this.getHandle().getBrain().getMemories().keySet(), PaperMemoryKey::minecraftToBukkit); + } + + @Override + public boolean hasMemory(final io.papermc.paper.entity.ai.MemoryKey memoryKey) { + return this.getHandle().getBrain().hasMemoryValue(PaperMemoryKey.bukkitToMinecraft(memoryKey)); + } + + @Override + public T getMemory(final io.papermc.paper.entity.ai.MemoryKey.Valued memoryKey) { + return this.getMemory0((PaperMemoryKey.ValuedImpl) memoryKey); + } + + @Override + public long getTimeRemaining(final io.papermc.paper.entity.ai.MemoryKey memoryKey) { + return this.getHandle().getBrain().getTimeUntilExpiry(PaperMemoryKey.bukkitToMinecraft(memoryKey)); + } + + public API getMemory0(io.papermc.paper.entity.ai.PaperMemoryKey.ValuedImpl memoryKey) { + final Optional memory = this.getHandle().getBrain().getMemoryInternal(memoryKey.getHandle()); + return memory != null ? memory.map(a -> memoryKey.getConverter().fromVanilla(a)).orElse(null) : null; + } + + @Override + public void setMemory(final io.papermc.paper.entity.ai.MemoryKey.NonValued memoryKey) { + this.setMemory0((PaperMemoryKey) memoryKey, null, OptionalLong.empty()); + } + + @Override + public void setMemory(final io.papermc.paper.entity.ai.MemoryKey.NonValued memoryKey, final long expirationTime) { + this.setMemory0((PaperMemoryKey) memoryKey, null, OptionalLong.of(expirationTime)); + } + + @Override + public void setMemory(final io.papermc.paper.entity.ai.MemoryKey.Valued memoryKey, final T value) { + this.setMemory0((PaperMemoryKey.ValuedImpl) memoryKey, value, OptionalLong.empty()); + } + + @Override + public void setMemory(final io.papermc.paper.entity.ai.MemoryKey.Valued memoryKey, final T value, final long expirationTime) { + this.setMemory0((PaperMemoryKey.ValuedImpl) memoryKey, value, OptionalLong.of(expirationTime)); + } + + public void setMemory0(PaperMemoryKey memoryKey, API value, final OptionalLong expirationTime) { + if (expirationTime.isPresent()) { + this.getHandle().getBrain().setMemoryWithExpiry(memoryKey.getHandle(), memoryKey.getConverter().toVanilla(value), expirationTime.getAsLong()); + } else { + this.getHandle().getBrain().setMemory(memoryKey.getHandle(), memoryKey.getConverter().toVanilla(value)); + } + } + + @Override + public void forgetMemory(io.papermc.paper.entity.ai.MemoryKey memoryKey) { + this.getHandle().getBrain().eraseMemory(PaperMemoryKey.bukkitToMinecraft(memoryKey)); + } + @Override public Sound getHurtSound() { SoundEvent sound = this.getHandle().getHurtSound(this.getHandle().damageSources().generic()); 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/main/java/org/bukkit/craftbukkit/util/CraftLocation.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftLocation.java index 644e7019c4c4..091dde7929b4 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftLocation.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftLocation.java @@ -53,8 +53,8 @@ public static Location toBukkit(Vec3i pos, Level level, float yaw, float pitch) return toBukkit(pos, level.getWorld(), yaw, pitch); } - public static Location toBukkit(Node point, Level level) { - return new Location(level.getWorld(), point.x, point.y, point.z); + public static Location toBukkit(Node point, World world) { + return new Location(world, point.x, point.y, point.z); } public static BlockPos toBlockPosition(Location loc) { 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..1fb7c5f5c7c8 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,8 @@ import net.minecraft.core.registries.Registries; import net.minecraft.resources.Identifier; import net.minecraft.resources.ResourceKey; +import net.minecraft.world.attribute.EnvironmentAttributes; +import net.minecraft.world.entity.ai.memory.MemoryModuleType; import org.bukkit.Keyed; import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.support.RegistryHelper; @@ -58,6 +60,22 @@ 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 + )); + ignore(Registries.MEMORY_MODULE_TYPE, Set.of( + MemoryModuleType.DUMMY, // no use case + MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, + MemoryModuleType.WALK_TARGET, + MemoryModuleType.LOOK_TARGET, + MemoryModuleType.SPEAR_STATUS + )); } 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..861c45675b5f 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,29 @@ import io.papermc.paper.datacomponent.DataComponentTypes; import io.papermc.paper.dialog.Dialog; import io.papermc.paper.dialog.PaperDialog; +import io.papermc.paper.entity.ai.MemoryKey; +import io.papermc.paper.entity.ai.MemoryKeys; +import io.papermc.paper.entity.ai.PaperMemoryKey; 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.ai.memory.MemoryModuleType; 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 +157,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.MEMORY_MODULE_TYPE, MemoryKey.class, MemoryKeys.class, PaperMemoryKey.class, MemoryModuleType.class); } private static void register(ResourceKey> registryKey, Class api, Class impl, Class internal) {