remove paper-api dependency

Remove the needs to compile paper-api while running rewriters.
Allow to rewrite test source set for implementation (rewriteImplTest).
Some other changes:
- item type generics is now supported
- generate CraftItemMetas#getItemMetaData
- registry test data are now generated to generalize registry handling
- generate Pose and Attribute (trial)
- print removed fields from Tag while updating the game
This commit is contained in:
Lulu13022002
2025-03-31 22:41:01 +02:00
parent b4466ec981
commit 61d6ec4973
146 changed files with 5244 additions and 2381 deletions

View File

@@ -23,7 +23,7 @@ import org.jspecify.annotations.NullMarked;
"SpellCheckingInspection"
})
@NullMarked
@GeneratedFrom("1.21.7-rc2")
@GeneratedFrom("1.21.7")
public final class DialogKeys {
/**
* {@code minecraft:custom_options}

View File

@@ -7,7 +7,6 @@ import io.papermc.paper.generated.GeneratedFrom;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.tag.TagKey;
import net.kyori.adventure.key.Key;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
/**
@@ -24,8 +23,7 @@ import org.jspecify.annotations.NullMarked;
"SpellCheckingInspection"
})
@NullMarked
@GeneratedFrom("1.21.7-rc2")
@ApiStatus.Experimental
@GeneratedFrom("1.21.7")
public final class DialogTagKeys {
/**
* {@code #minecraft:pause_screen_additions}
@@ -50,7 +48,6 @@ public final class DialogTagKeys {
* @param key the tag key's key
* @return a new tag key
*/
@ApiStatus.Experimental
public static TagKey<Dialog> create(final Key key) {
return TagKey.create(RegistryKey.DIALOG, key);
}

View File

@@ -0,0 +1,133 @@
Dump of the rewriters that apply to the file: io/papermc/paper/block/property/BlockProperties.java
Configuration:
Indent unit: " " (4 char)
Indent char: ' ' (U+0020)
Name: BlockProperties
Start comment marker: Start generate - BlockProperties
End comment marker: End generate - BlockProperties
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
public static final BooleanBlockProperty ATTACHED = bool("attached");
public static final BooleanBlockProperty BERRIES = bool("berries");
public static final BooleanBlockProperty BLOOM = bool("bloom");
public static final BooleanBlockProperty BOTTOM = bool("bottom");
public static final BooleanBlockProperty CAN_SUMMON = bool("can_summon");
public static final BooleanBlockProperty CHISELED_BOOKSHELF_SLOT_0_OCCUPIED = bool("slot_0_occupied");
public static final BooleanBlockProperty CHISELED_BOOKSHELF_SLOT_1_OCCUPIED = bool("slot_1_occupied");
public static final BooleanBlockProperty CHISELED_BOOKSHELF_SLOT_2_OCCUPIED = bool("slot_2_occupied");
public static final BooleanBlockProperty CHISELED_BOOKSHELF_SLOT_3_OCCUPIED = bool("slot_3_occupied");
public static final BooleanBlockProperty CHISELED_BOOKSHELF_SLOT_4_OCCUPIED = bool("slot_4_occupied");
public static final BooleanBlockProperty CHISELED_BOOKSHELF_SLOT_5_OCCUPIED = bool("slot_5_occupied");
public static final BooleanBlockProperty CONDITIONAL = bool("conditional");
public static final BooleanBlockProperty CRACKED = bool("cracked");
public static final BooleanBlockProperty CRAFTING = bool("crafting");
public static final BooleanBlockProperty DISARMED = bool("disarmed");
public static final BooleanBlockProperty DOWN = bool("down");
public static final BooleanBlockProperty DRAG = bool("drag");
public static final BooleanBlockProperty EAST = bool("east");
public static final BooleanBlockProperty ENABLED = bool("enabled");
public static final BooleanBlockProperty EXTENDED = bool("extended");
public static final BooleanBlockProperty EYE = bool("eye");
public static final BooleanBlockProperty FALLING = bool("falling");
public static final BooleanBlockProperty HANGING = bool("hanging");
public static final BooleanBlockProperty HAS_BOOK = bool("has_book");
public static final BooleanBlockProperty HAS_BOTTLE_0 = bool("has_bottle_0");
public static final BooleanBlockProperty HAS_BOTTLE_1 = bool("has_bottle_1");
public static final BooleanBlockProperty HAS_BOTTLE_2 = bool("has_bottle_2");
public static final BooleanBlockProperty HAS_RECORD = bool("has_record");
public static final BooleanBlockProperty INVERTED = bool("inverted");
public static final BooleanBlockProperty IN_WALL = bool("in_wall");
public static final BooleanBlockProperty LIT = bool("lit");
public static final BooleanBlockProperty LOCKED = bool("locked");
public static final BooleanBlockProperty MAP = bool("map");
public static final BooleanBlockProperty NATURAL = bool("natural");
public static final BooleanBlockProperty NORTH = bool("north");
public static final BooleanBlockProperty OCCUPIED = bool("occupied");
public static final BooleanBlockProperty OMINOUS = bool("ominous");
public static final BooleanBlockProperty OPEN = bool("open");
public static final BooleanBlockProperty PERSISTENT = bool("persistent");
public static final BooleanBlockProperty POWERED = bool("powered");
public static final BooleanBlockProperty SHORT = bool("short");
public static final BooleanBlockProperty SHRIEKING = bool("shrieking");
public static final BooleanBlockProperty SIGNAL_FIRE = bool("signal_fire");
public static final BooleanBlockProperty SNOWY = bool("snowy");
public static final BooleanBlockProperty SOUTH = bool("south");
public static final BooleanBlockProperty TIP = bool("tip");
public static final BooleanBlockProperty TRIGGERED = bool("triggered");
public static final BooleanBlockProperty UNSTABLE = bool("unstable");
public static final BooleanBlockProperty UP = bool("up");
public static final BooleanBlockProperty WATERLOGGED = bool("waterlogged");
public static final BooleanBlockProperty WEST = bool("west");
public static final EnumBlockProperty<org.bukkit.block.data.FaceAttachable.AttachedFace> ATTACH_FACE = enumeration("face", FaceAttachable.AttachedFace.class);
public static final EnumBlockProperty<org.bukkit.Axis> AXIS = enumeration("axis", Axis.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.Bamboo.Leaves> BAMBOO_LEAVES = enumeration("leaves", Bamboo.Leaves.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.Bed.Part> BED_PART = enumeration("part", Bed.Part.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.Bell.Attachment> BELL_ATTACHMENT = enumeration("attachment", Bell.Attachment.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.Chest.Type> CHEST_TYPE = enumeration("type", Chest.Type.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.CreakingHeart.State> CREAKING_HEART_STATE = enumeration("creaking_heart_state", CreakingHeart.State.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.Door.Hinge> DOOR_HINGE = enumeration("hinge", Door.Hinge.class);
public static final EnumBlockProperty<org.bukkit.block.data.Bisected.Half> DOUBLE_BLOCK_HALF = enumeration("half", Bisected.Half.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.PointedDripstone.Thickness> DRIPSTONE_THICKNESS = enumeration("thickness", PointedDripstone.Thickness.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.RedstoneWire.Connection> EAST_REDSTONE = enumeration("east", RedstoneWire.Connection.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.Wall.Height> EAST_WALL = enumeration("east", Wall.Height.class);
public static final EnumBlockProperty<org.bukkit.block.BlockFace> FACING = enumeration("facing", BlockFace.class, org.bukkit.block.BlockFace::isCartesian);
public static final EnumBlockProperty<org.bukkit.block.BlockFace> FACING_HOPPER = enumeration("facing", BlockFace.class, ((Predicate<org.bukkit.block.BlockFace>) org.bukkit.block.BlockFace::isCartesian).and(face -> face != org.bukkit.block.BlockFace.UP));
public static final EnumBlockProperty<org.bukkit.block.data.Bisected.Half> HALF = enumeration("half", Bisected.Half.class);
public static final EnumBlockProperty<org.bukkit.Axis> HORIZONTAL_AXIS = enumeration("axis", Axis.class, org.bukkit.Axis::isHorizontal);
public static final EnumBlockProperty<org.bukkit.block.BlockFace> HORIZONTAL_FACING = enumeration("facing", BlockFace.class, org.bukkit.block.BlockFace::isCardinal);
public static final EnumBlockProperty<org.bukkit.block.data.type.Comparator.Mode> MODE_COMPARATOR = enumeration("mode", Comparator.Mode.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.RedstoneWire.Connection> NORTH_REDSTONE = enumeration("north", RedstoneWire.Connection.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.Wall.Height> NORTH_WALL = enumeration("north", Wall.Height.class);
public static final EnumBlockProperty<org.bukkit.Instrument> NOTEBLOCK_INSTRUMENT = enumeration("instrument", Instrument.class);
public static final EnumBlockProperty<org.bukkit.block.Orientation> ORIENTATION = enumeration("orientation", Orientation.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.TechnicalPiston.Type> PISTON_TYPE = enumeration("type", TechnicalPiston.Type.class);
public static final EnumBlockProperty<org.bukkit.block.data.Rail.Shape> RAIL_SHAPE = enumeration("shape", Rail.Shape.class);
public static final EnumBlockProperty<org.bukkit.block.data.Rail.Shape> RAIL_SHAPE_STRAIGHT = enumeration("shape", Rail.Shape.class, org.bukkit.block.data.Rail.Shape::isStraight);
public static final EnumBlockProperty<org.bukkit.block.data.type.SculkSensor.Phase> SCULK_SENSOR_PHASE = enumeration("sculk_sensor_phase", SculkSensor.Phase.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.Slab.Type> SLAB_TYPE = enumeration("type", Slab.Type.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.RedstoneWire.Connection> SOUTH_REDSTONE = enumeration("south", RedstoneWire.Connection.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.Wall.Height> SOUTH_WALL = enumeration("south", Wall.Height.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.Stairs.Shape> STAIRS_SHAPE = enumeration("shape", Stairs.Shape.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.StructureBlock.Mode> STRUCTUREBLOCK_MODE = enumeration("mode", StructureBlock.Mode.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.TestBlock.Mode> TEST_BLOCK_MODE = enumeration("mode", TestBlock.Mode.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.BigDripleaf.Tilt> TILT = enumeration("tilt", BigDripleaf.Tilt.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.TrialSpawner.State> TRIAL_SPAWNER_STATE = enumeration("trial_spawner_state", TrialSpawner.State.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.Vault.State> VAULT_STATE = enumeration("vault_state", Vault.State.class);
public static final EnumBlockProperty<org.bukkit.block.BlockFace> VERTICAL_DIRECTION = enumeration("vertical_direction", BlockFace.class, face -> face.getModY() != 0);
public static final EnumBlockProperty<org.bukkit.block.data.type.RedstoneWire.Connection> WEST_REDSTONE = enumeration("west", RedstoneWire.Connection.class);
public static final EnumBlockProperty<org.bukkit.block.data.type.Wall.Height> WEST_WALL = enumeration("west", Wall.Height.class);
public static final IntegerBlockProperty AGE_1 = integer("age", 0, 1);
public static final IntegerBlockProperty AGE_15 = integer("age", 0, 15);
public static final IntegerBlockProperty AGE_2 = integer("age", 0, 2);
public static final IntegerBlockProperty AGE_25 = integer("age", 0, 25);
public static final IntegerBlockProperty AGE_3 = integer("age", 0, 3);
public static final IntegerBlockProperty AGE_4 = integer("age", 0, 4);
public static final IntegerBlockProperty AGE_5 = integer("age", 0, 5);
public static final IntegerBlockProperty AGE_7 = integer("age", 0, 7);
public static final IntegerBlockProperty BITES = integer("bites", 0, 6);
public static final IntegerBlockProperty CANDLES = integer("candles", 1, 4);
public static final IntegerBlockProperty DELAY = integer("delay", 1, 4);
public static final IntegerBlockProperty DISTANCE = integer("distance", 1, 7);
public static final IntegerBlockProperty DRIED_GHAST_HYDRATION_LEVELS = integer("hydration", 0, 3);
public static final IntegerBlockProperty DUSTED = integer("dusted", 0, 3);
public static final IntegerBlockProperty EGGS = integer("eggs", 1, 4);
public static final IntegerBlockProperty FLOWER_AMOUNT = integer("flower_amount", 1, 4);
public static final IntegerBlockProperty HATCH = integer("hatch", 0, 2);
public static final IntegerBlockProperty LAYERS = integer("layers", 1, 8);
public static final IntegerBlockProperty LEVEL = integer("level", 0, 15);
public static final IntegerBlockProperty LEVEL_CAULDRON = integer("level", 1, 3);
public static final IntegerBlockProperty LEVEL_COMPOSTER = integer("level", 0, 8);
public static final IntegerBlockProperty LEVEL_FLOWING = integer("level", 1, 8);
public static final IntegerBlockProperty LEVEL_HONEY = integer("honey_level", 0, 5);
public static final IntegerBlockProperty MOISTURE = integer("moisture", 0, 7);
public static final BlockProperty<org.bukkit.Note> NOTE = register(new NoteBlockProperty("note"));
public static final IntegerBlockProperty PICKLES = integer("pickles", 1, 4);
public static final IntegerBlockProperty POWER = integer("power", 0, 15);
public static final IntegerBlockProperty RESPAWN_ANCHOR_CHARGES = integer("charges", 0, 4);
public static final EnumBlockProperty<org.bukkit.block.BlockFace> ROTATION_16 = register(new RotationBlockProperty("rotation"));
public static final IntegerBlockProperty SEGMENT_AMOUNT = integer("segment_amount", 1, 4);
public static final IntegerBlockProperty STABILITY_DISTANCE = integer("distance", 0, 7);
public static final IntegerBlockProperty STAGE = integer("stage", 0, 1);
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

View File

@@ -32,7 +32,7 @@ public interface Dialog extends Keyed, DialogLike {
}
// Start generate - Dialog
// @GeneratedFrom 1.21.7-rc2
// @GeneratedFrom 1.21.7
Dialog CUSTOM_OPTIONS = getDialog("custom_options");
Dialog QUICK_ACTIONS = getDialog("quick_actions");

View File

@@ -89,7 +89,6 @@ import org.bukkit.block.data.type.MangrovePropagule;
import org.bukkit.block.data.type.MossyCarpet;
import org.bukkit.block.data.type.NoteBlock;
import org.bukkit.block.data.type.Observer;
import org.bukkit.block.data.type.PinkPetals;
import org.bukkit.block.data.type.Piston;
import org.bukkit.block.data.type.PistonHead;
import org.bukkit.block.data.type.PitcherCrop;

View File

@@ -19,10 +19,14 @@ import org.jetbrains.annotations.NotNull;
*/
public interface Tag<T extends Keyed> extends Keyed {
String REGISTRY_BLOCKS = "blocks";
String REGISTRY_ITEMS = "items";
String REGISTRY_FLUIDS = "fluids";
String REGISTRY_ENTITY_TYPES = "entity_types";
String REGISTRY_GAME_EVENTS = "game_events";
// Start generate - Tag
// @GeneratedFrom 1.21.7
String REGISTRY_BLOCKS = "blocks";
Tag<Material> ACACIA_LOGS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("acacia_logs"), Material.class);
Tag<Material> AIR = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("air"), Material.class);
@@ -411,8 +415,6 @@ public interface Tag<T extends Keyed> extends Keyed {
Tag<Material> WOOL_CARPETS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("wool_carpets"), Material.class);
String REGISTRY_ITEMS = "items";
Tag<Material> ITEMS_ACACIA_LOGS = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("acacia_logs"), Material.class);
Tag<Material> ITEMS_ANVIL = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("anvil"), Material.class);
@@ -771,14 +773,10 @@ public interface Tag<T extends Keyed> extends Keyed {
Tag<Material> ITEMS_WOOL_CARPETS = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("wool_carpets"), Material.class);
String REGISTRY_FLUIDS = "fluids";
Tag<Fluid> FLUIDS_LAVA = Bukkit.getTag(REGISTRY_FLUIDS, NamespacedKey.minecraft("lava"), Fluid.class);
Tag<Fluid> FLUIDS_WATER = Bukkit.getTag(REGISTRY_FLUIDS, NamespacedKey.minecraft("water"), Fluid.class);
String REGISTRY_ENTITY_TYPES = "entity_types";
Tag<EntityType> ENTITY_TYPES_AQUATIC = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("aquatic"), EntityType.class);
Tag<EntityType> ENTITY_TYPES_ARROWS = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("arrows"), EntityType.class);
@@ -857,8 +855,6 @@ public interface Tag<T extends Keyed> extends Keyed {
Tag<EntityType> ENTITY_TYPES_ZOMBIES = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("zombies"), EntityType.class);
String REGISTRY_GAME_EVENTS = "game_events";
Tag<GameEvent> GAME_EVENT_ALLAY_CAN_LISTEN = Bukkit.getTag(REGISTRY_GAME_EVENTS, NamespacedKey.minecraft("allay_can_listen"), GameEvent.class);
Tag<GameEvent> GAME_EVENT_IGNORE_VIBRATIONS_SNEAKING = Bukkit.getTag(REGISTRY_GAME_EVENTS, NamespacedKey.minecraft("ignore_vibrations_sneaking"), GameEvent.class);

View File

@@ -17,147 +17,184 @@ import org.jetbrains.annotations.NotNull;
*/
public interface Attribute extends OldEnum<Attribute>, Keyed, Translatable, net.kyori.adventure.translation.Translatable { // Paper - Adventure translations
/**
* Maximum health of an Entity.
*/
Attribute MAX_HEALTH = getAttribute("max_health");
/**
* Range at which an Entity will follow others.
*/
Attribute FOLLOW_RANGE = getAttribute("follow_range");
/**
* Resistance of an Entity to knockback.
*/
Attribute KNOCKBACK_RESISTANCE = getAttribute("knockback_resistance");
/**
* Movement speed of an Entity.
*/
Attribute MOVEMENT_SPEED = getAttribute("movement_speed");
/**
* Flying speed of an Entity.
*/
Attribute FLYING_SPEED = getAttribute("flying_speed");
/**
* Attack damage of an Entity.
*/
Attribute ATTACK_DAMAGE = getAttribute("attack_damage");
/**
* Attack knockback of an Entity.
*/
Attribute ATTACK_KNOCKBACK = getAttribute("attack_knockback");
/**
* Attack speed of an Entity.
*/
Attribute ATTACK_SPEED = getAttribute("attack_speed");
// Start generate - Attribute
// @GeneratedFrom 1.21.7
/**
* Armor bonus of an Entity.
*/
Attribute ARMOR = getAttribute("armor");
/**
* Armor durability bonus of an Entity.
*/
Attribute ARMOR_TOUGHNESS = getAttribute("armor_toughness");
/**
* The fall damage multiplier of an Entity.
* Attack damage of an Entity.
*/
Attribute FALL_DAMAGE_MULTIPLIER = getAttribute("fall_damage_multiplier");
Attribute ATTACK_DAMAGE = getAttribute("attack_damage");
/**
* Luck bonus of an Entity.
* Attack knockback of an Entity.
*/
Attribute LUCK = getAttribute("luck");
Attribute ATTACK_KNOCKBACK = getAttribute("attack_knockback");
/**
* Maximum absorption of an Entity.
* Attack speed of an Entity.
*/
Attribute MAX_ABSORPTION = getAttribute("max_absorption");
/**
* The distance which an Entity can fall without damage.
*/
Attribute SAFE_FALL_DISTANCE = getAttribute("safe_fall_distance");
/**
* The relative scale of an Entity.
*/
Attribute SCALE = getAttribute("scale");
/**
* The height which an Entity can walk over.
*/
Attribute STEP_HEIGHT = getAttribute("step_height");
/**
* The gravity applied to an Entity.
*/
Attribute GRAVITY = getAttribute("gravity");
/**
* Strength with which an Entity will jump.
*/
Attribute JUMP_STRENGTH = getAttribute("jump_strength");
/**
* How long an entity remains burning after ignition.
*/
Attribute BURNING_TIME = getAttribute("burning_time");
/**
* The camera distance of a player to their own entity.
*/
Attribute CAMERA_DISTANCE = getAttribute("camera_distance");
/**
* Resistance to knockback from explosions.
*/
Attribute EXPLOSION_KNOCKBACK_RESISTANCE = getAttribute("explosion_knockback_resistance");
/**
* Movement speed through difficult terrain.
*/
Attribute MOVEMENT_EFFICIENCY = getAttribute("movement_efficiency");
/**
* Oxygen use underwater.
*/
Attribute OXYGEN_BONUS = getAttribute("oxygen_bonus");
/**
* Movement speed through water.
*/
Attribute WATER_MOVEMENT_EFFICIENCY = getAttribute("water_movement_efficiency");
/**
* Range at which mobs will be tempted by items.
*/
Attribute TEMPT_RANGE = getAttribute("tempt_range");
/**
* The block reach distance of a Player.
*/
Attribute BLOCK_INTERACTION_RANGE = getAttribute("block_interaction_range");
/**
* The entity reach distance of a Player.
*/
Attribute ENTITY_INTERACTION_RANGE = getAttribute("entity_interaction_range");
Attribute ATTACK_SPEED = getAttribute("attack_speed");
/**
* Block break speed of a Player.
*/
Attribute BLOCK_BREAK_SPEED = getAttribute("block_break_speed");
/**
* The block reach distance of a Player.
*/
Attribute BLOCK_INTERACTION_RANGE = getAttribute("block_interaction_range");
/**
* How long an entity remains burning after ignition.
*/
Attribute BURNING_TIME = getAttribute("burning_time");
/**
* The camera distance of a player to their own entity.
*/
Attribute CAMERA_DISTANCE = getAttribute("camera_distance");
/**
* The entity reach distance of a Player.
*/
Attribute ENTITY_INTERACTION_RANGE = getAttribute("entity_interaction_range");
/**
* Resistance to knockback from explosions.
*/
Attribute EXPLOSION_KNOCKBACK_RESISTANCE = getAttribute("explosion_knockback_resistance");
/**
* The fall damage multiplier of an Entity.
*/
Attribute FALL_DAMAGE_MULTIPLIER = getAttribute("fall_damage_multiplier");
/**
* Flying speed of an Entity.
*/
Attribute FLYING_SPEED = getAttribute("flying_speed");
/**
* Range at which an Entity will follow others.
*/
Attribute FOLLOW_RANGE = getAttribute("follow_range");
/**
* The gravity applied to an Entity.
*/
Attribute GRAVITY = getAttribute("gravity");
/**
* Strength with which an Entity will jump.
*/
Attribute JUMP_STRENGTH = getAttribute("jump_strength");
/**
* Resistance of an Entity to knockback.
*/
Attribute KNOCKBACK_RESISTANCE = getAttribute("knockback_resistance");
/**
* Luck bonus of an Entity.
*/
Attribute LUCK = getAttribute("luck");
/**
* Maximum absorption of an Entity.
*/
Attribute MAX_ABSORPTION = getAttribute("max_absorption");
/**
* Maximum health of an Entity.
*/
Attribute MAX_HEALTH = getAttribute("max_health");
/**
* Mining speed for correct tools.
*/
Attribute MINING_EFFICIENCY = getAttribute("mining_efficiency");
/**
* Movement speed through difficult terrain.
*/
Attribute MOVEMENT_EFFICIENCY = getAttribute("movement_efficiency");
/**
* Movement speed of an Entity.
*/
Attribute MOVEMENT_SPEED = getAttribute("movement_speed");
/**
* Oxygen use underwater.
*/
Attribute OXYGEN_BONUS = getAttribute("oxygen_bonus");
/**
* The distance which an Entity can fall without damage.
*/
Attribute SAFE_FALL_DISTANCE = getAttribute("safe_fall_distance");
/**
* The relative scale of an Entity.
*/
Attribute SCALE = getAttribute("scale");
/**
* Sneaking speed.
*/
Attribute SNEAKING_SPEED = getAttribute("sneaking_speed");
/**
* Underwater mining speed.
*/
Attribute SUBMERGED_MINING_SPEED = getAttribute("submerged_mining_speed");
/**
* Sweeping damage.
*/
Attribute SWEEPING_DAMAGE_RATIO = getAttribute("sweeping_damage_ratio");
/**
* Chance of a zombie to spawn reinforcements.
*/
Attribute SPAWN_REINFORCEMENTS = getAttribute("spawn_reinforcements");
/**
* Attribute controlling the range an entity transmits itself as a waypoint.
* The height which an Entity can walk over.
*/
Attribute WAYPOINT_TRANSMIT_RANGE = getAttribute("waypoint_transmit_range");
Attribute STEP_HEIGHT = getAttribute("step_height");
/**
* Underwater mining speed.
*/
Attribute SUBMERGED_MINING_SPEED = getAttribute("submerged_mining_speed");
/**
* Sweeping damage.
*/
Attribute SWEEPING_DAMAGE_RATIO = getAttribute("sweeping_damage_ratio");
/**
* Range at which mobs will be tempted by items.
*/
Attribute TEMPT_RANGE = getAttribute("tempt_range");
/**
* Movement speed through water.
*/
Attribute WATER_MOVEMENT_EFFICIENCY = getAttribute("water_movement_efficiency");
/**
* Attribute controlling the range an entity receives other waypoints from.
*/
Attribute WAYPOINT_RECEIVE_RANGE = getAttribute("waypoint_receive_range");
/**
* Attribute controlling the range an entity transmits itself as a waypoint.
*/
Attribute WAYPOINT_TRANSMIT_RANGE = getAttribute("waypoint_transmit_range");
// End generate - Attribute
@NotNull
private static Attribute getAttribute(@NotNull String key) {
return Registry.ATTRIBUTE.getOrThrow(NamespacedKey.minecraft(key));

View File

@@ -37,8 +37,6 @@ import org.bukkit.entity.minecart.PoweredMinecart;
import org.bukkit.entity.minecart.RideableMinecart;
import org.bukkit.entity.minecart.SpawnerMinecart;
import org.bukkit.entity.minecart.StorageMinecart;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

View File

@@ -6,6 +6,7 @@ package org.bukkit.entity;
public enum Pose {
// Start generate - Pose
// @GeneratedFrom 1.21.7
/**
* Entity is standing normally.
*/

View File

@@ -1,5 +1,6 @@
package org.bukkit.inventory;
import com.destroystokyo.paper.inventory.meta.ArmorStandMeta;
import com.google.common.collect.Multimap;
import io.papermc.paper.datacomponent.DataComponentType;
import java.util.Set;
@@ -94,7 +95,7 @@ public interface ItemType extends Keyed, Translatable, net.kyori.adventure.trans
//<editor-fold desc="ItemTypes" defaultstate="collapsed">
// Start generate - ItemType
// @GeneratedFrom 1.21.7-rc1
// @GeneratedFrom 1.21.7
ItemType.Typed<ItemMeta> ACACIA_BOAT = getItemType("acacia_boat");
ItemType.Typed<ItemMeta> ACACIA_BUTTON = getItemType("acacia_button");
@@ -165,7 +166,7 @@ public interface ItemType extends Keyed, Translatable, net.kyori.adventure.trans
ItemType.Typed<SpawnEggMeta> ARMADILLO_SPAWN_EGG = getItemType("armadillo_spawn_egg");
ItemType.Typed<com.destroystokyo.paper.inventory.meta.ArmorStandMeta> ARMOR_STAND = getItemType("armor_stand");
ItemType.Typed<ArmorStandMeta> ARMOR_STAND = getItemType("armor_stand");
ItemType.Typed<ItemMeta> ARMS_UP_POTTERY_SHERD = getItemType("arms_up_pottery_sherd");

View File

@@ -1,3 +1,6 @@
[*.java]
ij_java_generate_final_locals = false
ij_java_generate_final_parameters = false
[*.json]
indent_size = 2

View File

@@ -9,64 +9,63 @@ paperweight {
atFile.set(layout.projectDirectory.file("wideners.at"))
}
val serverRuntimeClasspath by configurations.registering { // resolvable?
isCanBeConsumed = false
isCanBeResolved = true
}
dependencies {
minecraftJar(project(":paper-server", "mappedJarOutgoing"))
implementation(project(":paper-server", "macheMinecraftLibraries"))
implementation("com.squareup:javapoet:1.13.0")
implementation(project(":paper-api"))
implementation("io.papermc.typewriter:typewriter:1.0.1") {
isTransitive = false // paper-api already have everything
}
implementation("io.papermc.typewriter:typewriter:1.0.2-20250601.125803-3")
implementation("info.picocli:picocli:4.7.6")
implementation("io.github.classgraph:classgraph:4.8.47")
implementation("org.jetbrains:annotations:26.0.1")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
implementation("io.github.classgraph:classgraph:4.8.179")
implementation("org.jetbrains:annotations:26.0.2")
implementation("org.jspecify:jspecify:1.0.0")
serverRuntimeClasspath(project(":paper-server", "runtimeConfiguration"))
testImplementation("org.junit.jupiter:junit-jupiter:5.12.2")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
val gameVersion = providers.gradleProperty("mcVersion")
val rewriteApi = tasks.registerGenerationTask("rewriteApi", true, "api", {
bootstrapTags = true
sourceSet = rootProject.layout.projectDirectory.dir("paper-api")
sourceSet = "paper-api/src/main/java"
}) {
description = "Rewrite existing API classes"
classpath(sourceSets.main.map { it.runtimeClasspath })
}
val rewriteImpl = tasks.registerGenerationTask("rewriteImpl", true, "impl", {
sourceSet = rootProject.layout.projectDirectory.dir("paper-server")
serverClassPath.from(serverRuntimeClasspath)
bootstrapTags = true // needed for CraftItemMetasRewriter, remove once item meta is gone
sourceSet = "paper-server/src/main/java"
}) {
description = "Rewrite existing implementation classes"
classpath(sourceSets.main.map { it.runtimeClasspath })
}
val rewriteImplTest = tasks.registerGenerationTask("rewriteImplTest", true, "impl-test", {
sourceSet = "paper-server/src/test/java"
}) {
description = "Rewrite existing implementation test classes"
classpath(sourceSets.main.map { it.runtimeClasspath })
}
tasks.register("rewrite") {
group = "generation"
description = "Rewrite existing API classes and its implementation"
dependsOn(rewriteApi, rewriteImpl)
dependsOn(rewriteApi, rewriteImpl, rewriteImplTest)
}
val generateApi = tasks.registerGenerationTask("generateApi", false, "api", {
bootstrapTags = true
sourceSet = rootProject.layout.projectDirectory.dir("paper-api")
sourceSet = "paper-api/src/generated/java"
}) {
description = "Generate new API classes"
classpath(sourceSets.main.map { it.runtimeClasspath })
}
val generateImpl = tasks.registerGenerationTask("generateImpl", false, "impl", {
sourceSet = rootProject.layout.projectDirectory.dir("paper-server")
sourceSet = "paper-server/src/generated/java"
}) {
description = "Generate new implementation classes"
classpath(sourceSets.main.map { it.runtimeClasspath })
@@ -78,21 +77,34 @@ tasks.register("generate") {
dependsOn(generateApi, generateImpl)
}
tasks.register<JavaExec>("prepareInputFiles") {
group = "generation"
description = "Prepare input files by sorting them (and updating them if possible)"
javaLauncher = javaToolchains.defaultJavaLauncher(project)
mainClass.set("io.papermc.generator.tasks.PrepareInputFiles")
classpath(sourceSets.main.map { it.runtimeClasspath })
inputs.property("gameVersion", gameVersion)
val resourceDir = layout.projectDirectory.dir("src/main/resources")
args(resourceDir.asFile.absolutePath)
inputs.dir(resourceDir)
outputs.dir(resourceDir)
}
if (providers.gradleProperty("updatingMinecraft").getOrElse("false").toBoolean()) {
val scanOldGeneratedSourceCode by tasks.registering(JavaExec::class) {
group = "verification"
description = "Scan source code to detect outdated generated code"
javaLauncher = javaToolchains.defaultJavaLauncher(project)
mainClass.set("io.papermc.generator.rewriter.utils.ScanOldGeneratedSourceCode")
mainClass.set("io.papermc.generator.tasks.ScanOldGeneratedSourceCode")
classpath(sourceSets.main.map { it.runtimeClasspath })
val projectDirs = listOf("paper-api", "paper-server").map { rootProject.layout.projectDirectory.dir(it) }
args(projectDirs.map { it.asFile.absolutePath })
val workDirs = projectDirs.map { it.dir("src/main/java") }
val workDirs = projectDirs.map { it.dir("src/main/java") }.plus(rootProject.layout.projectDirectory.dir("paper-server/src/test/java"))
workDirs.forEach { inputs.dir(it) }
inputs.property("gameVersion", gameVersion)
outputs.dirs(workDirs)
}
tasks.check {
dependsOn(scanOldGeneratedSourceCode)
@@ -110,20 +122,19 @@ fun TaskContainer.registerGenerationTask(
dependsOn(project.tasks.test)
javaLauncher = project.javaToolchains.defaultJavaLauncher(project)
inputs.property("gameVersion", gameVersion)
inputs.dir(layout.projectDirectory.dir("src/main/java")).withPathSensitivity(PathSensitivity.RELATIVE)
inputs.dir(layout.projectDirectory.dir("src/main/")).withPathSensitivity(PathSensitivity.RELATIVE)
mainClass.set("io.papermc.generator.Main")
systemProperty("paper.updatingMinecraft", providers.gradleProperty("updatingMinecraft").getOrElse("false").toBoolean())
val provider = objects.newInstance<GenerationArgumentProvider>()
provider.side = side
provider.rewrite = rewrite
provider.rootDir = rootProject.layout.projectDirectory
if (args != null) {
args(provider)
}
argumentProviders.add(provider)
val targetDir = if (rewrite) "src/main/java" else "src/generated/java"
outputs.dir(provider.sourceSet.dir(targetDir))
// outputs.dir(provider.sourceSet)
block(this)
}
@@ -133,7 +144,10 @@ abstract class GenerationArgumentProvider : CommandLineArgumentProvider {
@get:PathSensitive(PathSensitivity.NONE)
@get:InputDirectory
abstract val sourceSet: DirectoryProperty
abstract val rootDir: DirectoryProperty
@get:Input
abstract val sourceSet: Property<String>
@get:Input
abstract val rewrite: Property<Boolean>
@@ -141,9 +155,6 @@ abstract class GenerationArgumentProvider : CommandLineArgumentProvider {
@get:Input
abstract val side: Property<String>
@get:CompileClasspath
abstract val serverClassPath: ConfigurableFileCollection
@get:Input
@get:Optional
abstract val bootstrapTags: Property<Boolean>
@@ -155,17 +166,18 @@ abstract class GenerationArgumentProvider : CommandLineArgumentProvider {
override fun asArguments(): Iterable<String> {
val args = mutableListOf<String>()
args.add("--sourceset=${sourceSet.get().asFile.absolutePath}")
args.add("--root-dir=${rootDir.get().asFile.absolutePath}")
args.add("--sourceset=${rootDir.get().dir(sourceSet.get()).asFile.absolutePath}")
args.add("--side=${side.get()}")
args.add("--classpath=${serverClassPath.asPath}")
if (rewrite.get()) {
args.add("--rewrite")
}
if (bootstrapTags.get()) {
args.add(("--bootstrap-tags"))
args.add("--bootstrap-tags")
}
return args.toList()
}
}
@@ -173,6 +185,9 @@ abstract class GenerationArgumentProvider : CommandLineArgumentProvider {
tasks.test {
useJUnitPlatform()
}
tasks.compileTestJava {
options.compilerArgs.add("-parameters")
}
group = "io.papermc.paper"
version = "1.0-SNAPSHOT"

View File

@@ -4,6 +4,7 @@ import io.papermc.generator.registry.RegistryBootstrapper;
import io.papermc.generator.types.SourceGenerator;
import io.papermc.generator.types.craftblockdata.CraftBlockDataBootstrapper;
import io.papermc.generator.types.goal.MobGoalGenerator;
import io.papermc.generator.utils.BasePackage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -15,7 +16,7 @@ public interface Generators {
List<SourceGenerator> API = Collections.unmodifiableList(Util.make(new ArrayList<>(), list -> {
RegistryBootstrapper.bootstrap(list);
list.add(new MobGoalGenerator("VanillaGoal", "com.destroystokyo.paper.entity.ai"));
list.add(new MobGoalGenerator("VanillaGoal", BasePackage.PAPER_LEGACY.name() + ".entity.ai"));
// todo extract fields for registry based api
}));

View File

@@ -11,7 +11,6 @@ import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
@@ -44,12 +43,12 @@ import picocli.CommandLine;
)
public class Main implements Callable<Integer> {
@CommandLine.Option(names = {"--root-dir"}, required = true)
Path rootDir;
@CommandLine.Option(names = {"--sourceset"}, required = true)
Path sourceSet;
@CommandLine.Option(names = {"-cp", "--classpath"}, split = "[;:]", required = true)
Set<Path> classpath;
@CommandLine.Option(names = {"--rewrite"})
boolean isRewrite;
@@ -61,17 +60,19 @@ public class Main implements Callable<Integer> {
private static final Logger LOGGER = LogUtils.getLogger();
public static @MonotonicNonNull Path ROOT_DIR;
public static RegistryAccess.@MonotonicNonNull Frozen REGISTRY_ACCESS;
public static @MonotonicNonNull Map<TagKey<?>, String> EXPERIMENTAL_TAGS;
public static final boolean IS_UPDATING = Boolean.getBoolean("paper.updatingMinecraft");
public static CompletableFuture<Void> bootStrap(boolean withTags) {
SharedConstants.tryDetectVersion();
Bootstrap.bootStrap();
Bootstrap.validate();
PackRepository resourceRepository = ServerPacksSource.createVanillaTrustedRepository();
resourceRepository.reload();
MultiPackResourceManager resourceManager = new MultiPackResourceManager(PackType.SERVER_DATA, resourceRepository.getAvailablePacks().stream().map(Pack::open).toList());
PackRepository packRepository = ServerPacksSource.createVanillaTrustedRepository();
packRepository.reload();
MultiPackResourceManager resourceManager = new MultiPackResourceManager(PackType.SERVER_DATA, packRepository.getAvailablePacks().stream().map(Pack::open).toList());
LayeredRegistryAccess<RegistryLayer> layers = RegistryLayer.createRegistryAccess();
List<Registry.PendingTags<?>> pendingTags = TagLoader.loadTagsForExistingRegistries(resourceManager, layers.getLayer(RegistryLayer.STATIC));
List<HolderLookup.RegistryLookup<?>> worldGenLayer = TagLoader.buildUpdatedLookups(layers.getAccessForLoading(RegistryLayer.WORLDGEN), pendingTags);
@@ -106,9 +107,10 @@ public class Main implements Callable<Integer> {
public Integer call() {
bootStrap(this.tagBootstrap).join();
ROOT_DIR = this.rootDir;
try {
if (this.isRewrite) {
rewrite(this.sourceSet, this.classpath, this.side.equals("api") ? Rewriters.API : Rewriters.SERVER);
rewrite(this.sourceSet, Rewriters.VALUES.get(this.side));
} else {
generate(this.sourceSet, this.side.equals("api") ? Generators.API : Generators.SERVER);
}
@@ -120,22 +122,21 @@ public class Main implements Callable<Integer> {
return 0;
}
private static void rewrite(Path sourceSet, Set<Path> classpath, Consumer<PatternSourceSetRewriter> rewriters) throws IOException {
PatternSourceSetRewriter sourceSetRewriter = new PaperPatternSourceSetRewriter(classpath);
private static void rewrite(Path sourceSet, Consumer<PatternSourceSetRewriter> rewriters) throws IOException {
PatternSourceSetRewriter sourceSetRewriter = new PaperPatternSourceSetRewriter();
rewriters.accept(sourceSetRewriter);
sourceSetRewriter.apply(sourceSet.resolve("src/main/java"));
sourceSetRewriter.apply(sourceSet);
}
private static void generate(Path sourceSet, Collection<SourceGenerator> generators) throws IOException {
Path output = sourceSet.resolve("src/generated/java");
if (Files.exists(output)) {
PathUtils.deleteDirectory(output);
if (Files.exists(sourceSet)) {
PathUtils.deleteDirectory(sourceSet);
}
for (SourceGenerator generator : generators) {
generator.writeToFile(output);
generator.writeToFile(sourceSet);
}
LOGGER.info("Files written to {}", output.toAbsolutePath());
LOGGER.info("Files written to {}", sourceSet.toAbsolutePath());
}
public static void main(String[] args) {

View File

@@ -2,159 +2,144 @@ package io.papermc.generator;
import io.papermc.generator.registry.RegistryBootstrapper;
import io.papermc.generator.registry.RegistryEntries;
import io.papermc.generator.resources.DataFileLoader;
import io.papermc.generator.resources.DataFiles;
import io.papermc.generator.resources.data.EntityClassData;
import io.papermc.generator.rewriter.registration.PatternSourceSetRewriter;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.rewriter.types.registry.EnumRegistryRewriter;
import io.papermc.generator.rewriter.types.registry.FeatureFlagRewriter;
import io.papermc.generator.rewriter.types.registry.PaperFeatureFlagMapping;
import io.papermc.generator.rewriter.types.registry.RegistriesArgumentProviderRewriter;
import io.papermc.generator.rewriter.types.registry.RegistryConversionTestRewriter;
import io.papermc.generator.rewriter.types.registry.RegistryFieldRewriter;
import io.papermc.generator.rewriter.types.registry.RegistryTagRewriter;
import io.papermc.generator.rewriter.types.registry.TagRewriter;
import io.papermc.generator.rewriter.types.simple.BlockPropertiesRewriter;
import io.papermc.generator.rewriter.types.simple.BlockTypeRewriter;
import io.papermc.generator.rewriter.types.simple.CraftBlockDataMapping;
import io.papermc.generator.rewriter.types.simple.CraftBlockEntityStateMapping;
import io.papermc.generator.rewriter.types.simple.CraftItemMetasRewriter;
import io.papermc.generator.rewriter.types.simple.CraftPotionUtilRewriter;
import io.papermc.generator.rewriter.types.simple.EntityTypeRewriter;
import io.papermc.generator.rewriter.types.simple.ItemTypeRewriter;
import io.papermc.generator.rewriter.types.simple.MapPaletteRewriter;
import io.papermc.generator.rewriter.types.simple.MaterialRewriter;
import io.papermc.generator.rewriter.types.simple.MemoryKeyRewriter;
import io.papermc.generator.rewriter.types.simple.StatisticRewriter;
import io.papermc.generator.rewriter.types.simple.trial.AttributeRewriter;
import io.papermc.generator.rewriter.types.simple.trial.PoseRewriter;
import io.papermc.generator.rewriter.types.simple.trial.VillagerProfessionRewriter;
import io.papermc.generator.types.goal.MobGoalNames;
import io.papermc.generator.utils.Formatting;
import io.papermc.paper.datacomponent.item.consumable.ItemUseAnimation;
import io.papermc.paper.dialog.Dialog;
import io.papermc.typewriter.preset.EnumCloneRewriter;
import io.papermc.typewriter.preset.model.EnumValue;
import io.papermc.typewriter.preset.model.EnumConstant;
import io.papermc.typewriter.replace.SearchMetadata;
import io.papermc.typewriter.replace.SearchReplaceRewriter;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Consumer;
import javax.lang.model.SourceVersion;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minecraft.Util;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.animal.Fox;
import net.minecraft.world.entity.animal.Panda;
import net.minecraft.world.entity.animal.Salmon;
import net.minecraft.world.entity.animal.TropicalFish;
import net.minecraft.world.entity.animal.armadillo.Armadillo;
import net.minecraft.world.entity.animal.sniffer.Sniffer;
import net.minecraft.world.entity.vehicle.AbstractBoat;
import net.minecraft.world.item.ItemUseAnimation;
import net.minecraft.world.item.JukeboxSong;
import net.minecraft.world.item.Rarity;
import org.bukkit.Art;
import org.bukkit.FeatureFlag;
import org.bukkit.Fluid;
import org.bukkit.GameEvent;
import org.bukkit.JukeboxSong;
import org.bukkit.Material;
import org.bukkit.MusicInstrument;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.Statistic;
import org.bukkit.Tag;
import org.bukkit.block.Biome;
import org.bukkit.block.BlockType;
import org.bukkit.block.banner.PatternType;
import org.bukkit.damage.DamageType;
import org.bukkit.entity.Armadillo;
import org.bukkit.entity.Boat;
import org.bukkit.entity.Cat;
import org.bukkit.entity.Chicken;
import org.bukkit.entity.Cow;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Fox;
import org.bukkit.entity.Frog;
import org.bukkit.entity.Panda;
import org.bukkit.entity.Pig;
import org.bukkit.entity.Salmon;
import org.bukkit.entity.Sniffer;
import org.bukkit.entity.TropicalFish;
import org.bukkit.entity.Villager;
import org.bukkit.entity.Wolf;
import org.bukkit.entity.memory.MemoryKey;
import org.bukkit.generator.structure.Structure;
import org.bukkit.generator.structure.StructureType;
import org.bukkit.inventory.ItemRarity;
import org.bukkit.inventory.meta.trim.TrimMaterial;
import org.bukkit.inventory.meta.trim.TrimPattern;
import org.bukkit.inventory.recipe.CookingBookCategory;
import org.bukkit.inventory.recipe.CraftingBookCategory;
import org.bukkit.map.MapCursor;
import org.bukkit.map.MapPalette;
import org.bukkit.potion.PotionType;
import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.tag.DamageTypeTags;
import net.minecraft.world.item.crafting.CookingBookCategory;
import net.minecraft.world.item.crafting.CraftingBookCategory;
import net.minecraft.world.scores.DisplaySlot;
import org.jspecify.annotations.NullMarked;
import static io.papermc.generator.rewriter.registration.PaperPatternSourceSetRewriter.composite;
import static io.papermc.generator.rewriter.registration.RewriterHolder.holder;
import static io.papermc.generator.rewriter.registration.RewriterHolder.sameHolder;
import static io.papermc.generator.utils.Formatting.quoted;
@NullMarked
public final class Rewriters {
public static void bootstrap(PatternSourceSetRewriter apiSourceSet, PatternSourceSetRewriter serverSourceSet) {
bootstrapApi(apiSourceSet);
bootstrapServer(serverSourceSet);
public static void bootstrap(PatternSourceSetRewriter... sourceSets) {
Iterator<Consumer<PatternSourceSetRewriter>> values = VALUES.values().iterator();
for (PatternSourceSetRewriter sourceSetRewriter : sourceSets) {
values.next().accept(sourceSetRewriter);
}
}
public static final Consumer<PatternSourceSetRewriter> API = Rewriters::bootstrapApi;
public static final Consumer<PatternSourceSetRewriter> SERVER = Rewriters::bootstrapServer;
public static final Map<String, Consumer<PatternSourceSetRewriter>> VALUES = Util.make(new LinkedHashMap<>(), map -> {
map.put("api", Rewriters::bootstrapApi);
map.put("impl", Rewriters::bootstrapImpl);
map.put("impl-test", Rewriters::bootstrapImplTest);
});
private static void bootstrapApi(PatternSourceSetRewriter sourceSet) {
sourceSet
.register("PotionType", PotionType.class, new EnumRegistryRewriter<>(Registries.POTION))
.register("EntityType", EntityType.class, new EntityTypeRewriter())
.register("DisplaySlot", DisplaySlot.class, new EnumCloneRewriter<>(net.minecraft.world.scores.DisplaySlot.class) {
.register("PotionType", new EnumRegistryRewriter<>(Registries.POTION))
.register("EntityType", new EntityTypeRewriter())
.register("DisplaySlot", Types.DISPLAY_SLOT, new EnumCloneRewriter<>(DisplaySlot.class) {
@Override
protected EnumValue.Builder rewriteEnumValue(net.minecraft.world.scores.DisplaySlot slot) {
final String name;
if (slot == net.minecraft.world.scores.DisplaySlot.LIST) {
name = "PLAYER_LIST";
} else {
name = Formatting.formatKeyAsField(slot.getSerializedName());
protected EnumConstant.Builder constantPrototype(DisplaySlot slot) {
return EnumConstant.builder(Formatting.formatKeyAsField(slot.getSerializedName()));
}
@Override
protected void rewriteConstant(EnumConstant.Builder builder, DisplaySlot slot) {
if (slot == DisplaySlot.LIST) {
builder.rename(name -> "PLAYER_LIST");
}
builder.argument(quoted(slot.getSerializedName()));
}
})
.register("Pose", Types.POSE, new PoseRewriter())
.register("SnifferState", Types.SNIFFER_STATE, new EnumCloneRewriter<>(Sniffer.State.class))
.register("PandaGene", Types.PANDA_GENE, new EnumCloneRewriter<>(Panda.Gene.class) {
@Override
protected void rewriteConstant(EnumConstant.Builder builder, Panda.Gene gene) {
builder.argument(String.valueOf(gene.isRecessive()));
}
})
.register("CookingBookCategory", Types.COOKING_BOOK_CATEGORY, new EnumCloneRewriter<>(CookingBookCategory.class))
.register("CraftingBookCategory", Types.CRAFTING_BOOK_CATEGORY, new EnumCloneRewriter<>(CraftingBookCategory.class))
.register("TropicalFishPattern", Types.TROPICAL_FISH_PATTERN, new EnumCloneRewriter<>(TropicalFish.Pattern.class))
.register("BoatStatus", Types.BOAT_STATUS, new EnumCloneRewriter<>(AbstractBoat.Status.class))
.register("FoxType", Types.FOX_TYPE, new EnumCloneRewriter<>(Fox.Variant.class))
.register("SalmonVariant", Types.SALMON_VARIANT, new EnumCloneRewriter<>(Salmon.Variant.class))
.register("ArmadilloState", Types.ARMADILLO_STATE, new EnumCloneRewriter<>(Armadillo.ArmadilloState.class))
.register("SoundCategory", Types.SOUND_CATEGORY, new EnumCloneRewriter<>(SoundSource.class))
.register("ItemUseAnimation", Types.ITEM_USE_ANIMATION, new EnumCloneRewriter<>(ItemUseAnimation.class))
.register("ItemRarity", Types.ITEM_RARITY, new EnumCloneRewriter<>(Rarity.class) {
@Override
protected void rewriteConstant(EnumConstant.Builder builder, Rarity rarity) {
builder.argument("%s.%s".formatted(Types.NAMED_TEXT_COLOR.simpleName(), rarity.color().name()));
}
})
.register(Types.MATERIAL, composite(
sameHolder("Blocks", new MaterialRewriter.Blocks()),
//sameHolder("Material#isTransparent", MaterialRewriter.IsTransparent()),
return EnumValue.builder(name).argument(quoted(slot.getSerializedName()));
}
})
.register("SnifferState", Sniffer.State.class, new EnumCloneRewriter<>(net.minecraft.world.entity.animal.sniffer.Sniffer.State.class))
.register("PandaGene", Panda.Gene.class, new EnumCloneRewriter<>(net.minecraft.world.entity.animal.Panda.Gene.class) {
@Override
protected EnumValue.Builder rewriteEnumValue(net.minecraft.world.entity.animal.Panda.Gene gene) {
return super.rewriteEnumValue(gene).argument(String.valueOf(gene.isRecessive()));
}
})
.register("CookingBookCategory", CookingBookCategory.class, new EnumCloneRewriter<>(net.minecraft.world.item.crafting.CookingBookCategory.class))
.register("CraftingBookCategory", CraftingBookCategory.class, new EnumCloneRewriter<>(net.minecraft.world.item.crafting.CraftingBookCategory.class))
.register("TropicalFishPattern", TropicalFish.Pattern.class, new EnumCloneRewriter<>(net.minecraft.world.entity.animal.TropicalFish.Pattern.class))
.register("BoatStatus", Boat.Status.class, new EnumCloneRewriter<>(net.minecraft.world.entity.vehicle.Boat.Status.class))
.register("FoxType", Fox.Type.class, new EnumCloneRewriter<>(net.minecraft.world.entity.animal.Fox.Variant.class))
.register("SalmonVariant", Salmon.Variant.class, new EnumCloneRewriter<>(net.minecraft.world.entity.animal.Salmon.Variant.class))
.register("ArmadilloState", Armadillo.State.class, new EnumCloneRewriter<>(net.minecraft.world.entity.animal.armadillo.Armadillo.ArmadilloState.class))
.register("SoundCategory", SoundCategory.class, new EnumCloneRewriter<>(SoundSource.class))
.register("ItemUseAnimation", ItemUseAnimation.class, new EnumCloneRewriter<>(net.minecraft.world.item.ItemUseAnimation.class))
.register("ItemRarity", ItemRarity.class, new EnumCloneRewriter<>(Rarity.class) {
@Override
protected EnumValue.Builder rewriteEnumValue(Rarity rarity) {
return super.rewriteEnumValue(rarity).argument(
"%s.%s".formatted(NamedTextColor.class.getSimpleName(), rarity.color().name())
);
}
})
.register(Material.class, composite(
holder("Blocks", new MaterialRewriter.Blocks()),
//holder("Material#isTransparent", MaterialRewriter.IsTransparent()),
holder("Items", new MaterialRewriter.Items())
sameHolder("Items", new MaterialRewriter.Items())
))
.register(Statistic.class, composite(
holder("StatisticCustom", new StatisticRewriter.Custom()),
holder("StatisticType", new StatisticRewriter.Type())
.register(Types.STATISTIC, composite(
sameHolder("StatisticCustom", new StatisticRewriter.Custom()),
sameHolder("StatisticType", new StatisticRewriter.Type())
))
.register(Villager.class, composite(
holder("VillagerType", Villager.Type.class, new RegistryFieldRewriter<>(Registries.VILLAGER_TYPE, "getType")),
holder("VillagerProfession", Villager.Profession.class, new VillagerProfessionRewriter())
.register(Types.VILLAGER, composite(
holder("VillagerType", new RegistryFieldRewriter<>(Registries.VILLAGER_TYPE, "getType")),
holder("VillagerProfession", new VillagerProfessionRewriter())
))
.register("JukeboxSong", JukeboxSong.class, new RegistryFieldRewriter<>(Registries.JUKEBOX_SONG, "get") {
.register("JukeboxSong", new RegistryFieldRewriter<>(Registries.JUKEBOX_SONG, "get") {
@Override
protected String rewriteFieldName(Holder.Reference<net.minecraft.world.item.JukeboxSong> reference) {
protected String rewriteFieldName(Holder.Reference<JukeboxSong> reference) {
String keyedName = super.rewriteFieldName(reference);
if (!SourceVersion.isIdentifier(keyedName)) {
// fallback to field names for invalid identifier (happens for 5, 11, 13 etc.)
@@ -163,57 +148,59 @@ public final class Rewriters {
return keyedName;
}
})
.register("DamageTypeTags", DamageTypeTags.class, new RegistryTagRewriter<>(Registries.DAMAGE_TYPE, DamageType.class))
.register("MapCursorType", MapCursor.Type.class, new RegistryFieldRewriter<>(Registries.MAP_DECORATION_TYPE, "getType"))
.register("Structure", Structure.class, new RegistryFieldRewriter<>(Registries.STRUCTURE, "getStructure"))
.register("StructureType", StructureType.class, new RegistryFieldRewriter<>(Registries.STRUCTURE_TYPE, "getStructureType"))
.register("TrimPattern", TrimPattern.class, new RegistryFieldRewriter<>(Registries.TRIM_PATTERN, "getTrimPattern"))
.register("TrimMaterial", TrimMaterial.class, new RegistryFieldRewriter<>(Registries.TRIM_MATERIAL, "getTrimMaterial"))
.register("DamageType", DamageType.class, new RegistryFieldRewriter<>(Registries.DAMAGE_TYPE, "getDamageType"))
.register("GameEvent", GameEvent.class, new RegistryFieldRewriter<>(Registries.GAME_EVENT, "getEvent"))
.register("MusicInstrument", MusicInstrument.class, new RegistryFieldRewriter<>(Registries.INSTRUMENT, "getInstrument"))
.register("WolfVariant", Wolf.Variant.class, new RegistryFieldRewriter<>(Registries.WOLF_VARIANT, "getVariant"))
.register("WolfSoundVariant", Wolf.SoundVariant.class, new RegistryFieldRewriter<>(Registries.WOLF_SOUND_VARIANT, "getSoundVariant"))
.register("CatType", Cat.Type.class, new RegistryFieldRewriter<>(Registries.CAT_VARIANT, "getType"))
.register("FrogVariant", Frog.Variant.class, new RegistryFieldRewriter<>(Registries.FROG_VARIANT, "getVariant"))
.register("PatternType", PatternType.class, new RegistryFieldRewriter<>(Registries.BANNER_PATTERN, "getType"))
.register("Biome", Biome.class, new RegistryFieldRewriter<>(Registries.BIOME, "getBiome"))
.register("Fluid", Fluid.class, new RegistryFieldRewriter<>(Registries.FLUID, "getFluid"))
// .register("Attribute", Attribute.class, new RegistryFieldRewriter<>(Registries.ATTRIBUTE, "getAttribute")) - disable for now (javadocs)
.register("Sound", Sound.class, new RegistryFieldRewriter<>(Registries.SOUND_EVENT, "getSound"))
.register("Art", Art.class, new RegistryFieldRewriter<>(Registries.PAINTING_VARIANT, "getArt"))
.register("ChickenVariant", Chicken.Variant.class, new RegistryFieldRewriter<>(Registries.CHICKEN_VARIANT, "getVariant"))
.register("CowVariant", Cow.Variant.class, new RegistryFieldRewriter<>(Registries.COW_VARIANT, "getVariant"))
.register("PigVariant", Pig.Variant.class, new RegistryFieldRewriter<>(Registries.PIG_VARIANT, "getVariant"))
.register("Dialog", Dialog.class, new RegistryFieldRewriter<>(Registries.DIALOG, "getDialog"))
.register("MemoryKey", MemoryKey.class, new MemoryKeyRewriter())
// .register("ItemType", ItemType.class, new ItemTypeRewriter()) - disable for now, lynx want the generic type
.register("BlockType", BlockType.class, new BlockTypeRewriter())
.register("FeatureFlag", FeatureFlag.class, new FeatureFlagRewriter())
.register("Tag", Tag.class, new TagRewriter())
.register("MapPalette#colors", MapPalette.class, new MapPaletteRewriter());
.register("DamageTypeTags", Types.DAMAGE_TYPE_TAGS, new RegistryTagRewriter<>(Registries.DAMAGE_TYPE))
.register("MapCursorType", new RegistryFieldRewriter<>(Registries.MAP_DECORATION_TYPE, "getType"))
.register("Structure", new RegistryFieldRewriter<>(Registries.STRUCTURE, "getStructure"))
.register("StructureType", new RegistryFieldRewriter<>(Registries.STRUCTURE_TYPE, "getStructureType"))
.register("TrimPattern", new RegistryFieldRewriter<>(Registries.TRIM_PATTERN, "getTrimPattern"))
.register("TrimMaterial", new RegistryFieldRewriter<>(Registries.TRIM_MATERIAL, "getTrimMaterial"))
.register("DamageType", new RegistryFieldRewriter<>(Registries.DAMAGE_TYPE, "getDamageType"))
.register("GameEvent", new RegistryFieldRewriter<>(Registries.GAME_EVENT, "getEvent"))
.register("MusicInstrument", new RegistryFieldRewriter<>(Registries.INSTRUMENT, "getInstrument"))
.register("WolfVariant", new RegistryFieldRewriter<>(Registries.WOLF_VARIANT, "getVariant"))
.register("WolfSoundVariant", new RegistryFieldRewriter<>(Registries.WOLF_SOUND_VARIANT, "getSoundVariant"))
.register("CatType", new RegistryFieldRewriter<>(Registries.CAT_VARIANT, "getType"))
.register("FrogVariant", new RegistryFieldRewriter<>(Registries.FROG_VARIANT, "getVariant"))
.register("PatternType", new RegistryFieldRewriter<>(Registries.BANNER_PATTERN, "getType"))
.register("Biome", new RegistryFieldRewriter<>(Registries.BIOME, "getBiome"))
.register("Fluid", new RegistryFieldRewriter<>(Registries.FLUID, "getFluid"))
.register("Attribute", new AttributeRewriter())
.register("Sound", new RegistryFieldRewriter<>(Registries.SOUND_EVENT, "getSound"))
.register("Art", new RegistryFieldRewriter<>(Registries.PAINTING_VARIANT, "getArt"))
.register("ChickenVariant", new RegistryFieldRewriter<>(Registries.CHICKEN_VARIANT, "getVariant"))
.register("CowVariant", new RegistryFieldRewriter<>(Registries.COW_VARIANT, "getVariant"))
.register("PigVariant", new RegistryFieldRewriter<>(Registries.PIG_VARIANT, "getVariant"))
.register("Dialog", new RegistryFieldRewriter<>(Registries.DIALOG, "getDialog"))
.register("BlockProperties", Types.BLOCK_PROPERTIES, new BlockPropertiesRewriter())
.register("MemoryKey", new MemoryKeyRewriter())
.register("ItemType", new ItemTypeRewriter())
.register("BlockType", new BlockTypeRewriter())
.register("FeatureFlag", Types.FEATURE_FLAG, new FeatureFlagRewriter())
.register("Tag", Types.TAG, new TagRewriter())
.register("MapPalette#colors", Types.MAP_PALETTE, new MapPaletteRewriter());
RegistryBootstrapper.bootstrapApi(sourceSet);
}
private static void bootstrapServer(PatternSourceSetRewriter sourceSet) {
private static void bootstrapImpl(PatternSourceSetRewriter sourceSet) {
sourceSet
.register("CraftBlockData#MAP", Types.CRAFT_BLOCK_DATA, new CraftBlockDataMapping())
.register("CraftBlockEntityStates", Types.CRAFT_BLOCK_STATES, new CraftBlockEntityStateMapping())
.register("CraftItemMetas#getItemMetaData", Types.CRAFT_ITEM_METAS, new CraftItemMetasRewriter())
.register(Types.CRAFT_STATISTIC, composite(
holder("CraftStatisticCustom", new StatisticRewriter.CraftCustom()),
holder("CraftStatisticType", new StatisticRewriter.CraftType())
sameHolder("CraftStatisticCustom", new StatisticRewriter.CraftCustom()),
sameHolder("CraftStatisticType", new StatisticRewriter.CraftType())
))
.register(Types.CRAFT_POTION_UTIL, composite(
holder("CraftPotionUtil#upgradeable", new CraftPotionUtilRewriter("strong")),
holder("CraftPotionUtil#extendable", new CraftPotionUtilRewriter("long"))
sameHolder("CraftPotionUtil#upgradeable", new CraftPotionUtilRewriter("strong")),
sameHolder("CraftPotionUtil#extendable", new CraftPotionUtilRewriter("long"))
))
.register("PaperFeatureFlagProviderImpl#FLAGS", Types.PAPER_FEATURE_FLAG_PROVIDER_IMPL, new PaperFeatureFlagMapping())
.register("MobGoalHelper#BUKKIT_BRIDGE", Types.MOB_GOAL_HELPER, new SearchReplaceRewriter() {
@Override
protected void insert(SearchMetadata metadata, StringBuilder builder) {
for (Map.Entry<Class<? extends Mob>, Class<? extends org.bukkit.entity.Mob>> entry : MobGoalNames.BUKKIT_BRIDGE.entrySet()) {
for (Map.Entry<Class<? extends Mob>, EntityClassData> entry : DataFileLoader.get(DataFiles.ENTITY_CLASS_NAMES).entrySet()) {
builder.append(metadata.indent()).append("map.put(%s.class, %s.class);".formatted(
entry.getKey().getCanonicalName(), this.importCollector.getShortName(entry.getValue())
entry.getKey().getCanonicalName(), this.importCollector.getShortName(Types.typed(entry.getValue().name()))
));
builder.append('\n');
}
@@ -221,4 +208,10 @@ public final class Rewriters {
});
RegistryBootstrapper.bootstrapServer(sourceSet);
}
private static void bootstrapImplTest(PatternSourceSetRewriter sourceSet) {
sourceSet
.register("RegistriesArgumentProvider#DATA", Types.REGISTRIES_ARGUMENT_PROVIDER, new RegistriesArgumentProviderRewriter())
.register("RegistryConversionTest#IGNORE_FOR_DIRECT_HOLDER", Types.REGISTRY_CONVERSION_TEST, new RegistryConversionTestRewriter());
}
}

View File

@@ -7,7 +7,7 @@ import io.papermc.generator.rewriter.types.registry.RegistryEventsRewriter;
import io.papermc.generator.types.SourceGenerator;
import io.papermc.generator.types.registry.GeneratedKeyType;
import io.papermc.generator.types.registry.GeneratedTagKeyType;
import io.papermc.paper.registry.event.RegistryEvents;
import io.papermc.generator.utils.BasePackage;
import java.util.List;
import net.minecraft.core.registries.Registries;
import org.jspecify.annotations.NullMarked;
@@ -15,19 +15,19 @@ import org.jspecify.annotations.NullMarked;
@NullMarked
public class RegistryBootstrapper {
private static final String PAPER_REGISTRY_PACKAGE = "io.papermc.paper.registry";
private static final String PAPER_REGISTRY_PACKAGE = BasePackage.PAPER.name() + ".registry";
public static void bootstrap(List<SourceGenerator> generators) {
// typed/tag keys
RegistryEntries.forEach(entry -> {
generators.add(new GeneratedKeyType<>(PAPER_REGISTRY_PACKAGE + ".keys", entry));
if (entry.registry().listTags().findAny().isPresent()) {
generators.add(new GeneratedTagKeyType(entry, PAPER_REGISTRY_PACKAGE + ".keys.tags"));
generators.add(new GeneratedTagKeyType<>(entry, PAPER_REGISTRY_PACKAGE + ".keys.tags"));
}
});
// todo remove once entity type is a registry
generators.add(new GeneratedTagKeyType(RegistryEntries.byRegistryKey(Registries.ENTITY_TYPE), PAPER_REGISTRY_PACKAGE + ".keys.tags"));
generators.add(new GeneratedTagKeyType<>(RegistryEntries.byRegistryKey(Registries.ENTITY_TYPE), PAPER_REGISTRY_PACKAGE + ".keys.tags"));
}
public static void bootstrap(PatternSourceSetRewriter apiSourceSet, PatternSourceSetRewriter serverSourceSet) {
@@ -36,7 +36,7 @@ public class RegistryBootstrapper {
}
public static void bootstrapApi(PatternSourceSetRewriter sourceSet) {
sourceSet.register("RegistryEvents", RegistryEvents.class, new RegistryEventsRewriter());
sourceSet.register("RegistryEvents", Types.REGISTRY_EVENTS, new RegistryEventsRewriter());
}
public static void bootstrapServer(PatternSourceSetRewriter sourceSet) {

View File

@@ -1,36 +1,24 @@
package io.papermc.generator.registry;
import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
import io.papermc.generator.resources.DataFileLoader;
import io.papermc.generator.resources.data.RegistryData;
import io.papermc.generator.utils.ClassHelper;
import io.papermc.paper.datacomponent.DataComponentType;
import io.papermc.paper.datacomponent.DataComponentTypes;
import io.papermc.paper.dialog.Dialog;
import io.papermc.paper.registry.data.BannerPatternRegistryEntry;
import io.papermc.paper.registry.data.CatTypeRegistryEntry;
import io.papermc.paper.registry.data.ChickenVariantRegistryEntry;
import io.papermc.paper.registry.data.CowVariantRegistryEntry;
import io.papermc.paper.registry.data.DamageTypeRegistryEntry;
import io.papermc.paper.registry.data.EnchantmentRegistryEntry;
import io.papermc.paper.registry.data.FrogVariantRegistryEntry;
import io.papermc.paper.registry.data.GameEventRegistryEntry;
import io.papermc.paper.registry.data.InstrumentRegistryEntry;
import io.papermc.paper.registry.data.JukeboxSongRegistryEntry;
import io.papermc.paper.registry.data.PaintingVariantRegistryEntry;
import io.papermc.paper.registry.data.PigVariantRegistryEntry;
import io.papermc.paper.registry.data.SoundEventRegistryEntry;
import io.papermc.paper.registry.data.WolfVariantRegistryEntry;
import io.papermc.paper.registry.data.dialog.DialogRegistryEntry;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import net.minecraft.Util;
import net.minecraft.core.Registry;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.particles.ParticleTypes;
@@ -40,6 +28,7 @@ import net.minecraft.server.dialog.Dialogs;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.damagesource.DamageTypes;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.entity.animal.CatVariants;
@@ -52,6 +41,7 @@ import net.minecraft.world.entity.animal.wolf.WolfVariants;
import net.minecraft.world.entity.decoration.PaintingVariants;
import net.minecraft.world.entity.npc.VillagerProfession;
import net.minecraft.world.entity.npc.VillagerType;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.item.Instruments;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.JukeboxSongs;
@@ -62,69 +52,21 @@ import net.minecraft.world.item.equipment.trim.TrimPatterns;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BannerPatterns;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.levelgen.structure.BuiltinStructures;
import net.minecraft.world.level.levelgen.structure.StructureType;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.level.saveddata.maps.MapDecorationTypes;
import org.bukkit.Art;
import org.bukkit.Fluid;
import org.bukkit.GameEvent;
import org.bukkit.JukeboxSong;
import org.bukkit.Keyed;
import org.bukkit.MusicInstrument;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.attribute.Attribute;
import org.bukkit.block.Biome;
import org.bukkit.block.BlockType;
import org.bukkit.block.banner.PatternType;
import org.bukkit.damage.DamageType;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Cat;
import org.bukkit.entity.Chicken;
import org.bukkit.entity.Cow;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Frog;
import org.bukkit.entity.Pig;
import org.bukkit.entity.Villager;
import org.bukkit.entity.Wolf;
import org.bukkit.entity.memory.MemoryKey;
import org.bukkit.generator.structure.Structure;
import org.bukkit.generator.structure.StructureType;
import org.bukkit.inventory.ItemType;
import org.bukkit.inventory.MenuType;
import org.bukkit.inventory.meta.trim.TrimMaterial;
import org.bukkit.inventory.meta.trim.TrimPattern;
import org.bukkit.map.MapCursor;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.potion.PotionType;
import org.jspecify.annotations.NullMarked;
@NullMarked
public final class RegistryEntries {
// CraftBukkit entry where implementation start by "Craft"
private static <T> RegistryEntry<T> entry(ResourceKey<? extends Registry<T>> registryKey, Class<?> holderElementsClass, Class<? extends Keyed> apiClass) {
return entry(registryKey, holderElementsClass, apiClass, "Craft");
private static <T> RegistryIntern<T> entry(ResourceKey<? extends Registry<T>> registryKey, Class<?> holderElementsClass) {
return new RegistryIntern<>(registryKey, holderElementsClass);
}
private static <T> RegistryEntry<T> entry(ResourceKey<? extends Registry<T>> registryKey, Class<?> holderElementsClass, Class<? extends Keyed> apiClass, String implPrefix) {
String name = io.papermc.typewriter.util.ClassHelper.retrieveFullNestedName(apiClass);
RegistryKeyField<T> registryKeyField = (RegistryKeyField<T>) REGISTRY_KEY_FIELDS.get(registryKey);
String[] classes = name.split("\\.");
if (classes.length == 0) {
return new RegistryEntry<>(registryKey, registryKeyField, holderElementsClass, apiClass, implPrefix.concat(apiClass.getSimpleName()));
}
String implName = Arrays.stream(classes).map(implPrefix::concat).collect(Collectors.joining("."));
return new RegistryEntry<>(registryKey, registryKeyField, holderElementsClass, apiClass, implName);
}
@Deprecated
private static <T> RegistryEntry<T> inconsistentEntry(ResourceKey<? extends Registry<T>> registryKey, Class<?> holderElementsClass, Class<? extends Keyed> apiClass, String implClass) {
return new RegistryEntry<>(registryKey, (RegistryKeyField<T>) REGISTRY_KEY_FIELDS.get(registryKey), holderElementsClass, apiClass, implClass);
}
private static final Map<ResourceKey<? extends Registry<?>>, RegistryKeyField<?>> REGISTRY_KEY_FIELDS;
public static final Map<ResourceKey<? extends Registry<?>>, RegistryKeyField<?>> REGISTRY_KEY_FIELDS;
static {
Map<ResourceKey<? extends Registry<?>>, RegistryKeyField<?>> registryKeyFields = new IdentityHashMap<>();
try {
@@ -146,77 +88,104 @@ public final class RegistryEntries {
REGISTRY_KEY_FIELDS = Collections.unmodifiableMap(registryKeyFields);
}
public static final Set<Class<?>> REGISTRY_CLASS_NAME_BASED_ON_API = Set.of(
BlockType.class,
ItemType.class
private static final Map<ResourceKey<? extends Registry<?>>, RegistryIntern<?>> EXPOSED_REGISTRIES = Stream.of(
entry(Registries.GAME_EVENT, GameEvent.class),
entry(Registries.STRUCTURE_TYPE, StructureType.class),
entry(Registries.MOB_EFFECT, MobEffects.class),
entry(Registries.BLOCK, Blocks.class),
entry(Registries.ITEM, Items.class),
entry(Registries.VILLAGER_PROFESSION, VillagerProfession.class),
entry(Registries.VILLAGER_TYPE, VillagerType.class),
entry(Registries.MAP_DECORATION_TYPE, MapDecorationTypes.class),
entry(Registries.MENU, MenuType.class),
entry(Registries.ATTRIBUTE, Attributes.class),
entry(Registries.FLUID, Fluids.class),
entry(Registries.SOUND_EVENT, SoundEvents.class),
entry(Registries.DATA_COMPONENT_TYPE, DataComponents.class),
entry(Registries.BIOME, Biomes.class),
entry(Registries.STRUCTURE, BuiltinStructures.class),
entry(Registries.TRIM_MATERIAL, TrimMaterials.class),
entry(Registries.TRIM_PATTERN, TrimPatterns.class),
entry(Registries.DAMAGE_TYPE, DamageTypes.class),
entry(Registries.WOLF_VARIANT, WolfVariants.class),
entry(Registries.WOLF_SOUND_VARIANT, WolfSoundVariants.class),
entry(Registries.ENCHANTMENT, Enchantments.class),
entry(Registries.JUKEBOX_SONG, JukeboxSongs.class),
entry(Registries.BANNER_PATTERN, BannerPatterns.class),
entry(Registries.PAINTING_VARIANT, PaintingVariants.class),
entry(Registries.INSTRUMENT, Instruments.class),
entry(Registries.CAT_VARIANT, CatVariants.class),
entry(Registries.FROG_VARIANT, FrogVariants.class),
entry(Registries.CHICKEN_VARIANT, ChickenVariants.class),
entry(Registries.COW_VARIANT, CowVariants.class),
entry(Registries.PIG_VARIANT, PigVariants.class),
entry(Registries.DIALOG, Dialogs.class),
entry(Registries.ENTITY_TYPE, EntityType.class),
entry(Registries.PARTICLE_TYPE, ParticleTypes.class),
entry(Registries.POTION, Potions.class),
entry(Registries.MEMORY_MODULE_TYPE, MemoryModuleType.class)
).collect(Collectors.toMap(RegistryIntern::getRegistryKey, entry -> entry));
@Deprecated
public static final List<RegistryEntry<?>> API_ONLY = new ArrayList<>();
@Deprecated
public static final List<ResourceKey<? extends Registry<?>>> API_ONLY_KEYS = List.of(
Registries.ENTITY_TYPE, Registries.PARTICLE_TYPE, Registries.POTION, Registries.MEMORY_MODULE_TYPE
);
public static final List<RegistryEntry<?>> BUILT_IN = List.of(
entry(Registries.GAME_EVENT, net.minecraft.world.level.gameevent.GameEvent.class, GameEvent.class).writableApiRegistryBuilder(GameEventRegistryEntry.Builder.class, "PaperGameEventRegistryEntry.PaperBuilder"),
entry(Registries.STRUCTURE_TYPE, net.minecraft.world.level.levelgen.structure.StructureType.class, StructureType.class),
entry(Registries.MOB_EFFECT, MobEffects.class, PotionEffectType.class),
entry(Registries.BLOCK, Blocks.class, BlockType.class),
entry(Registries.ITEM, Items.class, ItemType.class),
entry(Registries.VILLAGER_PROFESSION, VillagerProfession.class, Villager.Profession.class),
entry(Registries.VILLAGER_TYPE, VillagerType.class, Villager.Type.class),
entry(Registries.MAP_DECORATION_TYPE, MapDecorationTypes.class, MapCursor.Type.class),
entry(Registries.MENU, net.minecraft.world.inventory.MenuType.class, MenuType.class),
entry(Registries.ATTRIBUTE, Attributes.class, Attribute.class).serializationUpdater("ATTRIBUTE_RENAME"),
entry(Registries.FLUID, Fluids.class, Fluid.class),
entry(Registries.SOUND_EVENT, SoundEvents.class, Sound.class).allowDirect().apiRegistryField("SOUNDS").apiRegistryBuilder(SoundEventRegistryEntry.Builder.class, "PaperSoundEventRegistryEntry.PaperBuilder", RegistryEntry.RegistryModificationApiSupport.NONE),
entry(Registries.DATA_COMPONENT_TYPE, DataComponents.class, DataComponentType.class, "Paper").preload(DataComponentTypes.class).apiAccessName("of")
);
public static final Multimap<RegistryEntry.Type, RegistryEntry<?>> REGISTRIES = Util.make(MultimapBuilder.enumKeys(RegistryEntry.Type.class).arrayListValues().build(), map -> {
List<ResourceKey<? extends Registry<?>>> remainingRegistries = new ArrayList<>(EXPOSED_REGISTRIES.keySet());
DataFileLoader.REGISTRIES.forEach((type, file) -> {
Map<ResourceKey<? extends Registry<?>>, RegistryData> registries = file.get();
for (Map.Entry<ResourceKey<? extends Registry<?>>, RegistryData> registry : registries.entrySet()) {
ResourceKey<? extends Registry<?>> registryKey = registry.getKey();
RegistryIntern<?> intern = Objects.requireNonNull(EXPOSED_REGISTRIES.get(registryKey),
() -> "Registry '%s' found in registry/%s.json is not exposed to the api".formatted(registryKey.location(), type.getSerializedName())
);
RegistryEntry<?> entry = intern.bind(registry.getValue());
entry.validate(type);
if (remainingRegistries.remove(registryKey)) {
if (API_ONLY_KEYS.contains(registryKey)) {
API_ONLY.add(entry);
} else {
map.put(type, entry);
}
}
}
});
public static final List<RegistryEntry<?>> DATA_DRIVEN = List.of(
entry(Registries.BIOME, Biomes.class, Biome.class).delayed(),
entry(Registries.STRUCTURE, BuiltinStructures.class, Structure.class).delayed(),
entry(Registries.TRIM_MATERIAL, TrimMaterials.class, TrimMaterial.class).allowDirect().delayed(),
entry(Registries.TRIM_PATTERN, TrimPatterns.class, TrimPattern.class).allowDirect().delayed(),
entry(Registries.DAMAGE_TYPE, DamageTypes.class, DamageType.class).writableApiRegistryBuilder(DamageTypeRegistryEntry.Builder.class, "PaperDamageTypeRegistryEntry.PaperBuilder").delayed(),
entry(Registries.WOLF_VARIANT, WolfVariants.class, Wolf.Variant.class).writableApiRegistryBuilder(WolfVariantRegistryEntry.Builder.class, "PaperWolfVariantRegistryEntry.PaperBuilder").delayed(),
entry(Registries.WOLF_SOUND_VARIANT, WolfSoundVariants.class, Wolf.SoundVariant.class),
entry(Registries.ENCHANTMENT, Enchantments.class, Enchantment.class).writableApiRegistryBuilder(EnchantmentRegistryEntry.Builder.class, "PaperEnchantmentRegistryEntry.PaperBuilder").serializationUpdater("ENCHANTMENT_RENAME").delayed(),
entry(Registries.JUKEBOX_SONG, JukeboxSongs.class, JukeboxSong.class).writableApiRegistryBuilder(JukeboxSongRegistryEntry.Builder.class, "PaperJukeboxSongRegistryEntry.PaperBuilder").delayed(),
entry(Registries.BANNER_PATTERN, BannerPatterns.class, PatternType.class).allowDirect().writableApiRegistryBuilder(BannerPatternRegistryEntry.Builder.class, "PaperBannerPatternRegistryEntry.PaperBuilder").delayed(),
entry(Registries.PAINTING_VARIANT, PaintingVariants.class, Art.class).writableApiRegistryBuilder(PaintingVariantRegistryEntry.Builder.class, "PaperPaintingVariantRegistryEntry.PaperBuilder").apiRegistryField("ART").delayed(),
entry(Registries.INSTRUMENT, Instruments.class, MusicInstrument.class).allowDirect().writableApiRegistryBuilder(InstrumentRegistryEntry.Builder.class, "PaperInstrumentRegistryEntry.PaperBuilder").delayed(),
entry(Registries.CAT_VARIANT, CatVariants.class, Cat.Type.class).writableApiRegistryBuilder(CatTypeRegistryEntry.Builder.class, "PaperCatTypeRegistryEntry.PaperBuilder").delayed(),
entry(Registries.FROG_VARIANT, FrogVariants.class, Frog.Variant.class).writableApiRegistryBuilder(FrogVariantRegistryEntry.Builder.class, "PaperFrogVariantRegistryEntry.PaperBuilder").delayed(),
entry(Registries.CHICKEN_VARIANT, ChickenVariants.class, Chicken.Variant.class).writableApiRegistryBuilder(ChickenVariantRegistryEntry.Builder.class, "PaperChickenVariantRegistryEntry.PaperBuilder"),
entry(Registries.COW_VARIANT, CowVariants.class, Cow.Variant.class).writableApiRegistryBuilder(CowVariantRegistryEntry.Builder.class, "PaperCowVariantRegistryEntry.PaperBuilder"),
entry(Registries.PIG_VARIANT, PigVariants.class, Pig.Variant.class).writableApiRegistryBuilder(PigVariantRegistryEntry.Builder.class, "PaperPigVariantRegistryEntry.PaperBuilder"),
entry(Registries.DIALOG, Dialogs.class, Dialog.class, "Paper").allowDirect().writableApiRegistryBuilder(DialogRegistryEntry.Builder.class, "PaperDialogRegistryEntry.PaperBuilder")
);
if (!remainingRegistries.isEmpty()) {
throw new IllegalStateException("Registry not found in data files: " + remainingRegistries);
}
});
public static final List<RegistryEntry<?>> 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)
);
public static Collection<RegistryEntry<?>> byType(RegistryEntry.Type type) {
return REGISTRIES.get(type);
}
public static final Map<ResourceKey<? extends Registry<?>>, RegistryEntry<?>> BY_REGISTRY_KEY;
static {
Map<ResourceKey<? extends Registry<?>>, RegistryEntry<?>> byRegistryKey = new IdentityHashMap<>(BUILT_IN.size() + DATA_DRIVEN.size() + API_ONLY.size());
Map<ResourceKey<? extends Registry<?>>, RegistryEntry<?>> byRegistryKey = new IdentityHashMap<>(REGISTRIES.size() + API_ONLY.size());
forEach(entry -> {
byRegistryKey.put(entry.registryKey(), entry);
}, RegistryEntries.BUILT_IN, RegistryEntries.DATA_DRIVEN, RegistryEntries.API_ONLY);
byRegistryKey.put(entry.getRegistryKey(), entry);
}, REGISTRIES.values(), API_ONLY);
BY_REGISTRY_KEY = Collections.unmodifiableMap(byRegistryKey);
}
@SuppressWarnings("unchecked")
public static <T> RegistryEntry<T> byRegistryKey(ResourceKey<? extends Registry<T>> registryKey) {
return (RegistryEntry<T>) Objects.requireNonNull(BY_REGISTRY_KEY.get(registryKey));
return (RegistryEntry<T>) Objects.requireNonNull(BY_REGISTRY_KEY.get(registryKey), "registry not found: " + registryKey);
}
// real registries
public static void forEach(Consumer<RegistryEntry<?>> callback) {
forEach(callback, RegistryEntries.BUILT_IN, RegistryEntries.DATA_DRIVEN);
forEach(callback, REGISTRIES.values());
}
@SafeVarargs
public static void forEach(Consumer<RegistryEntry<?>> callback, List<RegistryEntry<?>>... datas) {
for (List<RegistryEntry<?>> data : datas) {
public static void forEach(Consumer<RegistryEntry<?>> callback, Collection<RegistryEntry<?>>... datas) {
for (Collection<RegistryEntry<?>> data : datas) {
for (RegistryEntry<?> entry : data) {
callback.accept(entry);
}

View File

@@ -2,59 +2,42 @@ package io.papermc.generator.registry;
import com.google.common.base.Preconditions;
import io.papermc.generator.Main;
import io.papermc.generator.resources.data.RegistryData;
import io.papermc.generator.utils.ClassHelper;
import java.lang.constant.ConstantDescs;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import javax.lang.model.SourceVersion;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceKey;
import org.bukkit.Keyed;
import net.minecraft.util.StringRepresentable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
@NullMarked
public final class RegistryEntry<T> {
public class RegistryEntry<T> implements RegistryIdentifiable<T> {
private final ResourceKey<? extends Registry<T>> registryKey;
private final RegistryKeyField<T> registryKeyField;
private final Class<T> elementClass;
private final Class<?> holderElementsClass;
private boolean allowDirect;
private final Class<? extends Keyed> apiClass; // TODO remove Keyed
private Class<?> preloadClass;
private final String implClass;
private @Nullable RegistryModificationApiSupport modificationApiSupport;
private @Nullable Class<?> apiRegistryBuilder;
private @Nullable String apiRegistryBuilderImpl;
private @Nullable String fieldRename;
private boolean delayed;
private String apiAccessName = ConstantDescs.INIT_NAME;
private Optional<String> apiRegistryField = Optional.empty();
private final RegistryData data;
private @Nullable Map<ResourceKey<T>, String> fieldNames;
public RegistryEntry(ResourceKey<? extends Registry<T>> registryKey, RegistryKeyField<T> registryKeyField, Class<?> holderElementsClass, Class<? extends Keyed> apiClass, String implClass) {
protected RegistryEntry(ResourceKey<? extends Registry<T>> registryKey, RegistryKeyField<T> registryKeyField, Class<?> holderElementsClass, RegistryData data) {
this.registryKey = registryKey;
this.registryKeyField = registryKeyField;
this.elementClass = registryKeyField.elementClass();
this.holderElementsClass = holderElementsClass;
this.apiClass = apiClass;
this.preloadClass = apiClass;
this.implClass = implClass;
this.data = data;
}
public ResourceKey<? extends Registry<T>> registryKey() {
@Override
public ResourceKey<? extends Registry<T>> getRegistryKey() {
return this.registryKey;
}
@@ -62,123 +45,55 @@ public final class RegistryEntry<T> {
return Main.REGISTRY_ACCESS.lookupOrThrow(this.registryKey);
}
public Class<T> elementClass() {
return this.registryKeyField.elementClass();
}
public String registryKeyField() {
return this.registryKeyField.name();
}
public Class<? extends Keyed> apiClass() {
return this.apiClass;
public RegistryData data() {
return this.data;
}
public String implClass() {
return this.implClass;
}
public RegistryEntry<T> allowDirect() {
this.allowDirect = true;
return this;
}
public RegistryEntry<T> delayed() {
this.delayed = true;
return this;
}
public RegistryEntry<T> preload(Class<?> klass) {
this.preloadClass = klass;
return this;
}
public RegistryEntry<T> apiAccessName(String name) {
Preconditions.checkArgument(SourceVersion.isIdentifier(name) && !SourceVersion.isKeyword(name), "Invalid accessor name");
this.apiAccessName = name;
return this;
}
public RegistryEntry<T> serializationUpdater(String fieldName) {
this.fieldRename = fieldName;
return this;
}
public boolean canAllowDirect() {
return this.allowDirect;
}
public boolean isDelayed() {
return this.delayed;
}
public String apiAccessName() {
return this.apiAccessName;
}
public Class<?> preloadClass() {
return this.preloadClass;
}
public @Nullable String fieldRename() {
return this.fieldRename;
}
public @Nullable Class<?> apiRegistryBuilder() {
return this.apiRegistryBuilder;
}
public @Nullable String apiRegistryBuilderImpl() {
return this.apiRegistryBuilderImpl;
}
public @Nullable RegistryModificationApiSupport modificationApiSupport() {
return this.modificationApiSupport;
}
public RegistryEntry<T> writableApiRegistryBuilder(Class<?> builderClass, String builderImplClass) {
return this.apiRegistryBuilder(builderClass, builderImplClass, RegistryModificationApiSupport.WRITABLE);
}
public RegistryEntry<T> apiRegistryBuilder(Class<?> builderClass, String builderImplClass, RegistryModificationApiSupport modificationApiSupport) {
this.apiRegistryBuilder = builderClass;
this.apiRegistryBuilderImpl = builderImplClass;
this.modificationApiSupport = modificationApiSupport;
return this;
}
public Optional<String> apiRegistryField() {
return this.apiRegistryField;
}
public RegistryEntry<T> apiRegistryField(String registryField) {
this.apiRegistryField = Optional.of(registryField);
return this;
protected void validate(Type type) {
boolean isBuiltIn = type == Type.BUILT_IN;
Type realType = type == Type.BUILT_IN ? Type.DATA_DRIVEN : Type.BUILT_IN;
Preconditions.checkState(isBuiltIn == BuiltInRegistries.REGISTRY.containsKey(this.registryKey.location()), // type is checked at runtime and not guessed in case api/impl change is needed
"Mismatch type, registry '%s' is %s but was in registry/%s.json", this.registryKey.location(), realType.getSerializedName(), type.getSerializedName()
);
Preconditions.checkState(type != Type.BUILT_IN || !this.data.impl().delayed(), "Built-in registry '%s' cannot be delayed!", this.registryKey.location());
}
public String keyClassName() {
if (RegistryEntries.REGISTRY_CLASS_NAME_BASED_ON_API.contains(this.apiClass)) {
return this.apiClass.getSimpleName();
if (this.data.api().keyClassNameRelate()) {
return this.data.api().klass().name().simpleName();
}
return this.elementClass.getSimpleName();
return this.elementClass().getSimpleName();
}
public boolean allowCustomKeys() {
return (this.apiRegistryBuilder != null && this.modificationApiSupport.canAdd()) || RegistryEntries.DATA_DRIVEN.contains(this);
return (this.data.builder().isPresent() && this.data.builder().get().capability().canAdd()) || RegistryEntries.byType(Type.DATA_DRIVEN).contains(this);
}
private <TO> Map<ResourceKey<T>, TO> getFields(Map<ResourceKey<T>, TO> map, Function<Field, @Nullable TO> transform) {
Registry<T> registry = this.registry();
Class<T> elementClass = this.elementClass();
try {
for (Field field : this.holderElementsClass.getDeclaredFields()) {
if (!ResourceKey.class.isAssignableFrom(field.getType()) && !Holder.Reference.class.isAssignableFrom(field.getType()) && !this.elementClass.isAssignableFrom(field.getType())) {
if (!ResourceKey.class.isAssignableFrom(field.getType()) && !Holder.Reference.class.isAssignableFrom(field.getType()) && !elementClass.isAssignableFrom(field.getType())) {
continue;
}
if (ClassHelper.isStaticConstant(field, Modifier.PUBLIC)) {
ResourceKey<T> key = null;
if (this.elementClass.isAssignableFrom(field.getType())) {
key = registry.getResourceKey(this.elementClass.cast(field.get(null))).orElseThrow();
if (elementClass.isAssignableFrom(field.getType())) {
key = registry.getResourceKey(elementClass.cast(field.get(null))).orElseThrow();
} else {
if (field.getGenericType() instanceof ParameterizedType complexType && complexType.getActualTypeArguments().length == 1 &&
complexType.getActualTypeArguments()[0] == this.elementClass) {
complexType.getActualTypeArguments()[0] == elementClass) {
if (Holder.Reference.class.isAssignableFrom(field.getType())) {
key = ((Holder.Reference<T>) field.get(null)).key();
@@ -217,19 +132,23 @@ public final class RegistryEntry<T> {
return "RegistryEntry[" +
"registryKey=" + this.registryKey + ", " +
"registryKeyField=" + this.registryKeyField + ", " +
"apiClass=" + this.apiClass + ", " +
"implClass=" + this.implClass + ", " +
"data=" + this.data +
']';
}
public enum RegistryModificationApiSupport {
NONE,
ADDABLE,
MODIFIABLE,
WRITABLE;
public enum Type implements StringRepresentable {
public boolean canAdd() {
return this != MODIFIABLE && this != NONE;
BUILT_IN("built_in"),
DATA_DRIVEN("data_driven");
private final String name;
Type(String name) {
this.name = name;
}
@Override
public String getSerializedName() {
return this.name;
}
}
}

View File

@@ -0,0 +1,11 @@
package io.papermc.generator.registry;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import org.jspecify.annotations.NullMarked;
@NullMarked
public interface RegistryIdentifiable<T> {
ResourceKey<? extends Registry<T>> getRegistryKey();
}

View File

@@ -0,0 +1,22 @@
package io.papermc.generator.registry;
import io.papermc.generator.resources.data.RegistryData;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import org.jspecify.annotations.NullMarked;
@NullMarked
public record RegistryIntern<T>(ResourceKey<? extends Registry<T>> registryKey, RegistryKeyField<T> registryKeyField, Class<?> holderElementsClass) implements RegistryIdentifiable<T> {
public RegistryIntern(ResourceKey<? extends Registry<T>> registryKey, Class<?> holderElementsClass) {
this(registryKey, (RegistryKeyField<T>) RegistryEntries.REGISTRY_KEY_FIELDS.get(registryKey), holderElementsClass);
}
@Override
public ResourceKey<? extends Registry<T>> getRegistryKey() {
return this.registryKey;
}
public RegistryEntry<?> bind(RegistryData data) {
return new RegistryEntry<>(this.registryKey, this.registryKeyField, this.holderElementsClass, data);
}
}

View File

@@ -0,0 +1,182 @@
package io.papermc.generator.resources;
import com.google.gson.FormattingStyle;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.JsonOps;
import io.papermc.generator.Main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.stream.Collectors;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.jetbrains.annotations.VisibleForTesting;
public abstract class DataFile<V, A, R> {
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().setFormattingStyle(FormattingStyle.PRETTY).create();
private final String path;
protected final Codec<V> codec;
protected final DynamicOps<JsonElement> requiredOps;
private final Transmuter<V, A, R> transmuter;
private final boolean requireRegistry;
private @MonotonicNonNull V value;
protected DataFile(String path, Codec<V> codec, Transmuter<V, A, R> transmuter, boolean requireRegistry) {
this.path = path;
this.codec = codec;
this.transmuter = transmuter;
this.requireRegistry = requireRegistry;
this.requiredOps = this.getRequiredOps(JsonOps.INSTANCE);
}
protected DataFile(String path, Codec<V> codec, Transmuter<V, A, R> transmuter) {
this(path, codec, transmuter, false);
}
public V get() {
if (this.value == null) {
this.value = this.readUnchecked();
}
return this.value;
}
public V readUnchecked() {
try {
return this.read();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public V read() throws IOException {
try (Reader input = new BufferedReader(new InputStreamReader(DataFile.class.getClassLoader().getResourceAsStream(this.path)))) {
JsonElement predicates = GSON.fromJson(input, JsonElement.class);
return this.codec.parse(this.requiredOps, predicates).getOrThrow(JsonParseException::new);
}
}
public SliceResult<A, R> slice(){
return this.transmuter.examine(this.get());
}
public SliceResult<A, R> upgrade(Path destination) throws IOException {
if (!(this.transmuter instanceof Transmuter.Mutable<V, A, R> mutableTransmuter)) {
return SliceResult.empty();
}
SliceResult<A, R> result = this.slice();
this.value = mutableTransmuter.apply(this.value, result);
Files.writeString(destination, this.toJsonString(this.value) + "\n", StandardCharsets.UTF_8);
return result;
}
public String toJsonString(V value) {
JsonElement element = this.codec.encodeStart(this.requiredOps, value).getOrThrow();
return GSON.toJson(element);
}
public abstract FlattenSliceResult<String, String> print(SliceResult<A, R> result);
public String path() {
return this.path;
}
@VisibleForTesting
public Codec<V> codec() {
return this.codec;
}
@VisibleForTesting
public <T> DynamicOps<T> getRequiredOps(DynamicOps<T> ops) {
if (this.requireRegistry) {
return Main.REGISTRY_ACCESS.createSerializationContext(ops);
}
return ops;
}
@Override
public String toString() {
return "DataFile[path=" + this.path + ']';
}
public static class Map<K, V> extends DataFile<java.util.Map<K, V>, java.util.Map.Entry<K, V>, K> {
public Map(String path, Codec<java.util.Map<K, V>> codec, Transmuter<java.util.Map<K, V>, java.util.Map.Entry<K, V>, K> transmuter, boolean requireRegistry) {
super(path, codec, transmuter, requireRegistry);
}
public Map(String path, Codec<java.util.Map<K, V>> codec, Transmuter<java.util.Map<K, V>, java.util.Map.Entry<K, V>, K> transmuter) {
super(path, codec, transmuter);
}
@Override
public FlattenSliceResult<String, String> print(SliceResult<java.util.Map.Entry<K, V>, K> result) {
String newEntries = null;
String dropEntries = null;
if (!result.added().isEmpty()) {
java.util.Map<K, V> added = result.added().stream().collect(Collectors.toMap(java.util.Map.Entry::getKey, java.util.Map.Entry::getValue));
newEntries = this.toJsonString(added);
}
if (!result.removed().isEmpty()) {
java.util.Map<K, V> removed = new HashMap<>(result.removed().size());
result.removed().forEach(key -> removed.put(key, null));
JsonElement dropElement = this.codec.encodeStart(this.requiredOps, removed).getOrThrow();
if (dropElement instanceof JsonObject object) {
JsonArray array = new JsonArray(object.size());
for (String key : object.keySet()) {
array.add(key);
}
dropEntries = GSON.toJson(array);
}
}
return new FlattenSliceResult<>(
newEntries,
dropEntries
);
}
}
public static class List<E> extends DataFile<java.util.List<E>, E, E> {
public List(String path, Codec<java.util.List<E>> codec, Transmuter<java.util.List<E>, E, E> transmuter, boolean requireRegistry) {
super(path, codec, transmuter, requireRegistry);
}
public List(String path, Codec<java.util.List<E>> codec, Transmuter<java.util.List<E>, E, E> transmuter) {
super(path, codec, transmuter);
}
@Override
public FlattenSliceResult<String, String> print(SliceResult<E, E> result) {
String newEntries = null;
String dropEntries = null;
if (!result.added().isEmpty()) {
newEntries = this.toJsonString(java.util.List.copyOf(result.added()));
}
if (!result.removed().isEmpty()) {
dropEntries = this.toJsonString(java.util.List.copyOf(result.removed()));
}
return new FlattenSliceResult<>(
newEntries,
dropEntries
);
}
}
}

View File

@@ -0,0 +1,218 @@
package io.papermc.generator.resources;
import com.google.common.base.Suppliers;
import com.google.common.collect.Sets;
import com.google.common.reflect.TypeToken;
import com.mojang.serialization.Codec;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ScanResult;
import io.papermc.generator.registry.RegistryEntries;
import io.papermc.generator.registry.RegistryEntry;
import io.papermc.generator.resources.data.EntityClassData;
import io.papermc.generator.resources.data.EntityTypeData;
import io.papermc.generator.resources.data.ItemMetaData;
import io.papermc.generator.resources.data.RegistryData;
import io.papermc.generator.resources.predicate.BlockPredicate;
import io.papermc.generator.resources.predicate.ItemPredicate;
import io.papermc.generator.utils.BasePackage;
import io.papermc.generator.utils.ClassHelper;
import io.papermc.generator.utils.Formatting;
import io.papermc.generator.utils.SourceCodecs;
import io.papermc.typewriter.ClassNamed;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import net.minecraft.Util;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.vehicle.AbstractBoat;
import net.minecraft.world.entity.vehicle.AbstractMinecart;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
public class DataFileLoader {
private static <K, V> Transmuter<Map<K, V>, Map.Entry<K, V>, K> sortedMap(Comparator<K> comparator) {
return transmuteMap(SliceResult::empty, comparator);
}
private static <K, V> Transmuter<Map<K, V>, Map.Entry<K, V>, K> transmuteMap(Supplier<Set<K>> typesProvider, Function<K, V> onMissing, Comparator<K> comparator) {
return transmuteMap(map -> {
Set<K> types = typesProvider.get();
Set<K> registeredTypes = map.keySet();
Set<Map.Entry<K, V>> added = new HashSet<>();
Sets.difference(types, registeredTypes).forEach(missingType -> added.add(Map.entry(missingType, onMissing.apply(missingType))));
Set<K> removed = new HashSet<>(Sets.difference(registeredTypes, types));
return new SliceResult<>(added, removed);
}, comparator);
}
private static <K, V> Transmuter<Map<K, V>, Map.Entry<K, V>, K> transmuteMap(Function<Map<K, V>, SliceResult<Map.Entry<K, V>, K>> slicer, Comparator<K> comparator) {
return new Transmuter.Mutable<>() {
@Override
public SliceResult<Map.Entry<K, V>, K> examine(Map<K, V> original) {
return slicer.apply(original);
}
@Override
public Map<K, V> apply(Map<K, V> original, SliceResult<Map.Entry<K, V>, K> result) {
Map<K, V> map = new TreeMap<>(comparator);
map.putAll(original);
result.added().forEach(entry -> map.put(entry.getKey(), entry.getValue()));
result.removed().forEach(map::remove);
return map;
}
};
}
private static final @MonotonicNonNull Map<ResourceKey<? extends DataFile<?, ?, ?>>, DataFile<?, ?, ?>> DATA_FILES = new HashMap<>();
public static final @MonotonicNonNull Map<ResourceKey<? extends DataFile<?, ?, ?>>, DataFile<?, ?, ?>> DATA_FILES_VIEW = Collections.unmodifiableMap(DATA_FILES);
private static final Supplier<Map<ResourceKey<EntityType<?>>, Class<?>>> ENTITY_TYPE_GENERICS = Suppliers.memoize(() -> RegistryEntries.byRegistryKey(Registries.ENTITY_TYPE).getFields(field -> {
if (field.getGenericType() instanceof ParameterizedType complexType && complexType.getActualTypeArguments().length == 1) {
return (Class<?>) complexType.getActualTypeArguments()[0];
}
return null;
}));
public static final Map<RegistryEntry.Type, DataFile.Map<ResourceKey<? extends Registry<?>>, RegistryData>> REGISTRIES = Collections.unmodifiableMap(Util.make(new EnumMap<>(RegistryEntry.Type.class), map -> {
Codec<Map<ResourceKey<? extends Registry<?>>, RegistryData>> codec = Codec.lazyInitialized(() -> Codec.unboundedMap(SourceCodecs.REGISTRY_KEY, RegistryData.CODEC));
for (RegistryEntry.Type type : RegistryEntry.Type.values()) {
ResourceKey<DataFile.Map<ResourceKey<? extends Registry<?>>, RegistryData>> key = DataFiles.registry(type);
map.put(type, register(key, path -> {
return new DataFile.Map<>(path, codec, SliceResult::empty);
}));
}
}));
static {
// todo remove Orientation once the duplicate enum is gone and then possibly check enum property types conflict instead
register(DataFiles.BLOCK_STATE_AMBIGUOUS_NAMES, () -> Codec.unboundedMap(
SourceCodecs.IDENTIFIER, ExtraCodecs.nonEmptyList(SourceCodecs.IDENTIFIER.listOf())
),
(path, codec) -> new DataFile.Map<>(
path, codec, SliceResult::empty
));
register(DataFiles.BLOCK_STATE_ENUM_PROPERTY_TYPES, () -> Codec.unboundedMap(
SourceCodecs.classCodec(new TypeToken<Enum<? extends StringRepresentable>>() {}), SourceCodecs.CLASS_NAME
),
(path, codec) -> new DataFile.Map<>(
path, codec,
transmuteMap(() -> {
try {
Set<Class<? extends Enum<? extends StringRepresentable>>> enumPropertyTypes = Collections.newSetFromMap(new IdentityHashMap<>());
for (Field field : BlockStateProperties.class.getDeclaredFields()) {
if (ClassHelper.isStaticConstant(field, Modifier.PUBLIC)) {
if (!EnumProperty.class.isAssignableFrom(field.getType())) {
continue;
}
enumPropertyTypes.add(((EnumProperty<?>) field.get(null)).getValueClass());
}
}
return Collections.unmodifiableSet(enumPropertyTypes);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
},
missingType -> BasePackage.BUKKIT.relativeClass("block.data.type", missingType.getSimpleName()),
Comparator.comparing(Class::getCanonicalName))
));
// order matters: instance_of / is_class -> has_property -> contains_property
register(DataFiles.BLOCK_STATE_PREDICATES, () -> Codec.unboundedMap(
SourceCodecs.CLASS_NAMED, ExtraCodecs.compactListCodec(BlockPredicate.CODEC, ExtraCodecs.nonEmptyList(BlockPredicate.CODEC.listOf()))
),
(path, codec) -> new DataFile.Map<>(
path, codec, SliceResult::empty
));
register(DataFiles.ITEM_META_BRIDGE, () -> Codec.unboundedMap(SourceCodecs.CLASS_NAMED, ItemMetaData.CODEC),
(path, codec) -> new DataFile.Map<>(
path, codec, sortedMap(Comparator.comparing(ClassNamed::canonicalName))
));
// order matters
register(DataFiles.ITEM_META_PREDICATES, () -> Codec.unboundedMap(
SourceCodecs.CLASS_NAMED, ExtraCodecs.nonEmptyList(ItemPredicate.CODEC.listOf())
),
(path, codec) -> new DataFile.Map<>(
path, codec, SliceResult::empty, true
));
register(DataFiles.ENTITY_TYPES, () -> Codec.unboundedMap(ResourceKey.codec(Registries.ENTITY_TYPE), EntityTypeData.CODEC),
(path, codec) -> new DataFile.Map<>(
path, codec,
transmuteMap(() -> BuiltInRegistries.ENTITY_TYPE.listElementIds().collect(Collectors.toSet()),
missingType -> {
Class<?> genericType = ENTITY_TYPE_GENERICS.get().get(missingType);
String packageName = BasePackage.BUKKIT.name().concat(".entity");
if (AbstractBoat.class.isAssignableFrom(genericType)) {
packageName += ".boat";
} else if (AbstractMinecart.class.isAssignableFrom(genericType)) {
packageName += ".minecart";
}
return new EntityTypeData(ClassNamed.of(packageName, genericType.getSimpleName()));
},
Formatting.alphabeticKeyOrder(key -> key.location().getPath()))
));
register(DataFiles.ENTITY_CLASS_NAMES, () -> Codec.unboundedMap(SourceCodecs.classCodec(Mob.class), EntityClassData.CODEC),
(path, codec) -> new DataFile.Map<>(
path, codec,
transmuteMap(() -> {
try (ScanResult scanResult = new ClassGraph().enableClassInfo().acceptPackages(Entity.class.getPackageName()).scan()) {
Set<Class<? extends Mob>> classes = new HashSet<>(scanResult.getSubclasses(Mob.class.getName()).loadClasses(Mob.class));
if (classes.isEmpty()) {
throw new IllegalStateException("There are supposed to be more than 0 mob classes!");
}
classes.add(Mob.class);
return Collections.unmodifiableSet(classes);
}
},
missingType -> new EntityClassData(BasePackage.BUKKIT.relativeClass("entity", missingType.getSimpleName())),
Comparator.comparing(Class::getCanonicalName))
));
}
public static <V, A, R> V get(ResourceKey<? extends DataFile<V, A, R>> key) {
return ((DataFile<V, A, R>) DATA_FILES.get(key)).get();
}
private static <V, A, R> void register(ResourceKey<? extends DataFile<V, A, R>> key, Supplier<Codec<V>> codec, BiFunction<String, Codec<V>, DataFile<V, A, R>> maker) {
register(key, path -> maker.apply(path, Codec.lazyInitialized(codec)));
}
private static <F extends DataFile<?, ?, ?>> F register(ResourceKey<? extends F> key, Function<String, F> maker) {
F file = maker.apply("data/%s.json".formatted(key.location().getPath()));
DATA_FILES.put(key, file);
return file;
}
}

View File

@@ -0,0 +1,44 @@
package io.papermc.generator.resources;
import com.squareup.javapoet.ClassName;
import io.papermc.generator.registry.RegistryEntry;
import io.papermc.generator.resources.data.EntityClassData;
import io.papermc.generator.resources.data.EntityTypeData;
import io.papermc.generator.resources.data.ItemMetaData;
import io.papermc.generator.resources.data.RegistryData;
import io.papermc.generator.resources.predicate.BlockPredicate;
import io.papermc.generator.resources.predicate.ItemPredicate;
import io.papermc.typewriter.ClassNamed;
import java.util.List;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
public final class DataFiles {
private static final ResourceKey<Registry<DataFile<?, ?, ?>>> REGISTRY_KEY = ResourceKey.createRegistryKey(ResourceLocation.fromNamespaceAndPath("paper", "data_file"));
public static final ResourceKey<DataFile.Map<String, List<String>>> BLOCK_STATE_AMBIGUOUS_NAMES = store("block_state/ambiguous_names");
public static final ResourceKey<DataFile.Map<Class<? extends Enum<? extends StringRepresentable>>, ClassName>> BLOCK_STATE_ENUM_PROPERTY_TYPES = store("block_state/enum_property_types");
public static final ResourceKey<DataFile.Map<ClassNamed, List<BlockPredicate>>> BLOCK_STATE_PREDICATES = store("block_state/predicates");
public static final ResourceKey<DataFile.Map<ClassNamed, ItemMetaData>> ITEM_META_BRIDGE = store("item_meta/bridge");
public static final ResourceKey<DataFile.Map<ClassNamed, List<ItemPredicate>>> ITEM_META_PREDICATES = store("item_meta/predicates");
public static ResourceKey<DataFile.Map<ResourceKey<? extends Registry<?>>, RegistryData>> registry(RegistryEntry.Type type) {
return store("registry/%s".formatted(type.getSerializedName()));
}
public static final ResourceKey<DataFile.Map<ResourceKey<EntityType<?>>, EntityTypeData>> ENTITY_TYPES = store("entity_types");
public static final ResourceKey<DataFile.Map<Class<? extends Mob>, EntityClassData>> ENTITY_CLASS_NAMES = store("entity_class_names");
private static <T extends DataFile<?, ?, ?>> ResourceKey<T> store(String name) {
return (ResourceKey<T>) ResourceKey.create(REGISTRY_KEY, ResourceLocation.fromNamespaceAndPath("paper", name));
}
private DataFiles() {
}
}

View File

@@ -0,0 +1,6 @@
package io.papermc.generator.resources;
import org.jspecify.annotations.Nullable;
public record FlattenSliceResult<A, R>(@Nullable A added, @Nullable R removed) {
}

View File

@@ -0,0 +1,99 @@
package io.papermc.generator.resources;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.WildcardTypeName;
import io.papermc.generator.types.Types;
import io.papermc.generator.utils.SourceCodecs;
import io.papermc.typewriter.ClassNamed;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Function;
import net.minecraft.util.ExtraCodecs;
public record ParameterizedClass(ClassNamed klass, List<ParameterizedClass> arguments) {
public ParameterizedClass(ClassNamed value) {
this(value, List.of());
}
private static Codec<ParameterizedClass> directCodec(Codec<ParameterizedClass> codec) {
return RecordCodecBuilder.create(instance -> instance.group(
SourceCodecs.CLASS_NAMED.fieldOf("class").forGetter(ParameterizedClass::klass),
ExtraCodecs.compactListCodec(codec).optionalFieldOf("arguments", List.of()).forGetter(ParameterizedClass::arguments)
).apply(instance, ParameterizedClass::new));
}
public static final Codec<ParameterizedClass> CLASS_ONLY_CODEC = SourceCodecs.CLASS_NAMED.xmap(ParameterizedClass::new, ParameterizedClass::klass);
public static final Codec<ParameterizedClass> CODEC = Codec.recursive("ParameterizedClass", codec -> {
return Codec.either(CLASS_ONLY_CODEC, directCodec(codec)).xmap(Either::unwrap, parameterizedClass -> {
if (parameterizedClass.arguments().isEmpty()) {
return Either.left(parameterizedClass);
}
return Either.right(parameterizedClass);
});
});
public TypeName getType() {
ClassName rawType = Types.typed(this.klass);
if (!this.arguments.isEmpty()) {
List<TypeName> convertedArgs = new ArrayList<>(this.arguments.size());
for (ParameterizedClass argument : this.arguments) {
convertedArgs.add(argument.getType());
}
return ParameterizedTypeName.get(rawType, convertedArgs.toArray(TypeName[]::new));
}
return rawType;
}
public void appendType(StringBuilder builder, Function<ClassNamed, String> imported) {
builder.append(imported.apply(this.klass));
if (!this.arguments.isEmpty()) {
builder.append('<');
for (ParameterizedClass argument : this.arguments) {
argument.appendType(builder, imported);
}
builder.append('>');
}
}
public static TypeName getAsWildcardType(ClassName rawType, List<ParameterizedClass> wildcardClasses) {
if (!wildcardClasses.isEmpty()) {
TypeName[] wildcards = new TypeName[wildcardClasses.size()];
for (int i = 0; i < wildcardClasses.size(); i ++) {
wildcards[i] = WildcardTypeName.subtypeOf(wildcardClasses.get(i).getType());
}
return ParameterizedTypeName.get(rawType, wildcards);
}
return rawType;
}
public static void appendAsWildcardType(StringBuilder builder, ClassNamed rawType, List<ParameterizedClass> wildcardClasses, Function<ClassNamed, String> imported) {
builder.append(imported.apply(rawType));
int size = wildcardClasses.size();
if (size != 0) {
builder.append('<');
Iterator<ParameterizedClass> iterator = wildcardClasses.iterator();
while (iterator.hasNext()) {
ParameterizedClass wildcard = iterator.next();
if (wildcard.arguments().isEmpty() && wildcard.klass().canonicalName().equals(Object.class.getCanonicalName())) {
builder.append('?');
} else {
builder.append("? extends ");
wildcard.appendType(builder, imported);
}
if (iterator.hasNext()) {
builder.append(", ");
}
}
builder.append('>');
}
}
}

View File

@@ -0,0 +1,19 @@
package io.papermc.generator.resources;
import java.util.Collections;
import java.util.Set;
public record SliceResult<A, R>(Set<A> added, Set<R> removed) {
static <A, R> SliceResult<A, R> empty() {
return new SliceResult<>(Collections.emptySet(), Collections.emptySet());
}
static <V, A, R> SliceResult<A, R> empty(V value) {
return empty();
}
public boolean isEmpty() {
return this.added.isEmpty() && this.removed.isEmpty();
}
}

View File

@@ -0,0 +1,11 @@
package io.papermc.generator.resources;
public interface Transmuter<V, A, R> {
SliceResult<A, R> examine(V original);
interface Mutable<V, A, R> extends Transmuter<V, A, R> {
V apply(V original, SliceResult<A, R> result);
}
}

View File

@@ -0,0 +1,28 @@
package io.papermc.generator.resources.data;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import com.squareup.javapoet.ClassName;
import io.papermc.generator.utils.SourceCodecs;
public record EntityClassData(ClassName name, boolean hasSpecifier) {
public EntityClassData(ClassName name) {
this(name, true);
}
public static final Codec<EntityClassData> DIRECT_CODEC = RecordCodecBuilder.create(instance -> instance.group(
SourceCodecs.CLASS_NAME.fieldOf("name").forGetter(EntityClassData::name),
Codec.BOOL.optionalFieldOf("has_specifier", true).forGetter(EntityClassData::hasSpecifier)
).apply(instance, EntityClassData::new));
private static final Codec<EntityClassData> CLASS_ONLY_CODEC = SourceCodecs.CLASS_NAME.xmap(EntityClassData::new, EntityClassData::name);
public static final Codec<EntityClassData> CODEC = Codec.either(CLASS_ONLY_CODEC, DIRECT_CODEC).xmap(Either::unwrap, data -> {
if (!data.hasSpecifier()) {
return Either.right(data);
}
return Either.left(data);
});
}

View File

@@ -0,0 +1,31 @@
package io.papermc.generator.resources.data;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.papermc.generator.utils.SourceCodecs;
import io.papermc.typewriter.ClassNamed;
import net.minecraft.util.ExtraCodecs;
public record EntityTypeData(ClassNamed api, int legacyId) {
private static final int NO_LEGACY_ID = -1;
public EntityTypeData(ClassNamed api) {
this(api, NO_LEGACY_ID);
}
public static final Codec<EntityTypeData> DIRECT_CODEC = RecordCodecBuilder.create(instance -> instance.group(
SourceCodecs.CLASS_NAMED.fieldOf("api").forGetter(EntityTypeData::api),
ExtraCodecs.intRange(-1, Integer.MAX_VALUE).optionalFieldOf("legacy_id", NO_LEGACY_ID).deprecated(13).forGetter(EntityTypeData::legacyId)
).apply(instance, EntityTypeData::new));
private static final Codec<EntityTypeData> CLASS_ONLY_CODEC = SourceCodecs.CLASS_NAMED.xmap(EntityTypeData::new, EntityTypeData::api);
public static final Codec<EntityTypeData> CODEC = Codec.either(CLASS_ONLY_CODEC, DIRECT_CODEC).xmap(Either::unwrap, data -> {
if (data.legacyId() != NO_LEGACY_ID) {
return Either.right(data);
}
return Either.left(data);
});
}

View File

@@ -0,0 +1,15 @@
package io.papermc.generator.resources.data;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.papermc.generator.utils.SourceCodecs;
import io.papermc.typewriter.ClassNamed;
@Deprecated
public record ItemMetaData(ClassNamed api, String field) {
public static final Codec<ItemMetaData> CODEC = RecordCodecBuilder.create(instance -> instance.group(
SourceCodecs.CLASS_NAMED.fieldOf("api").forGetter(ItemMetaData::api),
SourceCodecs.IDENTIFIER.fieldOf("field").forGetter(ItemMetaData::field)
).apply(instance, ItemMetaData::new));
}

View File

@@ -0,0 +1,160 @@
package io.papermc.generator.resources.data;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import com.squareup.javapoet.TypeName;
import io.papermc.generator.resources.ParameterizedClass;
import io.papermc.generator.types.Types;
import io.papermc.generator.utils.SourceCodecs;
import io.papermc.typewriter.ClassNamed;
import java.lang.constant.ConstantDescs;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.StringRepresentable;
public record RegistryData(
Api api,
Impl impl,
Optional<Builder> builder,
Optional<String> serializationUpdaterField,
boolean allowInline
) {
public static final Codec<RegistryData> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Api.CODEC.fieldOf("api").forGetter(RegistryData::api),
Impl.CODEC.fieldOf("impl").forGetter(RegistryData::impl),
Builder.CODEC.optionalFieldOf("builder").forGetter(RegistryData::builder),
SourceCodecs.IDENTIFIER.optionalFieldOf("serialization_updater_field").forGetter(RegistryData::serializationUpdaterField),
Codec.BOOL.optionalFieldOf("allow_inline", false).forGetter(RegistryData::allowInline)
).apply(instance, RegistryData::new));
public record Api(Class klass, Optional<HolderClass> holderClass, boolean keyClassNameRelate, Optional<String> registryField) {
public Api(ClassNamed klass) {
this(new Class(klass), Optional.of(new HolderClass(klass)), false, Optional.empty());
}
public static final Codec<Api> DIRECT_CODEC = RecordCodecBuilder.create(instance -> instance.group(
Class.CODEC.fieldOf("class").forGetter(Api::klass),
HolderClass.CODEC.optionalFieldOf("holder_class").forGetter(Api::holderClass),
Codec.BOOL.optionalFieldOf("key_class_name_relate", false).forGetter(Api::keyClassNameRelate),
SourceCodecs.IDENTIFIER.optionalFieldOf("registry_field").forGetter(Api::registryField)
).apply(instance, Api::new));
public static final Codec<Api> CLASS_ONLY_CODEC = SourceCodecs.CLASS_NAMED.xmap(Api::new, api -> api.klass().name());
public static final Codec<Api> CODEC = Codec.either(CLASS_ONLY_CODEC, DIRECT_CODEC).xmap(Either::unwrap, api -> {
if ((api.holderClass().isEmpty() ||
(api.holderClass().get().name().isEmpty() || api.klass().name().equals(api.holderClass().get().name().get()) && api.holderClass().get().isInterface())) &&
!api.klass().legacyEnum() && api.klass().wildcards().isEmpty() &&
!api.keyClassNameRelate() && api.registryField().isEmpty()) {
return Either.left(api);
}
return Either.right(api);
});
public record Class(ClassNamed name, List<ParameterizedClass> wildcards, boolean legacyEnum) {
public Class(ClassNamed name) {
this(name, List.of(), false);
}
public static final Codec<Class> DIRECT_CODEC = RecordCodecBuilder.create(instance -> instance.group(
SourceCodecs.CLASS_NAMED.fieldOf("name").forGetter(Class::name),
ExtraCodecs.compactListCodec(ParameterizedClass.CODEC).optionalFieldOf("wildcards", List.of()).forGetter(Class::wildcards),
Codec.BOOL.optionalFieldOf("legacy_enum", false).deprecated(8).forGetter(Class::legacyEnum)
).apply(instance, Class::new));
public static final Codec<Class> CLASS_ONLY_CODEC = SourceCodecs.CLASS_NAMED.xmap(Class::new, Class::name);
public static final Codec<Class> CODEC = Codec.either(CLASS_ONLY_CODEC, DIRECT_CODEC).xmap(Either::unwrap, api -> {
if (!api.legacyEnum() && api.wildcards().isEmpty()) {
return Either.left(api);
}
return Either.right(api);
});
public TypeName getType() {
return ParameterizedClass.getAsWildcardType(Types.typed(this.name), this.wildcards);
}
public void appendType(StringBuilder builder, Function<ClassNamed, String> imported) {
ParameterizedClass.appendAsWildcardType(builder, this.name, this.wildcards, imported);
}
}
public record HolderClass(Optional<ClassNamed> name, boolean isInterface) {
public HolderClass(ClassNamed name) {
this(Optional.of(name), true);
}
public static final Codec<HolderClass> CODEC = RecordCodecBuilder.create(instance -> instance.group(
SourceCodecs.CLASS_NAMED.optionalFieldOf("name").forGetter(HolderClass::name),
Codec.BOOL.optionalFieldOf("is_interface", true).forGetter(HolderClass::isInterface)
).apply(instance, HolderClass::new));
}
}
public record Impl(ClassNamed klass, String instanceMethod, boolean delayed) {
public Impl(ClassNamed klass) {
this(klass, ConstantDescs.INIT_NAME, false);
}
public static final Codec<Impl> DIRECT_CODEC = RecordCodecBuilder.create(instance -> instance.group(
SourceCodecs.CLASS_NAMED.fieldOf("class").forGetter(Impl::klass),
SourceCodecs.IDENTIFIER.optionalFieldOf("instance_method", ConstantDescs.INIT_NAME).forGetter(Impl::instanceMethod),
Codec.BOOL.optionalFieldOf("delayed", false).deprecated(21).forGetter(Impl::delayed)
).apply(instance, Impl::new));
public static final Codec<Impl> CLASS_ONLY_CODEC = SourceCodecs.CLASS_NAMED.xmap(Impl::new, Impl::klass);
public static final Codec<Impl> CODEC = Codec.either(CLASS_ONLY_CODEC, DIRECT_CODEC).xmap(Either::unwrap, impl -> {
if (impl.instanceMethod().equals(ConstantDescs.INIT_NAME) && !impl.delayed()) {
return Either.left(impl);
}
return Either.right(impl);
});
}
public record Builder(ClassNamed api, ClassNamed impl, List<ParameterizedClass> wildcards, RegisterCapability capability) {
public static final Codec<Builder> CODEC = RecordCodecBuilder.create(instance -> instance.group(
SourceCodecs.CLASS_NAMED.fieldOf("api").forGetter(Builder::api),
SourceCodecs.CLASS_NAMED.fieldOf("impl").forGetter(Builder::impl),
ExtraCodecs.compactListCodec(ParameterizedClass.CODEC).optionalFieldOf("wildcards", List.of()).forGetter(Builder::wildcards),
RegisterCapability.CODEC.optionalFieldOf("capability", RegisterCapability.WRITABLE).forGetter(Builder::capability)
).apply(instance, Builder::new));
public TypeName getApiType() {
return ParameterizedClass.getAsWildcardType(Types.typed(this.api), this.wildcards);
}
public void appendApiType(StringBuilder builder, Function<ClassNamed, String> imported) {
ParameterizedClass.appendAsWildcardType(builder, this.api, this.wildcards, imported);
}
public enum RegisterCapability implements StringRepresentable {
NONE("none"),
ADDABLE("addable"),
MODIFIABLE("modifiable"),
WRITABLE("writable");
private final String name;
static final Codec<RegisterCapability> CODEC = StringRepresentable.fromEnum(RegisterCapability::values);
RegisterCapability(String name) {
this.name = name;
}
public boolean canAdd() {
return this != MODIFIABLE && this != NONE;
}
@Override
public String getSerializedName() {
return this.name;
}
}
}
}

View File

@@ -0,0 +1,4 @@
@NullMarked
package io.papermc.generator.resources;
import org.jspecify.annotations.NullMarked;

View File

@@ -0,0 +1,146 @@
package io.papermc.generator.resources.predicate;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.papermc.generator.utils.SourceCodecs;
import java.util.List;
import java.util.Set;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.properties.Property;
import org.jspecify.annotations.NullMarked;
@NullMarked
public sealed interface BlockPredicate permits BlockPredicate.ContainsPropertyPredicate, BlockPredicate.InstanceOfPredicate, BlockPredicate.IsClassPredicate {
Codec<BlockPredicate> CODEC = Type.CODEC.dispatch("type", BlockPredicate::type, type -> type.codec);
Type type();
enum Type implements StringRepresentable {
INSTANCE_OF("instance_of", InstanceOfPredicate.CODEC),
IS_CLASS("is_class", IsClassPredicate.CODEC),
HAS_PROPERTY("has_property", ContainsPropertyPredicate.SINGLE_CODEC),
CONTAINS_PROPERTY("contains_property", ContainsPropertyPredicate.CODEC);
public static final Codec<Type> CODEC = StringRepresentable.fromValues(Type::values);
private final String name;
final MapCodec<? extends BlockPredicate> codec;
Type(final String name, final MapCodec<? extends BlockPredicate> codec) {
this.name = name;
this.codec = codec;
}
@Override
public String getSerializedName() {
return this.name;
}
}
boolean matches(Class<? extends Block> block, Set<Property<?>> properties);
record IsClassPredicate(Class<? extends Block> value) implements BlockPredicate {
public static final MapCodec<IsClassPredicate> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
SourceCodecs.classCodec(Block.class).fieldOf("value").forGetter(IsClassPredicate::value)
).apply(instance, IsClassPredicate::new));
@Override
public Type type() {
return Type.IS_CLASS;
}
@Override
public boolean matches(Class<? extends Block> block, Set<Property<?>> properties) {
return this.value.equals(block);
}
}
record InstanceOfPredicate(Class<? extends Block> value, List<BlockPropertyPredicate> propertyPredicates) implements BlockPredicate {
public static final MapCodec<InstanceOfPredicate> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
SourceCodecs.classCodec(Block.class).fieldOf("value").forGetter(InstanceOfPredicate::value),
ExtraCodecs.compactListCodec(BlockPropertyPredicate.CODEC).optionalFieldOf("has_property", List.of()).forGetter(InstanceOfPredicate::propertyPredicates)
).apply(instance, InstanceOfPredicate::new));
@Override
public Type type() {
return Type.INSTANCE_OF;
}
@Override
public boolean matches(Class<? extends Block> block, Set<Property<?>> properties) {
if (!this.value.isAssignableFrom(block)) {
return false;
}
if (this.propertyPredicates.isEmpty()) {
return true;
}
for (BlockPropertyPredicate predicate : this.propertyPredicates) {
for (Property<?> property : properties) {
if (predicate.matches(property)) {
return true;
}
}
}
return false;
}
}
record ContainsPropertyPredicate(List<BlockPropertyPredicate> value, int count, Strategy strategy) implements BlockPredicate {
public static final MapCodec<ContainsPropertyPredicate> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
ExtraCodecs.nonEmptyList(BlockPropertyPredicate.CODEC.listOf()).fieldOf("value").forGetter(ContainsPropertyPredicate::value),
ExtraCodecs.POSITIVE_INT.fieldOf("count").forGetter(ContainsPropertyPredicate::count),
Strategy.CODEC.fieldOf("strategy").forGetter(ContainsPropertyPredicate::strategy)
).apply(instance, ContainsPropertyPredicate::new));
public static final MapCodec<ContainsPropertyPredicate> SINGLE_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
ExtraCodecs.compactListCodec(BlockPropertyPredicate.CODEC, ExtraCodecs.nonEmptyList(BlockPropertyPredicate.CODEC.listOf())).fieldOf("value").forGetter(ContainsPropertyPredicate::value)
).apply(instance, value -> new ContainsPropertyPredicate(value, 1, Strategy.AT_LEAST)));
@Override
public Type type() {
return Type.CONTAINS_PROPERTY;
}
@Override
public boolean matches(Class<? extends Block> block, Set<Property<?>> properties) {
int found = 0;
for (BlockPropertyPredicate predicate : this.value) {
for (Property<?> property : properties) {
if (predicate.matches(property)) {
found++;
if (this.strategy == Strategy.AT_LEAST && found == this.count) {
return true;
}
}
}
}
return this.strategy == Strategy.EXACT && found == this.count;
}
public enum Strategy implements StringRepresentable {
EXACT("exact"),
AT_LEAST("at_least");
private final String name;
static final Codec<Strategy> CODEC = StringRepresentable.fromEnum(Strategy::values);
Strategy(String name) {
this.name = name;
}
@Override
public String getSerializedName() {
return this.name;
}
}
}
}

View File

@@ -0,0 +1,112 @@
package io.papermc.generator.resources.predicate;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.papermc.generator.utils.BlockStateMapping;
import io.papermc.generator.utils.SourceCodecs;
import java.util.function.Predicate;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.Property;
import org.jspecify.annotations.NullMarked;
@NullMarked
public sealed interface BlockPropertyPredicate permits BlockPropertyPredicate.IsFieldPredicate, BlockPropertyPredicate.IsNamePredicate {
Codec<BlockPropertyPredicate> DIRECT_CODEC = Type.CODEC.dispatch("type", BlockPropertyPredicate::type, type -> type.codec);
Codec<BlockPropertyPredicate> COMPACT_CODEC = Codec.withAlternative(IsFieldPredicate.COMPACT_CODEC, IsNamePredicate.COMPACT_CODEC);
Codec<BlockPropertyPredicate> CODEC = Codec.withAlternative(DIRECT_CODEC, COMPACT_CODEC);
String value();
Type type();
enum Type implements StringRepresentable {
IS_FIELD("is_field", IsFieldPredicate.CODEC),
IS_NAME("is_name", IsNamePredicate.CODEC);
public static final Codec<Type> CODEC = StringRepresentable.fromValues(Type::values);
private final String name;
final MapCodec<? extends BlockPropertyPredicate> codec;
Type(final String name, final MapCodec<? extends BlockPropertyPredicate> codec) {
this.name = name;
this.codec = codec;
}
@Override
public String getSerializedName() {
return this.name;
}
}
boolean matches(Property<?> property);
static boolean testProperty(Predicate<String> predicate, String id, boolean supportInversion) {
// expand if needed with proper support + AND/OR-ed
if (supportInversion && id.charAt(0) == '!') {
return !predicate.test(id.substring(1));
}
return predicate.test(id);
}
record IsNamePredicate(String value) implements BlockPropertyPredicate {
private static final Codec<String> PROPERTY_NAME = ExtraCodecs.RESOURCE_PATH_CODEC
.comapFlatMap(name -> {
if (!BlockStateMapping.PROPERTY_NAMES.contains(name)) {
return DataResult.error(() -> "Invalid property name: '%s'".formatted(name));
}
return DataResult.success(name);
}, name -> name);
public static final MapCodec<IsNamePredicate> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
PROPERTY_NAME.fieldOf("value").forGetter(IsNamePredicate::value)
).apply(instance, IsNamePredicate::new));
public static final Codec<BlockPropertyPredicate> COMPACT_CODEC = PROPERTY_NAME.xmap(IsNamePredicate::new, BlockPropertyPredicate::value);
@Override
public Type type() {
return Type.IS_NAME;
}
@Override
public boolean matches(Property<?> property) {
return BlockPropertyPredicate.testProperty(
name -> name.equals(property.getName()),
this.value,
false
);
}
}
record IsFieldPredicate(String value) implements BlockPropertyPredicate {
public static final MapCodec<IsFieldPredicate> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
SourceCodecs.fieldNameCodec(BlockStateProperties.class, BlockStateMapping.GENERIC_FIELD_NAMES::containsValue).fieldOf("value").forGetter(IsFieldPredicate::value)
).apply(instance, IsFieldPredicate::new));
public static final Codec<BlockPropertyPredicate> COMPACT_CODEC = SourceCodecs.fieldCodec(
BlockStateProperties.class, BlockStateMapping.GENERIC_FIELD_NAMES::containsValue
).xmap(IsFieldPredicate::new, BlockPropertyPredicate::value);
@Override
public Type type() {
return Type.IS_FIELD;
}
@Override
public boolean matches(Property<?> property) {
return BlockPropertyPredicate.testProperty(
field -> field.equals(BlockStateMapping.GENERIC_FIELD_NAMES.get(property)),
this.value,
false
);
}
}
}

View File

@@ -0,0 +1,112 @@
package io.papermc.generator.resources.predicate;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.papermc.generator.utils.SourceCodecs;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.tags.TagKey;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import org.jspecify.annotations.NullMarked;
@NullMarked
public sealed interface ItemPredicate permits ItemPredicate.IsClassPredicate, ItemPredicate.InstanceOfPredicate, ItemPredicate.IsElementPredicate {
Codec<ItemPredicate> DIRECT_CODEC = Type.CODEC.dispatch("type", ItemPredicate::type, type -> type.codec);
Codec<ItemPredicate> CODEC = Codec.either(IsElementPredicate.COMPACT_CODEC, DIRECT_CODEC).xmap(Either::unwrap, Either::right);
Type type();
enum Type implements StringRepresentable {
INSTANCE_OF("instance_of", InstanceOfPredicate.CODEC),
IS_CLASS("is_class", IsClassPredicate.CODEC),
IS_ELEMENT("is_element", IsElementPredicate.CODEC);
public static final Codec<Type> CODEC = StringRepresentable.fromValues(Type::values);
private final String name;
final MapCodec<? extends ItemPredicate> codec;
Type(final String name, final MapCodec<? extends ItemPredicate> codec) {
this.name = name;
this.codec = codec;
}
@Override
public String getSerializedName() {
return this.name;
}
}
boolean matches(Holder.Reference<Item> item);
record IsClassPredicate(Class<?> value, boolean againstBlock) implements ItemPredicate {
public static final MapCodec<IsClassPredicate> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
SourceCodecs.CLASS.fieldOf("value").forGetter(IsClassPredicate::value),
Codec.BOOL.optionalFieldOf("against_block", false).forGetter(IsClassPredicate::againstBlock)
).apply(instance, IsClassPredicate::new));
@Override
public Type type() {
return Type.IS_CLASS;
}
@Override
public boolean matches(Holder.Reference<Item> item) {
if (!this.againstBlock) {
return this.value.equals(item.value().getClass());
} else if (item.value() instanceof BlockItem blockItem) {
return this.value.equals(blockItem.getBlock().getClass());
}
return false;
}
}
record InstanceOfPredicate(Class<?> value, boolean againstBlock) implements ItemPredicate {
public static final MapCodec<InstanceOfPredicate> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
SourceCodecs.CLASS.fieldOf("value").forGetter(InstanceOfPredicate::value),
Codec.BOOL.optionalFieldOf("against_block", false).forGetter(InstanceOfPredicate::againstBlock)
).apply(instance, InstanceOfPredicate::new));
@Override
public Type type() {
return Type.INSTANCE_OF;
}
@Override
public boolean matches(Holder.Reference<Item> item) {
if (!this.againstBlock) {
return this.value.isAssignableFrom(item.value().getClass());
} else if (item.value() instanceof BlockItem blockItem) {
return this.value.isAssignableFrom(blockItem.getBlock().getClass());
}
return false;
}
}
record IsElementPredicate(Either<TagKey<Item>, Holder<Item>> value) implements ItemPredicate {
public static final MapCodec<IsElementPredicate> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
SourceCodecs.elementOrTagCodec(Registries.ITEM).fieldOf("value").forGetter(IsElementPredicate::value)
).apply(instance, IsElementPredicate::new));
public static final Codec<IsElementPredicate> COMPACT_CODEC = SourceCodecs.elementOrTagCodec(Registries.ITEM).xmap(IsElementPredicate::new, IsElementPredicate::value);
@Override
public Type type() {
return Type.IS_ELEMENT;
}
@Override
public boolean matches(Holder.Reference<Item> item) {
return this.value.map(item::is, item::is);
}
}
}

View File

@@ -1,8 +1,8 @@
package io.papermc.generator.rewriter.registration;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.rewriter.utils.Annotations;
import io.papermc.generator.types.SimpleGenerator;
import io.papermc.paper.generated.GeneratedFrom;
import io.papermc.typewriter.ClassNamed;
import io.papermc.typewriter.SourceFile;
import io.papermc.typewriter.context.IndentUnit;
@@ -46,7 +46,7 @@ public class PaperPatternSourceSetRewriter extends SourceSetRewriterImpl<Pattern
COMMENT_MARKER_FORMAT.formatted("Start", pattern),
COMMENT_MARKER_FORMAT.formatted("End", pattern)
)
.generatedComment(Annotations.annotationStyle(GeneratedFrom.class) + " " + SharedConstants.getCurrentVersion().id())
.generatedComment(Annotations.annotationStyle(Types.GENERATED_FROM) + " " + SharedConstants.getCurrentVersion().id())
.targetClass(targetClass);
}

View File

@@ -1,5 +1,7 @@
package io.papermc.generator.rewriter.registration;
import io.papermc.generator.registry.RegistryEntries;
import io.papermc.generator.registry.RegistryIdentifiable;
import io.papermc.typewriter.ClassNamed;
import io.papermc.typewriter.registration.SourceSetRewriter;
import io.papermc.typewriter.replace.CompositeRewriter;
@@ -9,15 +11,11 @@ import org.jspecify.annotations.NullMarked;
@NullMarked
public interface PatternSourceSetRewriter extends SourceSetRewriter<PatternSourceSetRewriter> {
default PatternSourceSetRewriter register(String pattern, Class<?> targetClass, SearchReplaceRewriter rewriter) {
return register(pattern, new ClassNamed(targetClass), rewriter);
default <E, T extends SearchReplaceRewriter & RegistryIdentifiable<E>> PatternSourceSetRewriter register(String pattern, T rewriter) {
return this.register(pattern, RegistryEntries.byRegistryKey(rewriter.getRegistryKey()).data().api().klass().name(), rewriter);
}
PatternSourceSetRewriter register(String pattern, ClassNamed targetClass, SearchReplaceRewriter rewriter);
default PatternSourceSetRewriter register(Class<?> mainClass, CompositeRewriter rewriter) {
return this.register(new ClassNamed(mainClass), rewriter);
}
PatternSourceSetRewriter register(ClassNamed mainClass, CompositeRewriter rewriter);
}

View File

@@ -1,5 +1,7 @@
package io.papermc.generator.rewriter.registration;
import io.papermc.generator.registry.RegistryEntries;
import io.papermc.generator.registry.RegistryIdentifiable;
import io.papermc.typewriter.ClassNamed;
import io.papermc.typewriter.replace.ReplaceOptionsLike;
import io.papermc.typewriter.replace.SearchReplaceRewriter;
@@ -17,7 +19,12 @@ public record RewriterHolder(String pattern, @Nullable ClassNamed targetClass, S
}
@Contract(value = "_, _ -> new", pure = true)
public static RewriterHolder holder(String pattern, SearchReplaceRewriter rewriter) {
public static <E, T extends SearchReplaceRewriter & RegistryIdentifiable<E>> RewriterHolder holder(String pattern, T rewriter) {
return new RewriterHolder(pattern, RegistryEntries.byRegistryKey(rewriter.getRegistryKey()).data().api().klass().name(), rewriter);
}
@Contract(value = "_, _ -> new", pure = true)
public static RewriterHolder sameHolder(String pattern, SearchReplaceRewriter rewriter) {
return holder(pattern, null, rewriter);
}

View File

@@ -1,30 +1,149 @@
package io.papermc.generator.rewriter.types;
import com.squareup.javapoet.ClassName;
import io.papermc.typewriter.ClassNamed;
import java.util.ArrayList;
import java.util.List;
import org.jspecify.annotations.NullMarked;
import static io.papermc.generator.utils.BasePackage.BUKKIT;
import static io.papermc.generator.utils.BasePackage.CRAFT_BUKKIT;
import static io.papermc.generator.utils.BasePackage.PAPER;
import static io.papermc.generator.utils.BasePackage.PAPER_LEGACY;
@NullMarked
public final class Types {
public static final String BASE_PACKAGE = "org.bukkit.craftbukkit";
public static final ClassNamed BUKKIT_CLASS = BUKKIT.rootClassNamed("Bukkit");
public static final ClassNamed CRAFT_BLOCK_DATA = ClassNamed.of(BASE_PACKAGE + ".block.data", "CraftBlockData");
public static final ClassNamed FEATURE_FLAG = BUKKIT.rootClassNamed("FeatureFlag");
public static final ClassNamed CRAFT_BLOCK_STATES = ClassNamed.of(BASE_PACKAGE + ".block", "CraftBlockStates");
public static final ClassNamed REGISTRY = BUKKIT.rootClassNamed("Registry");
public static final ClassNamed CRAFT_STATISTIC = ClassNamed.of(BASE_PACKAGE, "CraftStatistic");
public static final ClassNamed TAG = BUKKIT.rootClassNamed("Tag");
public static final ClassNamed CRAFT_POTION_UTIL = ClassNamed.of(BASE_PACKAGE + ".potion", "CraftPotionUtil");
public static final ClassNamed NAMESPACED_KEY = typed(io.papermc.generator.types.Types.NAMESPACED_KEY);
public static final ClassNamed FIELD_RENAME = ClassNamed.of(BASE_PACKAGE + ".legacy", "FieldRename");
public static final ClassNamed MINECRAFT_EXPERIMENTAL = typed(io.papermc.generator.types.Types.MINECRAFT_EXPERIMENTAL);
public static final ClassNamed MINECRAFT_EXPERIMENTAL_REQUIRES = typed(io.papermc.generator.types.Types.MINECRAFT_EXPERIMENTAL_REQUIRES);
public static final ClassNamed PAPER_REGISTRIES = ClassNamed.of("io.papermc.paper.registry", "PaperRegistries");
@Deprecated
public static final ClassNamed STATISTIC = BUKKIT.rootClassNamed("Statistic");
public static final ClassNamed REGISTRY_MODIFICATION_API_SUPPORT = ClassNamed.of("io.papermc.paper.registry.entry", "RegistryEntryMeta", "RegistryModificationApiSupport");
public static final ClassNamed STATISTIC_TYPE = BUKKIT.rootClassNamed("Statistic", "Type");
public static final ClassNamed PAPER_FEATURE_FLAG_PROVIDER_IMPL = ClassNamed.of("io.papermc.paper.world.flag", "PaperFeatureFlagProviderImpl");
public static final ClassNamed BLOCK_TYPE_TYPED = BUKKIT.relativeClassNamed("block", "BlockType", "Typed");
public static final ClassNamed PAPER_SIMPLE_REGISTRY = ClassNamed.of("io.papermc.paper.registry", "PaperSimpleRegistry");
public static final ClassNamed ITEM_TYPE_TYPED = BUKKIT.relativeClassNamed("inventory", "ItemType", "Typed");
public static final ClassNamed MOB_GOAL_HELPER = ClassNamed.of("com.destroystokyo.paper.entity.ai", "MobGoalHelper");
public static final ClassNamed ITEM_META = BUKKIT.relativeClassNamed("inventory.meta", "ItemMeta");
public static final ClassNamed LOCATION = BUKKIT.rootClassNamed("Location");
public static final ClassNamed MATERIAL = BUKKIT.rootClassNamed("Material");
public static final ClassNamed POSE = BUKKIT.relativeClassNamed("entity", "Pose");
@Deprecated
public static final ClassNamed VILLAGER = BUKKIT.relativeClassNamed("entity", "Villager");
public static final ClassNamed SNIFFER_STATE = BUKKIT.relativeClassNamed("entity", "Sniffer", "State");
public static final ClassNamed TROPICAL_FISH_PATTERN = BUKKIT.relativeClassNamed("entity", "TropicalFish", "Pattern");
public static final ClassNamed FOX_TYPE = BUKKIT.relativeClassNamed("entity", "Fox", "Type");
public static final ClassNamed SALMON_VARIANT = BUKKIT.relativeClassNamed("entity", "Salmon", "Variant");
public static final ClassNamed ARMADILLO_STATE = BUKKIT.relativeClassNamed("entity", "Armadillo", "State");
public static final ClassNamed PANDA_GENE = BUKKIT.relativeClassNamed("entity", "Panda", "Gene");
public static final ClassNamed BOAT_STATUS = BUKKIT.relativeClassNamed("entity", "Boat", "Status");
public static final ClassNamed ITEM_RARITY = BUKKIT.relativeClassNamed("inventory", "ItemRarity");
public static final ClassNamed COOKING_BOOK_CATEGORY = BUKKIT.relativeClassNamed("inventory.recipe", "CookingBookCategory");
public static final ClassNamed CRAFTING_BOOK_CATEGORY = BUKKIT.relativeClassNamed("inventory.recipe", "CraftingBookCategory");
public static final ClassNamed MAP_PALETTE = BUKKIT.relativeClassNamed("map", "MapPalette");
public static final ClassNamed DISPLAY_SLOT = BUKKIT.relativeClassNamed("scoreboard", "DisplaySlot");
public static final ClassNamed SOUND_CATEGORY = BUKKIT.rootClassNamed("SoundCategory");
public static final ClassNamed DAMAGE_TYPE_TAGS = BUKKIT.relativeClassNamed("tag", "DamageTypeTags");
public static final ClassNamed BLOCK_DATA = BUKKIT.relativeClassNamed("block.data", "BlockData");
public static final ClassNamed BLOCK_DATA_REDSTONE_WIRE = BUKKIT.relativeClassNamed("block.data.type", "RedstoneWire");
public static final ClassNamed BLOCK_DATA_MULTIPLE_FACING = BUKKIT.relativeClassNamed("block.data", "MultipleFacing");
public static final ClassNamed BLOCK_DATA_RAIL_SHAPE = typed(io.papermc.generator.types.Types.BLOCK_DATA_RAIL_SHAPE);
public static final ClassNamed AXIS = typed(io.papermc.generator.types.Types.AXIS);
public static final ClassNamed BLOCK_FACE = typed(io.papermc.generator.types.Types.BLOCK_FACE);
public static final ClassNamed NOTE = typed(io.papermc.generator.types.Types.NOTE);
public static final ClassNamed NAMED_TEXT_COLOR = ClassNamed.of("net.kyori.adventure.text.format", "NamedTextColor");
public static final ClassNamed REGISTRY_KEY = typed(io.papermc.generator.types.Types.REGISTRY_KEY);
public static final ClassNamed REGISTRY_EVENTS = PAPER.relativeClassNamed("registry.event", "RegistryEvents");
public static final ClassNamed REGISTRY_EVENT_PROVIDER = PAPER.relativeClassNamed("registry.event", "RegistryEventProvider");
public static final ClassNamed ITEM_USE_ANIMATION = PAPER.relativeClassNamed("datacomponent.item.consumable", "ItemUseAnimation");
public static final ClassNamed GENERATED_FROM = typed(io.papermc.generator.types.Types.GENERATED_FROM);
public static final ClassNamed BLOCK_PROPERTIES = PAPER.relativeClassNamed("block.property", "BlockProperties");
public static final ClassNamed BLOCK_PROPERTY = PAPER.relativeClassNamed("block.property", "BlockProperty");
public static final ClassNamed BOOLEAN_BLOCK_PROPERTY = PAPER.relativeClassNamed("block.property", "BooleanBlockProperty");
public static final ClassNamed ENUM_BLOCK_PROPERTY = PAPER.relativeClassNamed("block.property", "EnumBlockProperty");
public static final ClassNamed INTEGER_BLOCK_PROPERTY = PAPER.relativeClassNamed("block.property", "IntegerBlockProperty");
public static final ClassNamed ROTATION_BLOCK_PROPERTY = PAPER.relativeClassNamed("block.property", "RotationBlockProperty");
public static final ClassNamed NOTE_BLOCK_PROPERTY = PAPER.relativeClassNamed("block.property", "NoteBlockProperty");
public static final ClassNamed CRAFT_BLOCK_DATA = typed(io.papermc.generator.types.Types.CRAFT_BLOCK_DATA);
public static final ClassNamed CRAFT_BLOCK_STATES = CRAFT_BUKKIT.relativeClassNamed("block", "CraftBlockStates");
public static final ClassNamed CRAFT_ITEM_METAS = CRAFT_BUKKIT.relativeClassNamed("inventory", "CraftItemMetas");
public static final ClassNamed CRAFT_STATISTIC = CRAFT_BUKKIT.relativeClassNamed(null, "CraftStatistic");
public static final ClassNamed CRAFT_POTION_UTIL = CRAFT_BUKKIT.relativeClassNamed("potion", "CraftPotionUtil");
public static final ClassNamed FIELD_RENAME = CRAFT_BUKKIT.relativeClassNamed("legacy", "FieldRename");
public static final ClassNamed REGISTRIES_ARGUMENT_PROVIDER = BUKKIT.relativeClassNamed("support.provider" , "RegistriesArgumentProvider");
public static final ClassNamed REGISTRY_CONVERSION_TEST = BUKKIT.relativeClassNamed("registry", "RegistryConversionTest");
public static final ClassNamed PAPER_REGISTRIES = PAPER.relativeClassNamed("registry", "PaperRegistries");
public static final ClassNamed PAPER_FEATURE_FLAG_PROVIDER_IMPL = PAPER.relativeClassNamed("world.flag", "PaperFeatureFlagProviderImpl");
public static final ClassNamed PAPER_SIMPLE_REGISTRY = PAPER.relativeClassNamed("registry", "PaperSimpleRegistry");
public static final ClassNamed REGISTRY_MODIFICATION_API_SUPPORT = PAPER.relativeClassNamed("registry.entry", "RegistryEntryMeta", "RegistryModificationApiSupport");
public static final ClassNamed MOB_GOAL_HELPER = PAPER_LEGACY.relativeClassNamed("entity.ai", "MobGoalHelper");
public static ClassNamed typed(ClassName name) {
List<String> names = new ArrayList<>(name.simpleNames());
String topName = names.removeFirst();
return ClassNamed.of(name.packageName(), topName, names.toArray(new String[0]));
}
}

View File

@@ -2,12 +2,13 @@ package io.papermc.generator.rewriter.types.registry;
import com.google.common.base.Suppliers;
import io.papermc.generator.Main;
import io.papermc.generator.registry.RegistryIdentifiable;
import io.papermc.generator.rewriter.utils.Annotations;
import io.papermc.generator.utils.Formatting;
import io.papermc.generator.utils.experimental.ExperimentalCollector;
import io.papermc.generator.utils.experimental.SingleFlagHolder;
import io.papermc.typewriter.preset.EnumRewriter;
import io.papermc.typewriter.preset.model.EnumValue;
import io.papermc.typewriter.preset.model.EnumConstant;
import java.util.Map;
import java.util.function.Supplier;
import net.minecraft.core.Holder;
@@ -16,29 +17,28 @@ import net.minecraft.resources.ResourceKey;
import net.minecraft.world.flag.FeatureElement;
import net.minecraft.world.flag.FeatureFlags;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import static io.papermc.generator.utils.Formatting.quoted;
@NullMarked
@ApiStatus.Obsolete
public class EnumRegistryRewriter<T> extends EnumRewriter<Holder.Reference<T>> {
public class EnumRegistryRewriter<T> extends EnumRewriter<Holder.Reference<T>> implements RegistryIdentifiable<T> {
private final ResourceKey<? extends Registry<T>> registryKey;
private final Supplier<Registry<T>> registry;
private final Supplier<Map<ResourceKey<T>, SingleFlagHolder>> experimentalKeys;
private final boolean isFilteredRegistry;
private final boolean hasKeyArgument;
public EnumRegistryRewriter(ResourceKey<? extends Registry<T>> registryKey) {
this(registryKey, true);
}
protected EnumRegistryRewriter(ResourceKey<? extends Registry<T>> registryKey, boolean hasKeyArgument) {
this.registryKey = registryKey;
this.registry = Suppliers.memoize(() -> Main.REGISTRY_ACCESS.lookupOrThrow(registryKey));
this.experimentalKeys = Suppliers.memoize(() -> ExperimentalCollector.collectDataDrivenElementIds(this.registry.get()));
this.isFilteredRegistry = FeatureElement.FILTERED_REGISTRIES.contains(registryKey);
this.hasKeyArgument = hasKeyArgument;
}
@Override
public ResourceKey<? extends Registry<T>> getRegistryKey() {
return this.registryKey;
}
@Override
@@ -47,23 +47,24 @@ public class EnumRegistryRewriter<T> extends EnumRewriter<Holder.Reference<T>> {
}
@Override
protected EnumValue.Builder rewriteEnumValue(Holder.Reference<T> reference) {
EnumValue.Builder value = EnumValue.builder(Formatting.formatKeyAsField(reference.key().location().getPath()));
if (this.hasKeyArgument) {
value.argument(quoted(reference.key().location().getPath()));
}
return value;
protected EnumConstant.Builder constantPrototype(Holder.Reference<T> reference) {
return EnumConstant.builder(Formatting.formatKeyAsField(reference.key().location().getPath()));
}
@Override
protected void appendEnumValue(Holder.Reference<T> reference, StringBuilder builder, String indent, boolean reachEnd) {
protected void rewriteConstant(EnumConstant.Builder builder, Holder.Reference<T> reference) {
builder.argument(quoted(reference.key().location().getPath()));
}
@Override
protected void appendConstant(Holder.Reference<T> reference, StringBuilder builder, String indent, boolean reachEnd) {
// experimental annotation
SingleFlagHolder requiredFeature = this.getRequiredFeature(reference);
if (requiredFeature != null) {
Annotations.experimentalAnnotations(builder, indent, this.importCollector, requiredFeature);
}
super.appendEnumValue(reference, builder, indent, reachEnd);
super.appendConstant(reference, builder, indent, reachEnd);
}
protected @Nullable SingleFlagHolder getRequiredFeature(Holder.Reference<T> reference) {

View File

@@ -1,8 +1,7 @@
package io.papermc.generator.rewriter.types.registry;
import com.mojang.logging.LogUtils;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.utils.Formatting;
import io.papermc.typewriter.SourceFile;
import io.papermc.typewriter.replace.SearchMetadata;
import io.papermc.typewriter.replace.SearchReplaceRewriter;
import java.util.Iterator;
@@ -12,29 +11,12 @@ import net.minecraft.world.flag.FeatureFlag;
import net.minecraft.world.flag.FeatureFlagSet;
import net.minecraft.world.flag.FeatureFlags;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import org.slf4j.Logger;
import static io.papermc.generator.rewriter.utils.Annotations.annotation;
import static io.papermc.generator.utils.Formatting.quoted;
@NullMarked
public class FeatureFlagRewriter extends SearchReplaceRewriter {
private static final Logger LOGGER = LogUtils.getLogger();
@Override
public boolean registerFor(SourceFile file) {
try {
org.bukkit.FeatureFlag.class.getDeclaredMethod("create", String.class);
} catch (NoSuchMethodException e) {
LOGGER.error("Fetch method not found, skipping the rewriter for feature flag", e);
return false;
}
return super.registerFor(file);
}
@Override
protected void insert(SearchMetadata metadata, StringBuilder builder) {
Iterator<Map.Entry<ResourceLocation, FeatureFlag>> flagIterator = FeatureFlags.REGISTRY.names.entrySet().stream().sorted(Formatting.alphabeticKeyOrder(entry -> entry.getKey().getPath())).iterator();
@@ -47,7 +29,7 @@ public class FeatureFlagRewriter extends SearchReplaceRewriter {
builder.append(metadata.indent());
builder.append(org.bukkit.FeatureFlag.class.getSimpleName()).append(' ').append(Formatting.formatKeyAsField(name.getPath()));
builder.append(Types.FEATURE_FLAG.simpleName()).append(' ').append(Formatting.formatKeyAsField(name.getPath()));
builder.append(" = ");
builder.append("create(%s)".formatted(quoted(name.getPath())));
builder.append(';');

View File

@@ -1,15 +1,13 @@
package io.papermc.generator.rewriter.types.registry;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.utils.Formatting;
import io.papermc.typewriter.replace.SearchMetadata;
import io.papermc.typewriter.replace.SearchReplaceRewriter;
import java.util.Iterator;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.flag.FeatureFlags;
import org.bukkit.FeatureFlag;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class PaperFeatureFlagMapping extends SearchReplaceRewriter {
@Override
@@ -20,7 +18,7 @@ public class PaperFeatureFlagMapping extends SearchReplaceRewriter {
ResourceLocation name = flagIterator.next();
String keyedName = Formatting.formatKeyAsField(name.getPath());
builder.append(metadata.indent());
builder.append("%s.%s, %s.%s".formatted(FeatureFlag.class.getSimpleName(), keyedName, FeatureFlags.class.getSimpleName(), keyedName));
builder.append("%s.%s, %s.%s".formatted(Types.FEATURE_FLAG.simpleName(), keyedName, FeatureFlags.class.getSimpleName(), keyedName));
if (flagIterator.hasNext()) {
builder.append(',');
}

View File

@@ -3,74 +3,66 @@ package io.papermc.generator.rewriter.types.registry;
import com.google.common.base.CaseFormat;
import io.papermc.generator.registry.RegistryEntries;
import io.papermc.generator.registry.RegistryEntry;
import io.papermc.generator.resources.data.RegistryData;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.typewriter.ClassNamed;
import io.papermc.typewriter.replace.SearchMetadata;
import io.papermc.typewriter.replace.SearchReplaceRewriter;
import java.lang.constant.ConstantDescs;
import java.util.stream.Stream;
import net.minecraft.core.registries.Registries;
import org.bukkit.Keyed;
import org.bukkit.Registry;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class PaperRegistriesRewriter extends SearchReplaceRewriter {
private void appendEntry(String indent, StringBuilder builder, RegistryEntry<?> entry, boolean canBeDelayed, boolean apiOnly) {
private void appendEntry(String indent, StringBuilder builder, RegistryEntry<?> entry, boolean apiOnly) {
builder.append(indent);
builder.append("start");
builder.append('(');
builder.append(Registries.class.getSimpleName()).append('.').append(entry.registryKeyField());
builder.append(", ");
builder.append(RegistryKey.class.getSimpleName()).append('.').append(entry.registryKeyField());
builder.append(Types.REGISTRY_KEY.simpleName()).append('.').append(entry.registryKeyField());
builder.append(").");
RegistryData data = entry.data();
if (apiOnly) {
builder.append("apiOnly(");
if (entry.apiClass().isEnum()) {
builder.append(this.importCollector.getShortName(Types.PAPER_SIMPLE_REGISTRY)).append("::").append(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, entry.registryKey().location().getPath()));
if (data.api().klass().legacyEnum()) {
builder.append(this.importCollector.getShortName(Types.PAPER_SIMPLE_REGISTRY)).append("::").append(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, entry.getRegistryKey().location().getPath()));
} else {
builder.append("() -> ");
builder.append(Registry.class.getCanonicalName()).append('.').append(entry.apiRegistryField().orElse(entry.registryKeyField()));
builder.append(Types.REGISTRY.canonicalName()).append('.').append(data.api().registryField().orElse(entry.registryKeyField()));
}
builder.append(')');
} else {
builder.append("craft(");
builder.append(this.importCollector.getShortName(entry.preloadClass())).append(".class");
builder.append(this.importCollector.getShortName(data.api().holderClass().flatMap(RegistryData.Api.HolderClass::name).orElse(data.api().klass().name()))).append(".class");
builder.append(", ");
builder.append(this.importCollector.getShortName(this.getImplClassName(entry))).append("::").append(entry.apiAccessName().equals(ConstantDescs.INIT_NAME) ? "new" : entry.apiAccessName());
builder.append(this.importCollector.getShortName(data.impl().klass())).append("::").append(data.impl().instanceMethod().equals(ConstantDescs.INIT_NAME) ? "new" : data.impl().instanceMethod());
if (entry.canAllowDirect()) {
if (data.allowInline()) {
builder.append(", ");
builder.append(Boolean.TRUE.toString());
}
builder.append(')');
if (entry.fieldRename() != null) {
builder.append(".serializationUpdater(").append(Types.FIELD_RENAME.simpleName()).append('.').append(entry.fieldRename()).append(")");
}
data.serializationUpdaterField().ifPresent(field -> {
builder.append(".serializationUpdater(").append(Types.FIELD_RENAME.simpleName()).append('.').append(field).append(")");
});
if (entry.apiRegistryBuilderImpl() != null && entry.modificationApiSupport() != null) {
switch (entry.modificationApiSupport()) {
case WRITABLE -> builder.append(".writable(");
case ADDABLE -> builder.append(".addable(");
case MODIFIABLE -> builder.append(".modifiable(");
case NONE -> builder.append(".create(");
data.builder().ifPresentOrElse(b -> {
if (b.capability() != RegistryData.Builder.RegisterCapability.NONE) {
builder.append(".%s(".formatted(b.capability().getSerializedName()));
builder.append(this.importCollector.getShortName(b.impl())).append("::new");
builder.append(')');
} else {
builder.append(".create(%s::new, %s.%s)".formatted(
this.importCollector.getShortName(b.impl()),
Types.REGISTRY_MODIFICATION_API_SUPPORT.dottedNestedName(),
b.capability().name()
));
}
builder.append(this.importCollector.getShortName(this.classNamedView.findFirst(entry.apiRegistryBuilderImpl()).resolve(this.classResolver))).append("::new");
if (entry.modificationApiSupport() == RegistryEntry.RegistryModificationApiSupport.NONE) {
builder.append(", ");
builder.append(Types.REGISTRY_MODIFICATION_API_SUPPORT.dottedNestedName()).append(".NONE");
}
builder.append(')');
} else {
builder.append(".build()");
}
}, () -> builder.append(".build()"));
}
if (canBeDelayed && entry.isDelayed()) {
if (data.impl().delayed()) {
builder.append(".delayed()");
}
builder.append(',');
@@ -79,37 +71,24 @@ public class PaperRegistriesRewriter extends SearchReplaceRewriter {
@Override
public void insert(SearchMetadata metadata, StringBuilder builder) {
builder.append(metadata.indent()).append("// built-in");
builder.append('\n');
for (RegistryEntry.Type type : RegistryEntry.Type.values()) {
builder.append(metadata.indent()).append("// ").append(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, type.getSerializedName()));
builder.append('\n');
for (RegistryEntry<?> entry : RegistryEntries.BUILT_IN) {
appendEntry(metadata.indent(), builder, entry, false, false);
for (RegistryEntry<?> entry : RegistryEntries.byType(type)) {
appendEntry(metadata.indent(), builder, entry, false);
}
builder.append('\n');
}
builder.append('\n');
builder.append(metadata.indent()).append("// data-driven");
builder.append('\n');
for (RegistryEntry<?> entry : RegistryEntries.DATA_DRIVEN) {
appendEntry(metadata.indent(), builder, entry, true, false);
}
builder.append('\n');
builder.append(metadata.indent()).append("// api-only");
builder.append('\n');
for (RegistryEntry<?> entry : RegistryEntries.API_ONLY) {
appendEntry(metadata.indent(), builder, entry, false, true);
appendEntry(metadata.indent(), builder, entry, true);
}
builder.deleteCharAt(builder.length() - 2); // delete extra comma...
}
private ClassNamed getImplClassName(RegistryEntry<?> entry) {
try (Stream<ClassNamed> stream = this.classNamedView.find(entry.implClass())) {
return stream.map(klass -> klass.resolve(this.classResolver))
.filter(klass -> Keyed.class.isAssignableFrom(klass.knownClass())) // todo check handleable/holderable once keyed is gone
.findFirst().orElseThrow();
}
}
}

View File

@@ -0,0 +1,37 @@
package io.papermc.generator.rewriter.types.registry;
import io.papermc.generator.registry.RegistryEntries;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.typewriter.replace.SearchMetadata;
import io.papermc.typewriter.replace.SearchReplaceRewriter;
import java.util.Set;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
public class RegistriesArgumentProviderRewriter extends SearchReplaceRewriter {
private static final Set<ResourceKey<? extends Registry<?>>> NEW_BRIDGE_METHODS = Set.of(
Registries.ITEM,
Registries.BLOCK
);
@Override
public void insert(SearchMetadata metadata, StringBuilder builder) {
RegistryEntries.forEach(entry -> {
builder.append(metadata.indent());
builder.append("register(").append(
"%s.%s, %s.class, %s.%s, %s.class, %s.class, %s".formatted(
Types.REGISTRY_KEY.simpleName(),
entry.registryKeyField(),
this.importCollector.getShortName(entry.data().api().klass().name()),
Registries.class.getSimpleName(),
entry.registryKeyField(),
this.importCollector.getShortName(entry.data().impl().klass()),
this.importCollector.getShortName(entry.elementClass()),
Boolean.toString(NEW_BRIDGE_METHODS.contains(entry.getRegistryKey()))
)).append(");");
builder.append("\n");
});
}
}

View File

@@ -0,0 +1,22 @@
package io.papermc.generator.rewriter.types.registry;
import io.papermc.generator.registry.RegistryEntries;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.typewriter.replace.SearchMetadata;
import io.papermc.typewriter.replace.SearchReplaceRewriter;
public class RegistryConversionTestRewriter extends SearchReplaceRewriter {
@Override
public void insert(SearchMetadata metadata, StringBuilder builder) {
RegistryEntries.forEach(entry -> {
if (entry.data().allowInline()) {
builder.append(metadata.indent());
builder.append("%s.%s,".formatted(Types.REGISTRY_KEY.simpleName(), entry.registryKeyField()));
builder.append("\n");
}
});
builder.deleteCharAt(builder.length() - 2); // delete extra comma...
}
}

View File

@@ -1,34 +1,40 @@
package io.papermc.generator.rewriter.types.registry;
import io.papermc.generator.registry.RegistryEntries;
import io.papermc.generator.registry.RegistryEntry;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.event.RegistryEventProvider;
import io.papermc.generator.resources.data.RegistryData;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.typewriter.replace.SearchMetadata;
import io.papermc.typewriter.replace.SearchReplaceRewriter;
import org.jspecify.annotations.NullMarked;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
@NullMarked
public class RegistryEventsRewriter extends SearchReplaceRewriter {
@Override
public void insert(SearchMetadata metadata, StringBuilder builder) {
RegistryEntries.forEach(entry -> {
if (entry.apiRegistryBuilder() != null && entry.modificationApiSupport() != RegistryEntry.RegistryModificationApiSupport.NONE) {
RegistryData data = entry.data();
data.builder().ifPresent(b -> {
if (b.capability() == RegistryData.Builder.RegisterCapability.NONE) {
return;
}
builder.append(metadata.indent());
builder.append("%s %s %s ".formatted(PUBLIC, STATIC, FINAL));
builder.append(RegistryEventProvider.class.getSimpleName());
builder.append("<").append(this.importCollector.getShortName(entry.apiClass())).append(", ").append(this.importCollector.getShortName(entry.apiRegistryBuilder())).append('>');
builder.append(Types.REGISTRY_EVENT_PROVIDER.simpleName());
builder.append('<');
data.api().klass().appendType(builder, name -> this.importCollector.getShortName(name));
builder.append(", ");
b.appendApiType(builder, name -> this.importCollector.getShortName(name));
builder.append('>');
builder.append(' ');
builder.append(entry.registryKeyField());
builder.append(" = ");
builder.append("create(").append(RegistryKey.class.getSimpleName()).append('.').append(entry.registryKeyField()).append(");");
builder.append("create(").append(Types.REGISTRY_KEY.simpleName()).append('.').append(entry.registryKeyField()).append(");");
builder.append('\n');
}
});
});
}
}

View File

@@ -1,20 +1,18 @@
package io.papermc.generator.rewriter.types.registry;
import com.google.common.base.Preconditions;
import com.google.common.base.Suppliers;
import com.mojang.logging.LogUtils;
import io.papermc.generator.Main;
import io.papermc.generator.registry.RegistryEntries;
import io.papermc.generator.registry.RegistryEntry;
import io.papermc.generator.registry.RegistryIdentifiable;
import io.papermc.generator.rewriter.utils.Annotations;
import io.papermc.generator.utils.Formatting;
import io.papermc.generator.utils.experimental.ExperimentalCollector;
import io.papermc.generator.utils.experimental.SingleFlagHolder;
import io.papermc.typewriter.ClassNamed;
import io.papermc.typewriter.SourceFile;
import io.papermc.typewriter.replace.SearchMetadata;
import io.papermc.typewriter.replace.SearchReplaceRewriter;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
@@ -22,25 +20,20 @@ import net.minecraft.resources.ResourceKey;
import net.minecraft.world.flag.FeatureElement;
import net.minecraft.world.flag.FeatureFlags;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
import static io.papermc.generator.utils.Formatting.quoted;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
@NullMarked
public class RegistryFieldRewriter<T> extends SearchReplaceRewriter {
private static final Logger LOGGER = LogUtils.getLogger();
public class RegistryFieldRewriter<T> extends SearchReplaceRewriter implements RegistryIdentifiable<T> {
private final ResourceKey<? extends Registry<T>> registryKey;
private final boolean isFilteredRegistry;
private final @Nullable String fetchMethod;
protected @MonotonicNonNull ClassNamed fieldClass;
protected @MonotonicNonNull RegistryEntry<T> entry;
private @MonotonicNonNull Supplier<Map<ResourceKey<T>, SingleFlagHolder>> experimentalKeys;
public RegistryFieldRewriter(ResourceKey<? extends Registry<T>> registryKey, @Nullable String fetchMethod) {
@@ -49,27 +42,21 @@ public class RegistryFieldRewriter<T> extends SearchReplaceRewriter {
this.fetchMethod = fetchMethod;
}
@Override
public ResourceKey<? extends Registry<T>> getRegistryKey() {
return this.registryKey;
}
@Override
public boolean registerFor(SourceFile file) {
this.fieldClass = this.options.targetClass().orElse(file.mainClass());
Preconditions.checkState(this.fieldClass.knownClass() != null, "This rewriter can't run without knowing the field class at runtime!");
if (this.fetchMethod != null) {
try {
this.fieldClass.knownClass().getDeclaredMethod(this.fetchMethod, String.class);
} catch (NoSuchMethodException e) {
LOGGER.error("Fetch method not found, skipping the rewriter for registry fields of {}", this.registryKey, e);
return false;
}
}
this.entry = RegistryEntries.byRegistryKey(this.registryKey);
return super.registerFor(file);
}
@Override
protected void insert(SearchMetadata metadata, StringBuilder builder) {
boolean isInterface = Objects.requireNonNull(this.fieldClass.knownClass()).isInterface();
Registry<T> registry = Main.REGISTRY_ACCESS.lookupOrThrow(this.registryKey);
boolean isInterface = this.entry.data().api().holderClass().isEmpty() || this.entry.data().api().holderClass().get().isInterface();
Registry<T> registry = this.entry.registry();
this.experimentalKeys = Suppliers.memoize(() -> ExperimentalCollector.collectDataDrivenElementIds(registry));
Iterator<Holder.Reference<T>> referenceIterator = registry.listElements().filter(this::canPrintField).sorted(Formatting.HOLDER_ORDER).iterator();
@@ -108,7 +95,7 @@ public class RegistryFieldRewriter<T> extends SearchReplaceRewriter {
}
protected String rewriteFieldType(Holder.Reference<T> reference) {
return this.fieldClass.simpleName();
return this.entry.data().api().klass().name().simpleName();
}
protected String rewriteFieldName(Holder.Reference<T> reference) {

View File

@@ -1,63 +1,44 @@
package io.papermc.generator.rewriter.types.registry;
import com.google.common.base.Preconditions;
import com.mojang.logging.LogUtils;
import io.papermc.generator.Main;
import io.papermc.generator.registry.RegistryEntries;
import io.papermc.generator.registry.RegistryEntry;
import io.papermc.generator.registry.RegistryIdentifiable;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.rewriter.utils.Annotations;
import io.papermc.generator.utils.Formatting;
import io.papermc.generator.utils.experimental.SingleFlagHolder;
import io.papermc.typewriter.ClassNamed;
import io.papermc.typewriter.SourceFile;
import io.papermc.typewriter.replace.SearchMetadata;
import io.papermc.typewriter.replace.SearchReplaceRewriter;
import java.util.Iterator;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.tags.TagKey;
import org.bukkit.Keyed;
import org.bukkit.Tag;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import org.slf4j.Logger;
import static io.papermc.generator.utils.Formatting.quoted;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
@NullMarked
@ApiStatus.Obsolete
public class RegistryTagRewriter<T> extends SearchReplaceRewriter {
private static final Logger LOGGER = LogUtils.getLogger();
public class RegistryTagRewriter<T> extends SearchReplaceRewriter implements RegistryIdentifiable<T> {
private final ResourceKey<? extends Registry<T>> registryKey;
private final Class<? extends Keyed> apiClass;
private final String fetchMethod = "getTag";
public RegistryTagRewriter(ResourceKey<? extends Registry<T>> registryKey, Class<? extends Keyed> apiClass) {
public RegistryTagRewriter(ResourceKey<? extends Registry<T>> registryKey) {
this.registryKey = registryKey;
this.apiClass = apiClass;
}
@Override
public boolean registerFor(SourceFile file) {
ClassNamed holderClass = this.options.targetClass().orElse(file.mainClass());
Preconditions.checkState(holderClass.knownClass() != null, "This rewriter can't run without knowing the field class at runtime!");
try {
holderClass.knownClass().getDeclaredMethod(this.fetchMethod, String.class);
} catch (NoSuchMethodException e) {
LOGGER.error("Fetch method not found, skipping the rewriter for registry tag fields of {}", this.registryKey, e);
return false;
}
return super.registerFor(file);
public ResourceKey<? extends Registry<T>> getRegistryKey() {
return this.registryKey;
}
@Override
protected void insert(SearchMetadata metadata, StringBuilder builder) {
Registry<T> registry = Main.REGISTRY_ACCESS.lookupOrThrow(this.registryKey);
Iterator<? extends TagKey<T>> keyIterator = registry.listTagIds().sorted(Formatting.TAG_ORDER).iterator();
RegistryEntry<T> entry = RegistryEntries.byRegistryKey(this.registryKey);
Iterator<? extends TagKey<T>> keyIterator = entry.registry().listTagIds().sorted(Formatting.TAG_ORDER).iterator();
while (keyIterator.hasNext()) {
TagKey<T> tagKey = keyIterator.next();
@@ -70,7 +51,7 @@ public class RegistryTagRewriter<T> extends SearchReplaceRewriter {
builder.append(metadata.indent());
builder.append("%s %s %s ".formatted(PUBLIC, STATIC, FINAL));
builder.append("%s<%s>".formatted(Tag.class.getSimpleName(), this.apiClass.getSimpleName())).append(' ').append(this.rewriteFieldName(tagKey));
builder.append("%s<%s>".formatted(Types.TAG.simpleName(), entry.data().api().klass().name().simpleName())).append(' ').append(this.rewriteFieldName(tagKey));
builder.append(" = ");
builder.append(this.rewriteFieldValue(tagKey));
builder.append(';');
@@ -87,6 +68,6 @@ public class RegistryTagRewriter<T> extends SearchReplaceRewriter {
}
protected String rewriteFieldValue(TagKey<T> tagKey) {
return "%s(%s)".formatted(this.fetchMethod, quoted(tagKey.location().getPath()));
return "%s(%s)".formatted(TagRewriter.FETCH_METHOD, quoted(tagKey.location().getPath()));
}
}

View File

@@ -1,47 +1,89 @@
package io.papermc.generator.rewriter.types.registry;
import com.mojang.logging.LogUtils;
import io.papermc.generator.Main;
import io.papermc.generator.registry.RegistryEntries;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.rewriter.utils.Annotations;
import io.papermc.generator.utils.Formatting;
import io.papermc.generator.utils.experimental.SingleFlagHolder;
import io.papermc.typewriter.ClassNamed;
import io.papermc.typewriter.parser.Lexer;
import io.papermc.typewriter.parser.sequence.SequenceTokens;
import io.papermc.typewriter.parser.sequence.TokenTaskBuilder;
import io.papermc.typewriter.parser.token.CharSequenceToken;
import io.papermc.typewriter.parser.token.TokenType;
import io.papermc.typewriter.replace.SearchMetadata;
import io.papermc.typewriter.replace.SearchReplaceRewriter;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.tags.TagKey;
import org.bukkit.Bukkit;
import org.bukkit.Fluid;
import org.bukkit.GameEvent;
import org.bukkit.Keyed;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import org.slf4j.Logger;
import static io.papermc.generator.utils.Formatting.quoted;
@NullMarked
@ApiStatus.Obsolete
public class TagRewriter extends SearchReplaceRewriter {
public record TagRegistry(String legacyFolderName, Class<? extends Keyed> apiType, ResourceKey<? extends Registry<?>> registryKey) { // TODO remove Keyed
private static final Logger LOGGER = LogUtils.getLogger();
static final String FETCH_METHOD = "getTag";
private record TagRegistry(String legacyFolderName, ClassNamed apiType, ResourceKey<? extends Registry<?>> registryKey) {
public TagRegistry(String legacyFolderName, ResourceKey<? extends Registry<?>> registryKey) {
this(legacyFolderName, RegistryEntries.BY_REGISTRY_KEY.get(registryKey).data().api().klass().name(), registryKey);
}
}
private static final TagRegistry[] SUPPORTED_REGISTRIES = { // 1.21 folder name are normalized to registry key but api will stay as is
new TagRegistry("blocks", Material.class, Registries.BLOCK),
new TagRegistry("items", Material.class, Registries.ITEM),
new TagRegistry("fluids", Fluid.class, Registries.FLUID),
new TagRegistry("entity_types", EntityType.class, Registries.ENTITY_TYPE),
new TagRegistry("game_events", GameEvent.class, Registries.GAME_EVENT)
// new TagRegistry("damage_types", DamageType.class, Registries.DAMAGE_TYPE) - separate in DamageTypeTags
new TagRegistry("blocks", Types.MATERIAL, Registries.BLOCK),
new TagRegistry("items", Types.MATERIAL, Registries.ITEM),
new TagRegistry("fluids", Registries.FLUID),
new TagRegistry("entity_types", Registries.ENTITY_TYPE),
new TagRegistry("game_events", Registries.GAME_EVENT)
// new TagRegistry("damage_types", Registries.DAMAGE_TYPE) - separate in DamageTypeTags
};
private static final Set<TokenType> FORMAT_TOKENS = EnumSet.of(
TokenType.COMMENT,
TokenType.SINGLE_COMMENT,
TokenType.JAVADOC,
TokenType.MARKDOWN_JAVADOC
);
private List<String> parseExistingFields(String content) {
List<String> fields = new ArrayList<>();
Lexer lex = new Lexer(content.toCharArray());
lex.checkMarkdownDocComments = !this.sourcesMetadata.canSkipMarkdownDocComments();
// todo skipUntilNextLine + cleanup lexer flags
SequenceTokens.wrap(lex, FORMAT_TOKENS)
.group(action -> {
action
.skip(TokenType.IDENTIFIER) // Tag
.skipClosure(TokenType.LT, TokenType.GT, true) // <*>
.map(TokenType.IDENTIFIER, token -> {
fields.add(((CharSequenceToken) token).value());
})
.skipQualifiedName() // Bukkit.getTag
.skipClosure(TokenType.LPAREN, TokenType.RPAREN, true) // (*)
.skip(TokenType.SECO); // ;
}, TokenTaskBuilder::asRepeatable)
.executeOrThrow();
return fields;
}
@Override
protected void insert(SearchMetadata metadata, StringBuilder builder) {
List<String> replacedFields = !Main.IS_UPDATING ? new ArrayList<>() : this.parseExistingFields(metadata.replacedContent());
for (int i = 0, len = SUPPORTED_REGISTRIES.length; i < len; i++) {
final TagRegistry tagRegistry = SUPPORTED_REGISTRIES[i];
@@ -56,11 +98,11 @@ public class TagRewriter extends SearchReplaceRewriter {
}
// registry name field
builder.append(metadata.indent());
builder.append("%s %s = %s;".formatted(String.class.getSimpleName(), registryFieldName, quoted(tagRegistry.legacyFolderName())));
//builder.append(metadata.indent());
//builder.append("%s %s = %s;".formatted(String.class.getSimpleName(), registryFieldName, quoted(tagRegistry.legacyFolderName())));
builder.append('\n');
builder.append('\n');
//builder.append('\n');
//builder.append('\n');
Iterator<? extends TagKey<?>> keyIterator = registry.listTagIds().sorted(Formatting.TAG_ORDER).iterator();
@@ -68,6 +110,7 @@ public class TagRewriter extends SearchReplaceRewriter {
TagKey<?> tagKey = keyIterator.next();
final String keyPath = tagKey.location().getPath();
final String fieldName = fieldPrefix + Formatting.formatKeyAsField(keyPath);
replacedFields.remove(fieldName);
// tag field
String featureFlagName = Main.EXPERIMENTAL_TAGS.get(tagKey);
@@ -78,7 +121,7 @@ public class TagRewriter extends SearchReplaceRewriter {
builder.append(metadata.indent());
builder.append("%s<%s>".formatted(this.source.mainClass().simpleName(), this.importCollector.getShortName(tagRegistry.apiType()))).append(' ').append(fieldName);
builder.append(" = ");
builder.append("%s.getTag(%s, %s.minecraft(%s), %s.class)".formatted(Bukkit.class.getSimpleName(), registryFieldName, NamespacedKey.class.getSimpleName(), quoted(keyPath), tagRegistry.apiType().getSimpleName())); // assume type is imported properly
builder.append("%s.%s(%s, %s.minecraft(%s), %s.class)".formatted(Types.BUKKIT_CLASS.simpleName(), FETCH_METHOD, registryFieldName, Types.NAMESPACED_KEY.simpleName(), quoted(keyPath), tagRegistry.apiType().simpleName())); // assume type is imported properly
builder.append(';');
builder.append('\n');
@@ -87,5 +130,10 @@ public class TagRewriter extends SearchReplaceRewriter {
}
}
}
if (!replacedFields.isEmpty()) {
LOGGER.warn("Removed {} tag field(s) from {} because they are no longer present in the game:", replacedFields.size(), Types.TAG.canonicalName());
replacedFields.forEach(fieldName -> LOGGER.warn("- {}", fieldName));
}
}
}

View File

@@ -0,0 +1,4 @@
@NullMarked
package io.papermc.generator.rewriter.types.registry;
import org.jspecify.annotations.NullMarked;

View File

@@ -0,0 +1,141 @@
package io.papermc.generator.rewriter.types.simple;
import com.squareup.javapoet.ClassName;
import io.papermc.generator.resources.DataFileLoader;
import io.papermc.generator.resources.DataFiles;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.utils.BlockStateMapping;
import io.papermc.typewriter.ClassNamed;
import io.papermc.typewriter.replace.SearchMetadata;
import io.papermc.typewriter.replace.SearchReplaceRewriter;
import java.lang.reflect.Field;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.level.block.state.properties.Property;
import org.jspecify.annotations.Nullable;
import static io.papermc.generator.utils.Formatting.quoted;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
public class BlockPropertiesRewriter extends SearchReplaceRewriter {
private record BlockPropertyData(ClassNamed propertyClass, String accessorName) {
}
private static final Map<Class<?>, BlockPropertyData> DATA = Map.of(
BooleanProperty.class, new BlockPropertyData(Types.BOOLEAN_BLOCK_PROPERTY, "bool"),
IntegerProperty.class, new BlockPropertyData(Types.INTEGER_BLOCK_PROPERTY, "integer"),
EnumProperty.class, new BlockPropertyData(Types.ENUM_BLOCK_PROPERTY, "enumeration")
);
private record PropertyType(ClassNamed typeClass, ClassNamed propertyClass, @Nullable ClassNamed valueClass) {
}
private static final Map<Property<?>, PropertyType> MODIFIED_TYPES = Map.of(
BlockStateProperties.NOTE, new PropertyType(Types.BLOCK_PROPERTY, Types.NOTE_BLOCK_PROPERTY, Types.NOTE),
BlockStateProperties.ROTATION_16, new PropertyType(Types.ENUM_BLOCK_PROPERTY, Types.ROTATION_BLOCK_PROPERTY, Types.BLOCK_FACE)
);
private interface CodeContext {
void write(StringBuilder builder, Function<ClassNamed, String> imported);
}
private static final Map<Property<?>, CodeContext> PREDICATES = Map.of(
BlockStateProperties.FACING, (builder, imported) -> {
builder.append("%s::isCartesian".formatted(imported.apply(Types.BLOCK_FACE)));
},
BlockStateProperties.HORIZONTAL_FACING, (builder, imported) -> {
builder.append("%s::isCardinal".formatted(imported.apply(Types.BLOCK_FACE)));
},
BlockStateProperties.FACING_HOPPER, (builder, imported) -> {
builder.append("((%1$s<%2$s>) %2$s::isCartesian).and(face -> face != %2$s.UP)".formatted(
Predicate.class.getSimpleName(),
imported.apply(Types.BLOCK_FACE)
));
},
BlockStateProperties.VERTICAL_DIRECTION, (builder, $) -> {
builder.append("%1$s -> %1$s.getModY() != 0".formatted("face"));
},
BlockStateProperties.HORIZONTAL_AXIS, (builder, imported) -> {
builder.append("%s::isHorizontal".formatted(
imported.apply(Types.AXIS)
));
},
BlockStateProperties.RAIL_SHAPE_STRAIGHT, (builder, imported) -> {
builder.append("%s::isStraight".formatted(
imported.apply(Types.BLOCK_DATA_RAIL_SHAPE)
));
}
);
private static final Comparator<? super Map.Entry<Property<?>, Field>> FIELD_ORDER =
Comparator.<Map.Entry<Property<?>, Field>, String>comparing(entry -> entry.getKey().getClass().getSimpleName())
.thenComparing(entry -> entry.getValue().getName());
@Override
protected void insert(SearchMetadata metadata, StringBuilder builder) {
Map<Class<? extends Enum<? extends StringRepresentable>>, ClassName> enumTypes = DataFileLoader.get(DataFiles.BLOCK_STATE_ENUM_PROPERTY_TYPES);
for (Map.Entry<Property<?>, Field> entry : BlockStateMapping.GENERIC_FIELDS.entrySet().stream().sorted(FIELD_ORDER).toList()) {
Property<?> property = entry.getKey();
builder.append(metadata.indent());
builder.append("%s %s %s ".formatted(PUBLIC, STATIC, FINAL));
BlockPropertyData data = DATA.get(property.getClass());
if (MODIFIED_TYPES.containsKey(property)) {
PropertyType type = MODIFIED_TYPES.get(property);
builder.append("%s<%s> %s = register(new %s(%s));".formatted(
type.typeClass().simpleName(),
this.importCollector.getShortName(type.valueClass()),
entry.getValue().getName(),
type.propertyClass().simpleName(),
quoted(entry.getKey().getName())
));
} else {
builder.append(data.propertyClass().simpleName());
ClassNamed enumType = null;
if (property.getClass().equals(EnumProperty.class)) {
builder.append('<');
if (!enumTypes.containsKey(property.getValueClass())) {
throw new IllegalStateException("Unknown enum type for " + property);
}
enumType = Types.typed(enumTypes.get(property.getValueClass()));
builder.append(this.importCollector.getShortName(enumType));
builder.append('>');
}
builder.append(' ');
builder.append(entry.getValue().getName());
builder.append(" = ");
builder.append(data.accessorName());
builder.append('(');
builder.append(quoted(entry.getKey().getName()));
if (property instanceof IntegerProperty intProperty) {
builder.append(", ");
List<Integer> values = intProperty.getPossibleValues();
builder.append("%d, %d".formatted(values.getFirst(), values.getLast()));
} else if (enumType != null) {
builder.append(", ");
builder.append("%s.class".formatted(enumType.dottedNestedName())); // already imported
CodeContext predicate = PREDICATES.get(property);
if (predicate != null) {
builder.append(", ");
predicate.write(builder, name -> this.importCollector.getShortName(name));
}
}
builder.append(");");
}
builder.append('\n');
}
}
}

View File

@@ -1,13 +1,12 @@
package io.papermc.generator.rewriter.types.simple;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.rewriter.types.registry.RegistryFieldRewriter;
import io.papermc.generator.utils.BlockStateMapping;
import io.papermc.typewriter.util.ClassHelper;
import io.papermc.typewriter.ClassNamed;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.level.block.Block;
import org.bukkit.block.BlockType;
import org.bukkit.block.data.BlockData;
public class BlockTypeRewriter extends RegistryFieldRewriter<Block> {
@@ -17,11 +16,11 @@ public class BlockTypeRewriter extends RegistryFieldRewriter<Block> {
@Override
protected String rewriteFieldType(Holder.Reference<Block> reference) {
Class<? extends BlockData> blockData = BlockStateMapping.getBestSuitedApiClass(reference.value().getClass());
ClassNamed blockData = BlockStateMapping.getBestSuitedApiClass(reference.value().getClass());
if (blockData == null) {
blockData = BlockData.class;
blockData = Types.BLOCK_DATA;
}
return "%s<%s>".formatted(ClassHelper.retrieveFullNestedName(BlockType.Typed.class), this.importCollector.getShortName(blockData));
return "%s<%s>".formatted(Types.BLOCK_TYPE_TYPED.dottedNestedName(), this.importCollector.getShortName(blockData));
}
}

View File

@@ -1,6 +1,6 @@
package io.papermc.generator.rewriter.types.simple;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.utils.BasePackage;
import io.papermc.generator.utils.BlockStateMapping;
import io.papermc.typewriter.replace.SearchMetadata;
import io.papermc.typewriter.replace.SearchReplaceRewriter;
@@ -10,9 +10,9 @@ public class CraftBlockDataMapping extends SearchReplaceRewriter {
@Override
protected void insert(SearchMetadata metadata, StringBuilder builder) {
BlockStateMapping.MAPPING.entrySet().stream().sorted(Comparator.comparing(entry -> entry.getKey().getCanonicalName())).forEach(entry -> {
BlockStateMapping.getOrCreate().entrySet().stream().sorted(Comparator.comparing(entry -> entry.getKey().getCanonicalName())).forEach(entry -> {
builder.append(metadata.indent());
builder.append("register(%s.class, %s.block.impl.%s::new);".formatted(entry.getKey().getCanonicalName(), Types.BASE_PACKAGE, entry.getValue().implName()));
builder.append("register(%s.class, %s::new);".formatted(entry.getKey().getCanonicalName(), BasePackage.CRAFT_BUKKIT.name().concat(".block.impl.").concat(entry.getValue().implName())));
builder.append('\n');
});
}

View File

@@ -0,0 +1,92 @@
package io.papermc.generator.rewriter.types.simple;
import io.papermc.generator.registry.RegistryEntries;
import io.papermc.generator.resources.DataFileLoader;
import io.papermc.generator.resources.DataFiles;
import io.papermc.generator.resources.predicate.ItemPredicate;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.utils.Formatting;
import io.papermc.typewriter.ClassNamed;
import io.papermc.typewriter.context.IndentUnit;
import io.papermc.typewriter.replace.SearchMetadata;
import io.papermc.typewriter.replace.SearchReplaceRewriter;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
@Deprecated
public class CraftItemMetasRewriter extends SearchReplaceRewriter {
@Override
protected void insert(SearchMetadata metadata, StringBuilder builder) {
IndentUnit indentUnit = this.indentUnit();
ClassNamed itemType = RegistryEntries.byRegistryKey(Registries.ITEM).data().api().klass().name();
for (Map.Entry<ClassNamed, List<ItemPredicate>> entry : DataFileLoader.get(DataFiles.ITEM_META_PREDICATES).entrySet()) {
String field = DataFileLoader.get(DataFiles.ITEM_META_BRIDGE).get(entry.getKey()).field();
Iterator<ItemPredicate> predicateIterator = entry.getValue().iterator();
builder.append(metadata.indent());
builder.append("if (");
boolean beginning = true;
while (predicateIterator.hasNext()) {
ItemPredicate predicate = predicateIterator.next();
if (!beginning) {
builder.append(metadata.indent()).append(indentUnit);
}
switch (predicate) {
case ItemPredicate.IsElementPredicate isElementPredicate:
isElementPredicate.value()
.ifLeft(tagKey -> {
// flatten tag since they can change at runtime with plugins/data-packs
Iterator<Holder<Item>> tagValues = BuiltInRegistries.ITEM.getTagOrEmpty(tagKey).iterator();
while (tagValues.hasNext()) {
appendElementEquality(builder, itemType, tagValues.next().unwrapKey().orElseThrow().location());
if (tagValues.hasNext()) {
builder.append(" ||").append("\n");
builder.append(metadata.indent()).append(indentUnit);
}
}
})
.ifRight(element -> appendElementEquality(builder, itemType, element.unwrapKey().orElseThrow().location()));
break;
case ItemPredicate.IsClassPredicate isClassPredicate: {
String itemLikeName = isClassPredicate.againstBlock() ? "blockHandle" : "itemHandle";
if (itemLikeName.equals("itemHandle")) { // itemHandle is never null
builder.append("%s.getClass().equals(%s.class)".formatted(itemLikeName, this.importCollector.getShortName(isClassPredicate.value())));
} else {
builder.append("(%1$s != null && %1$s.getClass().equals(%2$s.class))".formatted(itemLikeName, this.importCollector.getShortName(isClassPredicate.value())));
}
break;
}
case ItemPredicate.InstanceOfPredicate instanceOfPredicate: {
String itemLikeName = instanceOfPredicate.againstBlock() ? "blockHandle" : "itemHandle";
builder.append("%s instanceof %s".formatted(itemLikeName, this.importCollector.getShortName(instanceOfPredicate.value())));
break;
}
}
if (predicateIterator.hasNext()) {
builder.append(" ||").append("\n");
}
beginning = false;
}
builder.append(") {").append("\n");
{
builder.append(metadata.indent()).append(indentUnit);
builder.append("return %s.asType(%s);".formatted(Types.CRAFT_ITEM_METAS.simpleName(), field));
builder.append("\n");
}
builder.append(metadata.indent());
builder.append("}").append("\n");
}
}
private static void appendElementEquality(StringBuilder builder, ClassNamed itemType, ResourceLocation id) {
builder.append("itemType == %s.%s".formatted(itemType.simpleName(), Formatting.formatKeyAsField(id.getPath())));
}
}

View File

@@ -1,12 +1,14 @@
package io.papermc.generator.rewriter.types.simple;
import io.papermc.generator.registry.RegistryEntries;
import io.papermc.generator.utils.Formatting;
import io.papermc.typewriter.ClassNamed;
import io.papermc.typewriter.replace.SearchMetadata;
import io.papermc.typewriter.replace.SearchReplaceRewriter;
import java.util.Locale;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import org.bukkit.potion.PotionType;
@Deprecated(forRemoval = true)
public class CraftPotionUtilRewriter extends SearchReplaceRewriter {
@@ -20,12 +22,13 @@ public class CraftPotionUtilRewriter extends SearchReplaceRewriter {
@Override
protected void insert(SearchMetadata metadata, StringBuilder builder) {
String upperStatePrefix = this.statePrefix.toUpperCase(Locale.ENGLISH);
ClassNamed potionType = RegistryEntries.byRegistryKey(Registries.POTION).data().api().klass().name();
BuiltInRegistries.POTION.keySet().stream()
.filter(key -> BuiltInRegistries.POTION.containsKey(key.withPath(path -> this.statePrefix + "_" + path)))
.sorted(Formatting.alphabeticKeyOrder(ResourceLocation::getPath)).forEach(key -> {
String keyedName = Formatting.formatKeyAsField(key.getPath());
builder.append(metadata.indent());
builder.append(".put(%s.%s, %s.%s_%s)".formatted(PotionType.class.getSimpleName(), keyedName, PotionType.class.getSimpleName(), upperStatePrefix, keyedName));
builder.append(".put(%1$s.%2$s, %1$s.%3$s_%4$s)".formatted(potionType.simpleName(), keyedName, upperStatePrefix, keyedName));
builder.append('\n');
});
}

View File

@@ -1,176 +1,37 @@
package io.papermc.generator.rewriter.types.simple;
import com.google.common.base.CaseFormat;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import io.papermc.generator.registry.RegistryEntries;
import io.papermc.generator.resources.DataFileLoader;
import io.papermc.generator.resources.DataFiles;
import io.papermc.generator.resources.data.EntityTypeData;
import io.papermc.generator.rewriter.types.registry.EnumRegistryRewriter;
import io.papermc.generator.types.goal.MobGoalNames;
import io.papermc.typewriter.ClassNamed;
import io.papermc.typewriter.preset.model.EnumValue;
import io.papermc.typewriter.util.ClassResolver;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import java.lang.reflect.ParameterizedType;
import io.papermc.typewriter.preset.model.EnumConstant;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.minecraft.Util;
import java.util.Objects;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
import static io.papermc.generator.utils.Formatting.quoted;
public class EntityTypeRewriter extends EnumRegistryRewriter<EntityType<?>> {
private static final Map<ResourceKey<EntityType<?>>, Class<? extends Entity>> ENTITY_GENERIC_TYPES =
RegistryEntries.byRegistryKey(Registries.ENTITY_TYPE).getFields(field -> {
if (field.getGenericType() instanceof ParameterizedType complexType && complexType.getActualTypeArguments().length == 1) {
return (Class<? extends Entity>) complexType.getActualTypeArguments()[0];
}
return null;
});
private static final Map<String, String> CLASS_RENAMES = ImmutableMap.<String, String>builder()
.put("ExperienceBottle", "ThrownExpBottle")
.put("EyeOfEnder", "EnderSignal")
.put("EndCrystal", "EnderCrystal")
.put("FireworkRocket", "Firework")
.put("FishingBobber", "FishHook")
.put("LeashKnot", "LeashHitch")
.put("LightningBolt", "LightningStrike")
.put("Tnt", "TNTPrimed")
.put("Minecart", "RideableMinecart")
.put("ChestMinecart", "StorageMinecart")
.put("CommandBlockMinecart", "CommandMinecart")
.put("TntMinecart", "ExplosiveMinecart")
.put("FurnaceMinecart", "PoweredMinecart")
.buildOrThrow();
@Deprecated
private static final Object2IntMap<EntityType<?>> LEGACY_ID = Util.make(new Object2IntOpenHashMap<>(), map -> {
map.put(EntityType.ITEM, 1);
map.put(EntityType.EXPERIENCE_ORB, 2);
map.put(EntityType.AREA_EFFECT_CLOUD, 3);
map.put(EntityType.ELDER_GUARDIAN, 4);
map.put(EntityType.WITHER_SKELETON, 5);
map.put(EntityType.STRAY, 6);
map.put(EntityType.EGG, 7);
map.put(EntityType.LEASH_KNOT, 8);
map.put(EntityType.PAINTING, 9);
map.put(EntityType.ARROW, 10);
map.put(EntityType.SNOWBALL, 11);
map.put(EntityType.FIREBALL, 12);
map.put(EntityType.SMALL_FIREBALL, 13);
map.put(EntityType.ENDER_PEARL, 14);
map.put(EntityType.EYE_OF_ENDER, 15);
map.put(EntityType.SPLASH_POTION, 16);
map.put(EntityType.EXPERIENCE_BOTTLE, 17);
map.put(EntityType.ITEM_FRAME, 18);
map.put(EntityType.WITHER_SKULL, 19);
map.put(EntityType.TNT, 20);
map.put(EntityType.FALLING_BLOCK, 21);
map.put(EntityType.FIREWORK_ROCKET, 22);
map.put(EntityType.HUSK, 23);
map.put(EntityType.SPECTRAL_ARROW, 24);
map.put(EntityType.SHULKER_BULLET, 25);
map.put(EntityType.DRAGON_FIREBALL, 26);
map.put(EntityType.ZOMBIE_VILLAGER, 27);
map.put(EntityType.SKELETON_HORSE, 28);
map.put(EntityType.ZOMBIE_HORSE, 29);
map.put(EntityType.ARMOR_STAND, 30);
map.put(EntityType.DONKEY, 31);
map.put(EntityType.MULE, 32);
map.put(EntityType.EVOKER_FANGS, 33);
map.put(EntityType.EVOKER, 34);
map.put(EntityType.VEX, 35);
map.put(EntityType.VINDICATOR, 36);
map.put(EntityType.ILLUSIONER, 37);
map.put(EntityType.COMMAND_BLOCK_MINECART, 40);
map.put(EntityType.MINECART, 42);
map.put(EntityType.CHEST_MINECART, 43);
map.put(EntityType.FURNACE_MINECART, 44);
map.put(EntityType.TNT_MINECART, 45);
map.put(EntityType.HOPPER_MINECART, 46);
map.put(EntityType.SPAWNER_MINECART, 47);
map.put(EntityType.CREEPER, 50);
map.put(EntityType.SKELETON, 51);
map.put(EntityType.SPIDER, 52);
map.put(EntityType.GIANT, 53);
map.put(EntityType.ZOMBIE, 54);
map.put(EntityType.SLIME, 55);
map.put(EntityType.GHAST, 56);
map.put(EntityType.ZOMBIFIED_PIGLIN, 57);
map.put(EntityType.ENDERMAN, 58);
map.put(EntityType.CAVE_SPIDER, 59);
map.put(EntityType.SILVERFISH, 60);
map.put(EntityType.BLAZE, 61);
map.put(EntityType.MAGMA_CUBE, 62);
map.put(EntityType.ENDER_DRAGON, 63);
map.put(EntityType.WITHER, 64);
map.put(EntityType.BAT, 65);
map.put(EntityType.WITCH, 66);
map.put(EntityType.ENDERMITE, 67);
map.put(EntityType.GUARDIAN, 68);
map.put(EntityType.SHULKER, 69);
map.put(EntityType.PIG, 90);
map.put(EntityType.SHEEP, 91);
map.put(EntityType.COW, 92);
map.put(EntityType.CHICKEN, 93);
map.put(EntityType.SQUID, 94);
map.put(EntityType.WOLF, 95);
map.put(EntityType.MOOSHROOM, 96);
map.put(EntityType.SNOW_GOLEM, 97);
map.put(EntityType.OCELOT, 98);
map.put(EntityType.IRON_GOLEM, 99);
map.put(EntityType.HORSE, 100);
map.put(EntityType.RABBIT, 101);
map.put(EntityType.POLAR_BEAR, 102);
map.put(EntityType.LLAMA, 103);
map.put(EntityType.LLAMA_SPIT, 104);
map.put(EntityType.PARROT, 105);
map.put(EntityType.VILLAGER, 120);
map.put(EntityType.END_CRYSTAL, 200);
});
private static final ClassResolver runtime = new ClassResolver(EntityTypeRewriter.class.getClassLoader());
public EntityTypeRewriter() {
super(Registries.ENTITY_TYPE, false);
super(Registries.ENTITY_TYPE);
}
@Override
protected EnumValue.Builder rewriteEnumValue(Holder.Reference<EntityType<?>> reference) {
protected void rewriteConstant(EnumConstant.Builder builder, Holder.Reference<EntityType<?>> reference) {
EntityTypeData data = Objects.requireNonNull(DataFileLoader.get(DataFiles.ENTITY_TYPES).get(reference.key()), () -> "Missing entity type data for " + reference);
String path = reference.key().location().getPath();
List<String> arguments = new ArrayList<>(4);
arguments.add(quoted(path));
arguments.add(toBukkitClass(reference).concat(".class"));
arguments.add(Integer.toString(LEGACY_ID.getOrDefault(reference.value(), -1)));
arguments.add(this.importCollector.getShortName(data.api()).concat(".class"));
arguments.add(Integer.toString(data.legacyId()));
if (!reference.value().canSummon()) {
arguments.add(Boolean.FALSE.toString());
}
return super.rewriteEnumValue(reference).arguments(arguments);
}
private String toBukkitClass(Holder.Reference<EntityType<?>> reference) {
Class<? extends Entity> internalClass = ENTITY_GENERIC_TYPES.get(reference.key());
if (Mob.class.isAssignableFrom(internalClass)) {
return this.importCollector.getShortName(MobGoalNames.BUKKIT_BRIDGE.get((Class<? extends Mob>) internalClass));
}
String className = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, reference.key().location().getPath()); // use the key instead of the internal class name since name match a bit more
ClassNamed resolvedClass = this.classNamedView.findFirst(CLASS_RENAMES.getOrDefault(className, className)).resolve(runtime);
Preconditions.checkArgument(org.bukkit.entity.Entity.class.isAssignableFrom(resolvedClass.knownClass()), "Generic type must be an entity");
return this.importCollector.getShortName(this.classNamedView.findFirst(CLASS_RENAMES.getOrDefault(className, className)).resolve(runtime));
builder.arguments(arguments);
}
}

View File

@@ -1,13 +1,17 @@
package io.papermc.generator.rewriter.types.simple;
import io.papermc.generator.resources.DataFileLoader;
import io.papermc.generator.resources.DataFiles;
import io.papermc.generator.resources.predicate.ItemPredicate;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.rewriter.types.registry.RegistryFieldRewriter;
import io.papermc.typewriter.util.ClassHelper;
import io.papermc.typewriter.ClassNamed;
import java.util.List;
import java.util.Map;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import org.bukkit.inventory.ItemType;
import org.bukkit.inventory.meta.ItemMeta;
@Deprecated // bad generic
public class ItemTypeRewriter extends RegistryFieldRewriter<Item> {
@@ -22,6 +26,21 @@ public class ItemTypeRewriter extends RegistryFieldRewriter<Item> {
return super.rewriteFieldType(reference);
}
return "%s<%s>".formatted(ClassHelper.retrieveFullNestedName(ItemType.Typed.class), ItemMeta.class.getSimpleName());
ClassNamed implMetaName = null;
mainLoop:
for (Map.Entry<ClassNamed, List<ItemPredicate>> entry : DataFileLoader.get(DataFiles.ITEM_META_PREDICATES).entrySet()) {
for (ItemPredicate predicate : entry.getValue()) {
if (predicate.matches(reference)) {
implMetaName = entry.getKey();
break mainLoop;
}
}
}
ClassNamed metaName = null;
if (implMetaName != null) {
metaName = DataFileLoader.get(DataFiles.ITEM_META_BRIDGE).get(implMetaName).api();
}
return "%s<%s>".formatted(Types.ITEM_TYPE_TYPED.dottedNestedName(), metaName != null ? this.importCollector.getShortName(metaName) : Types.ITEM_META.simpleName());
}
}

View File

@@ -1,6 +1,7 @@
package io.papermc.generator.rewriter.types.simple;
import com.mojang.logging.LogUtils;
import io.papermc.generator.Main;
import io.papermc.typewriter.replace.SearchMetadata;
import io.papermc.typewriter.replace.SearchReplaceRewriter;
import java.awt.Color;
@@ -11,7 +12,6 @@ import org.slf4j.Logger;
public class MapPaletteRewriter extends SearchReplaceRewriter {
private static final Logger LOGGER = LogUtils.getLogger();
private static final boolean UPDATING = Boolean.getBoolean("paper.updatingMinecraft");
@Override
protected void insert(SearchMetadata metadata, StringBuilder builder) {
@@ -34,7 +34,7 @@ public class MapPaletteRewriter extends SearchReplaceRewriter {
}
}
if (UPDATING) {
if (Main.IS_UPDATING) {
LOGGER.warn("There are {} map colors, check CraftMapView#render for possible change and update md5 hash in CraftMapColorCache", count);
}
}

View File

@@ -1,9 +1,13 @@
package io.papermc.generator.rewriter.types.simple;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.rewriter.types.registry.EnumRegistryRewriter;
import io.papermc.generator.utils.BlockStateMapping;
import io.papermc.generator.utils.Formatting;
import io.papermc.typewriter.preset.model.EnumValue;
import io.papermc.typewriter.ClassNamed;
import io.papermc.typewriter.preset.model.EnumConstant;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.BuiltInRegistries;
@@ -11,9 +15,6 @@ import net.minecraft.core.registries.Registries;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.WallSignBlock;
import org.bukkit.block.data.BlockData;
import static io.papermc.generator.utils.Formatting.asCode;
@Deprecated(forRemoval = true)
public class MaterialRewriter {
@@ -23,7 +24,7 @@ public class MaterialRewriter {
public static class Blocks extends EnumRegistryRewriter<Block> {
public Blocks() {
super(Registries.BLOCK, false);
super(Registries.BLOCK);
}
@Override
@@ -33,10 +34,12 @@ public class MaterialRewriter {
}
@Override
protected EnumValue.Builder rewriteEnumValue(Holder.Reference<Block> reference) {
EnumValue.Builder value = super.rewriteEnumValue(reference);
protected void rewriteConstant(EnumConstant.Builder builder, Holder.Reference<Block> reference) {
Block block = reference.value();
if (BlockStateMapping.MAPPING.containsKey(block.getClass())) {
List<String> args = new ArrayList<>(3);
args.add(Integer.toString(-1)); // legacy id (not needed for non legacy material)
if (BlockStateMapping.getOrCreate().containsKey(block.getClass())) {
// some block can also be represented as item in that enum
// doing a double job
Optional<Item> equivalentItem = BuiltInRegistries.ITEM.getOptional(reference.key().location());
@@ -47,16 +50,16 @@ public class MaterialRewriter {
equivalentItem = Optional.of(block.asItem());
}
Class<?> blockData = BlockStateMapping.getBestSuitedApiClass(block.getClass());
ClassNamed blockData = BlockStateMapping.getBestSuitedApiClass(block.getClass());
if (blockData == null) {
blockData = BlockData.class;
blockData = Types.BLOCK_DATA;
}
if (equivalentItem.isPresent() && equivalentItem.get().getDefaultMaxStackSize() != Item.DEFAULT_MAX_STACK_SIZE) {
return value.arguments(Integer.toString(-1), Integer.toString(equivalentItem.get().getDefaultMaxStackSize()), this.importCollector.getShortName(blockData).concat(".class"));
args.add(Integer.toString(equivalentItem.get().getDefaultMaxStackSize())); // max stack size
}
return value.arguments(Integer.toString(-1), this.importCollector.getShortName(blockData).concat(".class"));
args.add(this.importCollector.getShortName(blockData).concat(".class")); // block data class
}
return value.argument(Integer.toString(-1)); // id not needed for non legacy material
builder.arguments(args);
}
}
@@ -79,7 +82,7 @@ public class MaterialRewriter {
public static class Items extends EnumRegistryRewriter<Item> {
public Items() {
super(Registries.ITEM, false);
super(Registries.ITEM);
}
@Override
@@ -89,15 +92,17 @@ public class MaterialRewriter {
}
@Override
protected EnumValue.Builder rewriteEnumValue(Holder.Reference<Item> reference) {
EnumValue.Builder value = super.rewriteEnumValue(reference);
protected void rewriteConstant(EnumConstant.Builder builder, Holder.Reference<Item> reference) {
Item item = reference.value();
List<String> args = new ArrayList<>(2);
args.add(Integer.toString(-1)); // legacy id (not needed for non legacy material)
int maxStackSize = item.getDefaultMaxStackSize();
if (maxStackSize != Item.DEFAULT_MAX_STACK_SIZE) {
return value.arguments(asCode(-1, maxStackSize));
args.add(Integer.toString(maxStackSize));
}
return value.argument(Integer.toString(-1)); // id not needed for non legacy material
builder.arguments(args);
}
}
}

View File

@@ -2,8 +2,10 @@ package io.papermc.generator.rewriter.types.simple;
import com.google.gson.internal.Primitives;
import io.papermc.generator.registry.RegistryEntries;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.rewriter.types.registry.RegistryFieldRewriter;
import io.papermc.generator.utils.ClassHelper;
import io.papermc.typewriter.ClassNamed;
import java.lang.reflect.ParameterizedType;
import java.util.Map;
import java.util.Set;
@@ -21,8 +23,6 @@ import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities;
import net.minecraft.world.entity.ai.memory.WalkTarget;
import net.minecraft.world.level.pathfinder.Path;
import net.minecraft.world.phys.Vec3;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import static io.papermc.generator.utils.Formatting.quoted;
@@ -60,8 +60,8 @@ public class MemoryKeyRewriter extends RegistryFieldRewriter<MemoryModuleType<?>
Entity.class
);
private static final Map<Class<?>, Class<?>> API_BRIDGE = Map.of(
GlobalPos.class, Location.class
private static final Map<Class<?>, ClassNamed> API_BRIDGE = Map.of(
GlobalPos.class, Types.LOCATION
);
private static final Map<String, String> FIELD_RENAMES = Map.of(
@@ -83,7 +83,7 @@ public class MemoryKeyRewriter extends RegistryFieldRewriter<MemoryModuleType<?>
return true;
}
private @MonotonicNonNull Class<?> apiMemoryType;
private @MonotonicNonNull ClassNamed apiMemoryType;
@Override
protected String rewriteFieldType(Holder.Reference<MemoryModuleType<?>> reference) {
@@ -92,10 +92,10 @@ public class MemoryKeyRewriter extends RegistryFieldRewriter<MemoryModuleType<?>
if (!Primitives.isWrapperType(memoryType) && API_BRIDGE.containsKey(memoryType)) {
this.apiMemoryType = API_BRIDGE.get(memoryType);
} else {
this.apiMemoryType = memoryType;
this.apiMemoryType = new ClassNamed(memoryType);
}
return "%s<%s>".formatted(this.fieldClass.simpleName(), this.importCollector.getShortName(this.apiMemoryType));
return "%s<%s>".formatted(this.entry.data().api().klass().name().simpleName(), this.importCollector.getShortName(this.apiMemoryType));
}
@Override
@@ -107,10 +107,10 @@ public class MemoryKeyRewriter extends RegistryFieldRewriter<MemoryModuleType<?>
@Override
protected String rewriteFieldValue(Holder.Reference<MemoryModuleType<?>> reference) {
return "new %s<>(%s.minecraft(%s), %s.class)".formatted(
this.fieldClass.simpleName(),
NamespacedKey.class.getSimpleName(),
this.entry.data().api().klass().name().simpleName(),
Types.NAMESPACED_KEY.simpleName(),
quoted(reference.key().location().getPath()),
this.apiMemoryType.getSimpleName() // assume the type is already import (see above in rewriteFieldType)
this.apiMemoryType.simpleName() // assume the type is already imported (see above in rewriteFieldType)
);
}
}

View File

@@ -1,15 +1,11 @@
package io.papermc.generator.rewriter.types.simple;
import com.google.common.collect.ImmutableMap;
import io.papermc.generator.registry.RegistryEntries;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.rewriter.types.registry.EnumRegistryRewriter;
import io.papermc.generator.utils.ClassHelper;
import io.papermc.generator.utils.Formatting;
import io.papermc.typewriter.preset.model.EnumValue;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.Collections;
import java.util.IdentityHashMap;
import io.papermc.typewriter.preset.model.EnumConstant;
import java.util.Map;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.BuiltInRegistries;
@@ -20,7 +16,6 @@ import net.minecraft.stats.Stats;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import org.bukkit.Statistic;
import static io.papermc.generator.utils.Formatting.quoted;
@@ -65,12 +60,12 @@ public class StatisticRewriter {
public static class Custom extends EnumRegistryRewriter<ResourceLocation> {
public Custom() {
super(Registries.CUSTOM_STAT, false);
super(Registries.CUSTOM_STAT);
}
@Override
protected EnumValue.Builder rewriteEnumValue(Holder.Reference<ResourceLocation> reference) {
return super.rewriteEnumValue(reference).rename(name -> FIELD_RENAMES.getOrDefault(name, name));
protected void rewriteConstant(EnumConstant.Builder builder, Holder.Reference<ResourceLocation> reference) {
builder.rename(name -> FIELD_RENAMES.getOrDefault(name, name));
}
}
@@ -81,16 +76,14 @@ public class StatisticRewriter {
);
public CraftCustom() {
super(Registries.CUSTOM_STAT, false);
super(Registries.CUSTOM_STAT);
}
@Override
protected EnumValue.Builder rewriteEnumValue(Holder.Reference<ResourceLocation> reference) {
String keyedName = Formatting.formatKeyAsField(reference.key().location().getPath());
return super.rewriteEnumValue(reference)
protected void rewriteConstant(EnumConstant.Builder builder, Holder.Reference<ResourceLocation> reference) {
builder
.rename(name -> FIELD_RENAMES.getOrDefault(name, name))
.argument("%s.%s".formatted(Stats.class.getSimpleName(), INTERNAL_FIELD_RENAMES.getOrDefault(keyedName, keyedName)));
.argument("%s.%s".formatted(Stats.class.getSimpleName(), INTERNAL_FIELD_RENAMES.getOrDefault(builder.initialName(), builder.initialName())));
}
}
@@ -102,30 +95,8 @@ public class StatisticRewriter {
EntityType.class, "ENTITY"
);
private static final Map<StatType<?>, Class<?>> FIELD_GENERIC_TYPE;
static {
final Map<StatType<?>, Class<?>> map = new IdentityHashMap<>();
try {
for (Field field : Stats.class.getDeclaredFields()) {
if (field.getType() != StatType.class) {
continue;
}
if (ClassHelper.isStaticConstant(field, Modifier.PUBLIC)) {
java.lang.reflect.Type genericType = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
map.put((StatType<?>) field.get(null), ClassHelper.eraseType(genericType));
}
}
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
FIELD_GENERIC_TYPE = Collections.unmodifiableMap(map);
}
public Type() {
super(Registries.STAT_TYPE, false);
super(Registries.STAT_TYPE);
}
@Override
@@ -135,23 +106,22 @@ public class StatisticRewriter {
}
@Override
protected EnumValue.Builder rewriteEnumValue(Holder.Reference<StatType<?>> reference) {
Class<?> genericType = FIELD_GENERIC_TYPE.get(reference.value());
protected void rewriteConstant(EnumConstant.Builder builder, Holder.Reference<StatType<?>> reference) {
Class<?> genericType = RegistryEntries.byRegistryKey(reference.value().getRegistry().key()).elementClass();
if (!TYPE_MAPPING.containsKey(genericType)) {
throw new IllegalStateException("Unable to translate stat type generic " + genericType.getCanonicalName() + " into the api!");
}
return super.rewriteEnumValue(reference)
builder
.rename(name -> FIELD_RENAMES.getOrDefault(name, name))
.argument("%s.%s".formatted(Statistic.Type.class.getSimpleName(), TYPE_MAPPING.get(genericType))); // find a more direct way?
.argument("%s.%s".formatted(Types.STATISTIC_TYPE.simpleName(), TYPE_MAPPING.get(genericType))); // find a more direct way?
}
}
public static class CraftType extends EnumRegistryRewriter<StatType<?>> {
public CraftType() {
super(Registries.STAT_TYPE, false);
super(Registries.STAT_TYPE);
}
@Override
@@ -161,8 +131,8 @@ public class StatisticRewriter {
}
@Override
protected EnumValue.Builder rewriteEnumValue(Holder.Reference<StatType<?>> reference) {
return super.rewriteEnumValue(reference)
protected void rewriteConstant(EnumConstant.Builder builder, Holder.Reference<StatType<?>> reference) {
builder
.rename(name -> FIELD_RENAMES.getOrDefault(name, name))
.argument("%s.withDefaultNamespace(%s)".formatted(ResourceLocation.class.getSimpleName(), quoted(reference.key().location().getPath())));
}

View File

@@ -0,0 +1,80 @@
package io.papermc.generator.rewriter.types.simple.trial;
import io.papermc.generator.rewriter.types.registry.RegistryFieldRewriter;
import io.papermc.typewriter.parser.Lexer;
import io.papermc.typewriter.parser.sequence.SequenceTokens;
import io.papermc.typewriter.parser.sequence.TokenTaskBuilder;
import io.papermc.typewriter.parser.token.CharSequenceBlockToken;
import io.papermc.typewriter.parser.token.CharSequenceToken;
import io.papermc.typewriter.parser.token.TokenType;
import io.papermc.typewriter.replace.SearchMetadata;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.entity.ai.attributes.Attribute;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
public class AttributeRewriter extends RegistryFieldRewriter<Attribute> {
public AttributeRewriter() {
super(Registries.ATTRIBUTE, "getAttribute");
}
private static final Set<TokenType> FORMAT_TOKENS = EnumSet.of(
TokenType.COMMENT,
TokenType.SINGLE_COMMENT
);
private @MonotonicNonNull Map<String, CharSequenceBlockToken> javadocsPerConstant;
private Map<String, CharSequenceBlockToken> parseConstantJavadocs(String content) {
if (content.isBlank()) {
return Map.of();
}
Map<String, CharSequenceBlockToken> map = new HashMap<>();
Lexer lex = new Lexer(content.toCharArray());
lex.checkMarkdownDocComments = !this.sourcesMetadata.canSkipMarkdownDocComments();
SequenceTokens.wrap(lex, FORMAT_TOKENS)
.group(action -> {
ProtoConstant constant = new ProtoConstant();
action
.map(TokenType.JAVADOC, token -> { // /** */
constant.javadocs(((CharSequenceBlockToken) token));
}, TokenTaskBuilder::asOptional)
.skip(TokenType.IDENTIFIER) // Attribute
.map(TokenType.IDENTIFIER, token -> { // <name>
constant.name(((CharSequenceToken) token).value());
})
.skip(TokenType.IDENTIFIER) // getAttribute
.skipClosure(TokenType.LPAREN, TokenType.RPAREN, true) // (*)
.map(TokenType.SECO, $ -> { // ;
if (constant.isComplete()) {
map.put(constant.name(), constant.javadocs());
}
});
}, TokenTaskBuilder::asRepeatable)
.executeOrThrow();
return map;
}
@Override
protected void insert(SearchMetadata metadata, StringBuilder builder) {
this.javadocsPerConstant = parseConstantJavadocs(metadata.replacedContent());
super.insert(metadata, builder);
}
@Override
protected void rewriteJavadocs(Holder.Reference<Attribute> reference, String replacedContent, String indent, StringBuilder builder) {
String constantName = this.rewriteFieldName(reference);
if (this.javadocsPerConstant.containsKey(constantName)) {
CharSequenceBlockToken token = this.javadocsPerConstant.get(constantName);
builder.append(indent).append(replacedContent, token.pos(), token.endPos()).append('\n');
}
}
}

View File

@@ -7,7 +7,7 @@ import io.papermc.typewriter.parser.token.CharSequenceBlockToken;
import io.papermc.typewriter.parser.token.CharSequenceToken;
import io.papermc.typewriter.parser.token.TokenType;
import io.papermc.typewriter.preset.EnumCloneRewriter;
import io.papermc.typewriter.preset.model.EnumValue;
import io.papermc.typewriter.preset.model.EnumConstant;
import io.papermc.typewriter.replace.SearchMetadata;
import java.util.EnumSet;
import java.util.HashMap;
@@ -35,6 +35,10 @@ public class PoseRewriter extends EnumCloneRewriter<Pose> {
private @MonotonicNonNull Map<String, CharSequenceBlockToken> javadocsPerConstant;
private Map<String, CharSequenceBlockToken> parseConstantJavadocs(String content) {
if (content.isBlank()) {
return Map.of();
}
Map<String, CharSequenceBlockToken> map = new HashMap<>();
Lexer lex = new Lexer(content.toCharArray());
@@ -77,17 +81,17 @@ public class PoseRewriter extends EnumCloneRewriter<Pose> {
}
@Override
protected EnumValue.Builder rewriteEnumValue(Pose item) {
return super.rewriteEnumValue(item).rename(name -> RENAMES.getOrDefault(name, name));
protected void rewriteConstant(EnumConstant.Builder builder, Pose item) {
builder.rename(name -> RENAMES.getOrDefault(name, name));
}
@Override
protected void appendEnumValue(Pose item, StringBuilder builder, String indent, boolean reachEnd) {
protected void appendConstant(Pose item, StringBuilder builder, String indent, boolean reachEnd) {
String constantName = RENAMES.getOrDefault(item.name(), item.name());
if (this.javadocsPerConstant.containsKey(constantName)) {
CharSequenceBlockToken token = this.javadocsPerConstant.get(constantName);
builder.append(indent).append(this.metadata.replacedContent(), token.pos(), token.endPos()).append('\n');
}
super.appendEnumValue(item, builder, indent, reachEnd);
super.appendConstant(item, builder, indent, reachEnd);
}
}

View File

@@ -12,7 +12,6 @@ import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.entity.npc.VillagerProfession;
@@ -32,6 +31,10 @@ public class VillagerProfessionRewriter extends RegistryFieldRewriter<VillagerPr
private @MonotonicNonNull Map<String, CharSequenceBlockToken> javadocsPerConstant;
private Map<String, CharSequenceBlockToken> parseConstantJavadocs(String content) {
if (content.isBlank()) {
return Map.of();
}
Map<String, CharSequenceBlockToken> map = new HashMap<>();
Lexer lex = new Lexer(content.toCharArray());
@@ -40,46 +43,22 @@ public class VillagerProfessionRewriter extends RegistryFieldRewriter<VillagerPr
.group(action -> {
ProtoConstant constant = new ProtoConstant();
action
.map(TokenType.JAVADOC, token -> {
.map(TokenType.JAVADOC, token -> { // /** */
constant.javadocs(((CharSequenceBlockToken) token));
}, TokenTaskBuilder::asOptional)
.skipQualifiedName(Predicate.isEqual(TokenType.JAVADOC))
.map(TokenType.IDENTIFIER, token -> {
.skip(TokenType.IDENTIFIER) // Profession
.map(TokenType.IDENTIFIER, token -> { // <name>
constant.name(((CharSequenceToken) token).value());
})
.skip(TokenType.IDENTIFIER)
.skipClosure(TokenType.LPAREN, TokenType.RPAREN, true)
.map(TokenType.SECO, $ -> {
.skip(TokenType.IDENTIFIER) // getProfession
.skipClosure(TokenType.LPAREN, TokenType.RPAREN, true) // (*)
.map(TokenType.SECO, $ -> { // ;
if (constant.isComplete()) {
map.put(constant.name(), constant.javadocs());
}
});
}, TokenTaskBuilder::asRepeatable)
.executeOrThrow();
/*
for enums:
Set<TokenType> endMarkers = Set.of(TokenType.CO, TokenType.SECO); // move to static
SequenceTokens.wrap(lex, FORMAT_TOKENS)
.group(action -> {
ProtoConstant constant = new ProtoConstant();
action
.map(TokenType.JAVADOC, token -> {
constant.javadocs(((CharSequenceBlockToken) token).value());
}, TokenTaskBuilder::asOptional)
.map(TokenType.IDENTIFIER, token -> {
constant.name(((CharSequenceToken) token).value());
})
.skipClosure(TokenType.LPAREN, TokenType.RPAREN, true)
.skipClosure(TokenType.LSCOPE, TokenType.RSCOPE, true)
.map(endMarkers::contains, $ -> {
// this part will probably fail for the last entry for enum without end (,;)
if (constant.isComplete()) {
map.put(constant.name(), constant.javadocs());
}
});
}, TokenTaskBuilder::asRepeatable)
.executeOrThrow();
*/
return map;
}

View File

@@ -1,10 +1,11 @@
package io.papermc.generator.rewriter.utils;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.utils.experimental.SingleFlagHolder;
import io.papermc.typewriter.ClassNamed;
import io.papermc.typewriter.context.ImportCollector;
import io.papermc.typewriter.util.ClassHelper;
import java.lang.annotation.Annotation;
import org.bukkit.MinecraftExperimental;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
@@ -20,6 +21,22 @@ public final class Annotations {
}
public static String annotation(Class<? extends Annotation> clazz, ImportCollector collector, String param, String value) {
return annotation(new ClassNamed(clazz), collector, param, value);
}
public static String annotation(Class<? extends Annotation> clazz, ImportCollector collector, String value) {
return annotation(new ClassNamed(clazz), collector, value);
}
public static String annotation(ClassNamed clazz, ImportCollector collector) {
return "@%s".formatted(collector.getShortName(clazz));
}
public static String annotationStyle(ClassNamed clazz) {
return "@%s".formatted(clazz.dottedNestedName());
}
public static String annotation(ClassNamed clazz, ImportCollector collector, String param, String value) {
String annotation = annotation(clazz, collector);
if (value.isEmpty()) {
return annotation;
@@ -27,7 +44,7 @@ public final class Annotations {
return "%s(%s = %s)".formatted(annotation, param, value);
}
public static String annotation(Class<? extends Annotation> clazz, ImportCollector collector, String value) {
public static String annotation(ClassNamed clazz, ImportCollector collector, String value) {
String annotation = annotation(clazz, collector);
if (value.isEmpty()) {
return annotation;
@@ -36,8 +53,8 @@ public final class Annotations {
}
public static void experimentalAnnotations(StringBuilder builder, String indent, ImportCollector importCollector, SingleFlagHolder requiredFeature) {
builder.append(indent).append(annotation(MinecraftExperimental.class, importCollector, "%s.%s".formatted(
importCollector.getShortName(MinecraftExperimental.Requires.class, false), requiredFeature.asAnnotationMember().name()
builder.append(indent).append(annotation(Types.MINECRAFT_EXPERIMENTAL, importCollector, "%s.%s".formatted(
importCollector.getShortName(Types.MINECRAFT_EXPERIMENTAL_REQUIRES, false), requiredFeature.asAnnotationMember()
))).append('\n');
builder.append(indent).append(annotation(ApiStatus.Experimental.class, importCollector)).append('\n');

View File

@@ -0,0 +1,46 @@
package io.papermc.generator.tasks;
import com.mojang.logging.LogUtils;
import io.papermc.generator.Main;
import io.papermc.generator.resources.DataFile;
import io.papermc.generator.resources.DataFileLoader;
import io.papermc.generator.resources.FlattenSliceResult;
import io.papermc.generator.resources.SliceResult;
import java.io.IOException;
import java.nio.file.Path;
import org.slf4j.Logger;
public class PrepareInputFiles {
static {
Main.bootStrap(true);
}
private static final Logger LOGGER = LogUtils.getLogger();
public static void main(String[] args) throws IOException {
Path resourceDir = Path.of(args[0]);
for (DataFile<?, ?, ?> file : DataFileLoader.DATA_FILES_VIEW.values()) {
upgrade(resourceDir, file);
}
}
private static <V, A, R> void upgrade(Path resourceDir, DataFile<V, A, R> file) throws IOException {
Path filePath = Path.of(file.path());
SliceResult<A, R> result = file.upgrade(resourceDir.resolve(filePath));
if (result.isEmpty()) {
return;
}
FlattenSliceResult<String, String> printedResult = file.print(result);
if (printedResult.added() != null) {
LOGGER.info("Added the following elements in {}:", filePath);
LOGGER.info(printedResult.added());
}
if (printedResult.removed() != null) {
LOGGER.warn("Removed the following keys in {}:", filePath);
LOGGER.warn(printedResult.removed());
}
}
}

View File

@@ -1,9 +1,10 @@
package io.papermc.generator.rewriter.utils;
package io.papermc.generator.tasks;
import io.papermc.generator.Main;
import io.papermc.generator.Rewriters;
import io.papermc.generator.rewriter.registration.PaperPatternSourceSetRewriter;
import io.papermc.paper.generated.GeneratedFrom;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.rewriter.utils.Annotations;
import io.papermc.typewriter.SourceFile;
import io.papermc.typewriter.SourceRewriter;
import io.papermc.typewriter.context.FileMetadata;
@@ -35,12 +36,14 @@ public class ScanOldGeneratedSourceCode {
public static void main(String[] args) throws IOException {
PaperPatternSourceSetRewriter apiSourceSet = new PaperPatternSourceSetRewriter();
PaperPatternSourceSetRewriter serverSourceSet = new PaperPatternSourceSetRewriter();
PaperPatternSourceSetRewriter implSourceSet = new PaperPatternSourceSetRewriter();
PaperPatternSourceSetRewriter implTestSourceSet = new PaperPatternSourceSetRewriter();
Rewriters.bootstrap(apiSourceSet, serverSourceSet);
Rewriters.bootstrap(apiSourceSet, implSourceSet, implTestSourceSet);
checkOutdated(apiSourceSet, Path.of(args[0], "src/main/java"));
checkOutdated(serverSourceSet, Path.of(args[1], "src/main/java"));
checkOutdated(implSourceSet, Path.of(args[1], "src/main/java"));
checkOutdated(implTestSourceSet, Path.of(args[1], "src/test/java"));
}
private static void checkOutdated(PaperPatternSourceSetRewriter sourceSetRewriter, Path sourceSet) throws IOException {
@@ -86,7 +89,7 @@ public class ScanOldGeneratedSourceCode {
continue;
}
String generatedComment = "// %s ".formatted(Annotations.annotationStyle(GeneratedFrom.class));
String generatedComment = "// %s ".formatted(Annotations.annotationStyle(Types.GENERATED_FROM));
if (nextLineIterator.trySkipString(generatedComment) && nextLineIterator.canRead()) {
String generatedVersion = nextLineIterator.getRemaining();
if (!CURRENT_VERSION.equals(generatedVersion)) {

View File

@@ -3,6 +3,7 @@ package io.papermc.generator.types;
import com.mojang.logging.LogUtils;
import com.squareup.javapoet.MethodSpec;
import io.papermc.generator.utils.Annotations;
import io.papermc.typewriter.ClassNamed;
import java.util.Arrays;
import org.jspecify.annotations.NullMarked;
import org.slf4j.Logger;
@@ -10,38 +11,44 @@ import org.slf4j.Logger;
import static javax.lang.model.element.Modifier.PUBLIC;
@NullMarked
public abstract class OverriddenClassGenerator<T> extends SimpleGenerator {
public abstract class OverriddenClassGenerator extends SimpleGenerator {
private static final Logger LOGGER = LogUtils.getLogger();
protected final Class<? extends T> baseClass;
protected final ClassNamed baseClass;
protected boolean printWarningOnMissingOverride;
protected OverriddenClassGenerator(Class<T> baseClass, String className, String packageName) {
protected OverriddenClassGenerator(ClassNamed baseClass, String className, String packageName) {
super(className, packageName);
this.baseClass = baseClass;
}
public Class<? extends T> getBaseClass() {
public ClassNamed getBaseClass() {
return this.baseClass;
}
public MethodSpec.Builder createMethod(String name, Class<?>... parameterTypes) {
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(name)
.addModifiers(PUBLIC);
if (methodExists(name, parameterTypes)) {
if (this.baseClass.knownClass() == null || methodExists(name, parameterTypes)) {
methodBuilder.addAnnotation(Annotations.OVERRIDE);
} else {
if (this.printWarningOnMissingOverride) {
LOGGER.warn("Method {}#{}{} didn't override a known api method!", this.className, name, Arrays.toString(parameterTypes));
LOGGER.warn("Method {}#{}{} didn't override a known api method!", this.className, name, LogUtils.defer(() -> Arrays.toString(parameterTypes)));
}
}
return methodBuilder;
}
public MethodSpec.Builder createUnsafeMethod(String name) {
return MethodSpec.methodBuilder(name)
.addModifiers(PUBLIC)
.addAnnotation(Annotations.OVERRIDE);
}
protected boolean methodExists(String name, Class<?>... parameterTypes) {
try {
this.baseClass.getMethod(name, parameterTypes);
this.baseClass.knownClass().getMethod(name, parameterTypes);
return true;
} catch (NoSuchMethodException e) {
return false;

View File

@@ -6,11 +6,11 @@ import javax.lang.model.element.Modifier;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class SimpleEnumGenerator<T extends Enum<T>> extends SimpleGenerator {
public class SimpleEnumGenerator<E extends Enum<E>> extends SimpleGenerator {
private final Class<T> enumClass;
private final Class<E> enumClass;
public SimpleEnumGenerator(Class<T> enumClass, String packageName) {
public SimpleEnumGenerator(Class<E> enumClass, String packageName) {
super(enumClass.getSimpleName(), packageName);
this.enumClass = enumClass;
}
@@ -21,7 +21,7 @@ public class SimpleEnumGenerator<T extends Enum<T>> extends SimpleGenerator {
.addModifiers(Modifier.PUBLIC)
.addAnnotations(Annotations.CLASS_HEADER);
for (T enumValue : this.enumClass.getEnumConstants()) {
for (E enumValue : this.enumClass.getEnumConstants()) {
typeBuilder.addEnumConstant(enumValue.name());
}

View File

@@ -1,14 +1,64 @@
package io.papermc.generator.types;
import com.squareup.javapoet.ClassName;
import io.papermc.typewriter.ClassNamed;
import java.util.Arrays;
import org.jspecify.annotations.NullMarked;
import static io.papermc.generator.utils.BasePackage.BUKKIT;
import static io.papermc.generator.utils.BasePackage.CRAFT_BUKKIT;
import static io.papermc.generator.utils.BasePackage.PAPER;
import static io.papermc.generator.utils.BasePackage.PAPER_LEGACY;
@NullMarked
public final class Types {
public static final String BASE_PACKAGE = "org.bukkit.craftbukkit";
public static final ClassName NAMESPACED_KEY = BUKKIT.rootClass("NamespacedKey");
public static final ClassName CRAFT_BLOCK_DATA = ClassName.get(BASE_PACKAGE + ".block.data", "CraftBlockData");
public static final ClassName MINECRAFT_EXPERIMENTAL = BUKKIT.rootClass("MinecraftExperimental");
public static final ClassName CRAFT_BLOCK = ClassName.get(BASE_PACKAGE + ".block", "CraftBlock");
public static final ClassName MINECRAFT_EXPERIMENTAL_REQUIRES = BUKKIT.rootClass("MinecraftExperimental", "Requires");
public static final ClassName VECTOR = BUKKIT.relativeClass("util", "Vector");
public static final ClassName AXIS = BUKKIT.rootClass("Axis");
public static final ClassName BLOCK_FACE = BUKKIT.relativeClass("block", "BlockFace");
public static final ClassName NOTE = BUKKIT.rootClass("Note");
public static final ClassName BLOCK_DATA_RAIL_SHAPE = BUKKIT.relativeClass("block.data", "Rail", "Shape");
public static final ClassName KEY = ClassName.get("net.kyori.adventure.key", "Key");
public static final ClassName REGISTRY_KEY = PAPER.relativeClass("registry", "RegistryKey");
public static final ClassName TYPED_KEY = PAPER.relativeClass("registry", "TypedKey");
public static final ClassName GOAL_KEY = PAPER_LEGACY.relativeClass("entity.ai", "GoalKey");
public static final ClassName GOAL = PAPER_LEGACY.relativeClass("entity.ai", "Goal");
public static final ClassName MOB = BUKKIT.relativeClass("entity", "Mob");
public static final ClassName RANGED_ENTITY = PAPER_LEGACY.relativeClass("entity", "RangedEntity");
public static final ClassName CRAFT_BLOCK_DATA = CRAFT_BUKKIT.relativeClass("block.data", "CraftBlockData");
public static final ClassName CRAFT_BLOCK = CRAFT_BUKKIT.relativeClass("block", "CraftBlock");
public static final ClassName TAG_KEY = PAPER.relativeClass("registry.tag", "TagKey");
public static final ClassName GENERATED_FROM = PAPER.relativeClass("generated", "GeneratedFrom");
public static ClassName typed(ClassNamed name) {
if (name.knownClass() != null) {
return ClassName.get(name.knownClass());
}
String[] names = name.dottedNestedName().split("\\.", -1);
String topName = names[0];
return ClassName.get(name.packageName(), topName, Arrays.copyOfRange(names, 1, names.length));
}
}

View File

@@ -1,23 +1,18 @@
package io.papermc.generator.types.craftblockdata;
import com.google.common.base.Preconditions;
import io.papermc.generator.types.SourceGenerator;
import io.papermc.generator.utils.BlockStateMapping;
import java.util.List;
import java.util.Map;
import net.minecraft.world.level.block.Block;
import org.bukkit.block.data.BlockData;
import org.jspecify.annotations.NullMarked;
@NullMarked
public final class CraftBlockDataBootstrapper {
public static void bootstrap(List<SourceGenerator> generators) {
for (Map.Entry<Class<? extends Block>, BlockStateMapping.BlockData> entry : BlockStateMapping.MAPPING.entrySet()) {
Class<? extends BlockData> api = BlockStateMapping.getBestSuitedApiClass(entry.getValue());
Preconditions.checkState(api != null, "Unknown custom BlockData api class for " + entry.getKey().getCanonicalName());
generators.add(new CraftBlockDataGenerator<>(entry.getKey(), entry.getValue(), api));
for (Map.Entry<Class<? extends Block>, BlockStateMapping.BlockData> entry : BlockStateMapping.getOrCreate().entrySet()) {
generators.add(new CraftBlockDataGenerator(entry.getKey(), entry.getValue()));
}
}
}

View File

@@ -7,7 +7,10 @@ import com.mojang.datafixers.util.Either;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import io.papermc.generator.resources.DataFileLoader;
import io.papermc.generator.resources.DataFiles;
import io.papermc.generator.types.OverriddenClassGenerator;
import io.papermc.generator.types.Types;
import io.papermc.generator.types.craftblockdata.property.PropertyMaker;
@@ -19,12 +22,14 @@ import io.papermc.generator.types.craftblockdata.property.holder.VirtualField;
import io.papermc.generator.types.craftblockdata.property.holder.converter.DataConverter;
import io.papermc.generator.types.craftblockdata.property.holder.converter.DataConverters;
import io.papermc.generator.utils.Annotations;
import io.papermc.generator.utils.BasePackage;
import io.papermc.generator.utils.BlockStateMapping;
import io.papermc.generator.utils.CommonVariable;
import io.papermc.generator.utils.NamingManager;
import it.unimi.dsi.fastutil.Pair;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import net.minecraft.world.level.block.Block;
@@ -32,10 +37,6 @@ import net.minecraft.world.level.block.ChiseledBookShelfBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.Property;
import org.bukkit.Axis;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Rail;
import org.jspecify.annotations.NullMarked;
import static io.papermc.generator.utils.NamingManager.keywordGet;
@@ -46,18 +47,22 @@ import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
@NullMarked
public class CraftBlockDataGenerator<T extends BlockData> extends OverriddenClassGenerator<T> {
public class CraftBlockDataGenerator extends OverriddenClassGenerator {
private final Class<? extends Block> blockClass;
private final BlockStateMapping.BlockData blockData;
protected CraftBlockDataGenerator(Class<? extends Block> blockClass, BlockStateMapping.BlockData blockData, Class<T> baseClass) {
super(baseClass, blockData.implName(), Types.BASE_PACKAGE + ".block.impl");
protected CraftBlockDataGenerator(Class<? extends Block> blockClass, BlockStateMapping.BlockData blockData) {
super(blockData.api(), blockData.implName(), BasePackage.CRAFT_BUKKIT.name().concat(".block.impl"));
this.blockClass = blockClass;
this.blockData = blockData;
this.printWarningOnMissingOverride = true;
}
public Class<? extends Block> getBlock() {
return this.blockClass;
}
// default keywords: get/set
// for single boolean property: get = is
// for indexed boolean property: get = has
@@ -77,19 +82,19 @@ public class CraftBlockDataGenerator<T extends BlockData> extends OverriddenClas
method.addStatement("$1T.checkArgument($2N.isCartesian() && $2N.getModY() == 0, $3S)", Preconditions.class, param, "Invalid face, only cartesian horizontal face are allowed for this property!");
},
BlockStateProperties.FACING_HOPPER, (param, method) -> {
method.addStatement("$1T.checkArgument($2N.isCartesian() && $2N != $3T.UP, $4S)", Preconditions.class, param, BlockFace.class, "Invalid face, only cartesian face (excluding UP) are allowed for this property!");
method.addStatement("$1T.checkArgument($2N.isCartesian() && $2N != $3T.UP, $4S)", Preconditions.class, param, Types.BLOCK_FACE, "Invalid face, only cartesian face (excluding UP) are allowed for this property!");
},
BlockStateProperties.VERTICAL_DIRECTION, (param, method) -> {
method.addStatement("$T.checkArgument($N.getModY() != 0, $S)", Preconditions.class, param, "Invalid face, only vertical face are allowed for this property!");
},
BlockStateProperties.ROTATION_16, (param, method) -> {
method.addStatement("$1T.checkArgument($2N != $3T.SELF && $2N.getModY() == 0, $4S)", Preconditions.class, param, BlockFace.class, "Invalid face, only horizontal face are allowed for this property!");
method.addStatement("$1T.checkArgument($2N != $3T.SELF && $2N.getModY() == 0, $4S)", Preconditions.class, param, Types.BLOCK_FACE, "Invalid face, only horizontal face are allowed for this property!");
},
BlockStateProperties.HORIZONTAL_AXIS, (param, method) -> {
method.addStatement("$1T.checkArgument($2N == $3T.X || $2N == $3T.Z, $4S)", Preconditions.class, param, Axis.class, "Invalid axis, only horizontal axis are allowed for this property!");
method.addStatement("$1T.checkArgument($2N == $3T.X || $2N == $3T.Z, $4S)", Preconditions.class, param, Types.AXIS, "Invalid axis, only horizontal axis are allowed for this property!");
},
BlockStateProperties.RAIL_SHAPE_STRAIGHT, (param, method) -> {
method.addStatement("$1T.checkArgument($2N != $3T.NORTH_EAST && $2N != $3T.NORTH_WEST && $2N != $3T.SOUTH_EAST && $2N != $3T.SOUTH_WEST, $4S)", Preconditions.class, param, Rail.Shape.class, "Invalid rail shape, only straight rail are allowed for this property!");
method.addStatement("$1T.checkArgument($2N != $3T.NORTH_EAST && $2N != $3T.NORTH_WEST && $2N != $3T.SOUTH_EAST && $2N != $3T.SOUTH_WEST, $4S)", Preconditions.class, param, Types.BLOCK_DATA_RAIL_SHAPE, "Invalid rail shape, only straight rail are allowed for this property!");
}
);
@@ -98,7 +103,15 @@ public class CraftBlockDataGenerator<T extends BlockData> extends OverriddenClas
.addModifiers(PUBLIC)
.addAnnotation(Annotations.GENERATED_FROM)
.superclass(Types.CRAFT_BLOCK_DATA)
.addSuperinterface(this.baseClass);
.addSuperinterface(Types.typed(this.baseClass));
// since javapoet lack of context (doesn't know the api anymore), type clash with the super interface
Map<String, List<String>> ambiguousNames = DataFileLoader.get(DataFiles.BLOCK_STATE_AMBIGUOUS_NAMES);
for (Map.Entry<String, List<String>> entry : ambiguousNames.entrySet()) {
if (entry.getValue().contains(this.blockData.implName())) {
typeBuilder.alwaysQualify(entry.getKey());
}
}
ParameterSpec parameter = ParameterSpec.builder(BlockState.class, "state").build();
MethodSpec constructor = MethodSpec.constructorBuilder()
@@ -135,10 +148,10 @@ public class CraftBlockDataGenerator<T extends BlockData> extends OverriddenClas
typeBuilder.addField(field);
ConverterBase converter = Converters.getOrDefault(property, propertyMaker);
Class<?> apiClass = converter.getApiType();
TypeName apiType = converter.getApiType();
NamingManager.AccessKeyword accessKeyword = null;
if (apiClass == Boolean.TYPE) {
if (apiType.equals(TypeName.BOOLEAN)) {
accessKeyword = keywordGet("is");
}
accessKeyword = FLUENT_KEYWORD.getOrDefault(property, accessKeyword);
@@ -148,18 +161,18 @@ public class CraftBlockDataGenerator<T extends BlockData> extends OverriddenClas
{
MethodSpec.Builder methodBuilder = createMethod(propertyNaming.simpleGetterName(name -> !name.startsWith("is_") && !name.startsWith("has_")));
converter.convertGetter(methodBuilder, field);
methodBuilder.returns(apiClass);
methodBuilder.returns(apiType);
typeBuilder.addMethod(methodBuilder.build());
}
// set
{
String paramName = propertyNaming.paramName(apiClass);
ParameterSpec parameter = ParameterSpec.builder(apiClass, paramName, FINAL).build();
String paramName = propertyNaming.paramName(apiType);
ParameterSpec parameter = ParameterSpec.builder(apiType, paramName, FINAL).build();
MethodSpec.Builder methodBuilder = createMethod(propertyNaming.simpleSetterName(name -> !name.startsWith("is_")), apiClass).addParameter(parameter);
if (!apiClass.isPrimitive()) {
MethodSpec.Builder methodBuilder = createUnsafeMethod(propertyNaming.simpleSetterName(name -> !name.startsWith("is_"))).addParameter(parameter);
if (!apiType.isPrimitive()) {
methodBuilder.addStatement("$T.checkArgument($N != null, $S)", Preconditions.class, parameter, "%s cannot be null!".formatted(paramName));
}
if (SETTER_PRECONDITIONS.containsKey(property)) {
@@ -188,20 +201,20 @@ public class CraftBlockDataGenerator<T extends BlockData> extends OverriddenClas
typeBuilder.addField(field);
DataConverter converter = DataConverters.getOrThrow(dataPropertyMaker.getType());
Class<?> apiClass = propertyConverter.getApiType();
TypeName apiClass = propertyConverter.getApiType();
NamingManager.AccessKeyword accessKeyword = null;
if (apiClass == Boolean.TYPE) {
if (apiClass.equals(TypeName.BOOLEAN)) {
accessKeyword = NamingManager.keywordGet("has");
}
accessKeyword = FLUENT_KEYWORD.getOrDefault(firstProperty, accessKeyword);
NamingManager baseNaming = new NamingManager(accessKeyword, CaseFormat.UPPER_UNDERSCORE, dataPropertyMaker.getBaseName());
ParameterSpec indexParameter = ParameterSpec.builder(dataPropertyMaker.getIndexClass(), dataPropertyMaker.getIndexClass() == Integer.TYPE ? CommonVariable.INDEX : baseNaming.paramName(dataPropertyMaker.getIndexClass()), FINAL).build();
ParameterSpec indexParameter = ParameterSpec.builder(dataPropertyMaker.getIndexClass(), dataPropertyMaker.getIndexClass().equals(TypeName.INT) ? CommonVariable.INDEX : baseNaming.paramName(dataPropertyMaker.getIndexClass()), FINAL).build();
// get
{
MethodSpec.Builder methodBuilder = createMethod(baseNaming.simpleGetterName(name -> true), dataPropertyMaker.getIndexClass())
MethodSpec.Builder methodBuilder = createUnsafeMethod(baseNaming.simpleGetterName(name -> true))
.addParameter(indexParameter);
if (!dataPropertyMaker.getIndexClass().isPrimitive()) {
methodBuilder.addStatement("$T.checkArgument($N != null, $S)", Preconditions.class, indexParameter, "%s cannot be null!".formatted(indexParameter.name));
@@ -217,7 +230,7 @@ public class CraftBlockDataGenerator<T extends BlockData> extends OverriddenClas
String paramName = baseNaming.paramName(apiClass);
ParameterSpec parameter = ParameterSpec.builder(apiClass, paramName, FINAL).build();
MethodSpec.Builder methodBuilder = createMethod(baseNaming.simpleSetterName(name -> true), dataPropertyMaker.getIndexClass(), apiClass)
MethodSpec.Builder methodBuilder = createUnsafeMethod(baseNaming.simpleSetterName(name -> true))
.addParameter(indexParameter)
.addParameter(parameter);
if (!dataPropertyMaker.getIndexClass().isPrimitive()) {

View File

@@ -4,7 +4,8 @@ import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import io.papermc.generator.utils.BlockStateMapping;
import io.papermc.generator.resources.DataFileLoader;
import io.papermc.generator.resources.DataFiles;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import org.jspecify.annotations.NullMarked;
@@ -25,13 +26,9 @@ public class EnumPropertyWriter<T extends Enum<T> & StringRepresentable> extends
}
@Override
protected Class<?> processApiType() {
Class<?> apiClass = this.property.getValueClass();
apiClass = BlockStateMapping.ENUM_BRIDGE.get(apiClass);
if (apiClass == null) {
throw new IllegalStateException("Unknown enum type for " + this.property);
}
return apiClass;
protected TypeName processApiType() {
Class<?> rawClass = this.property.getValueClass();
return DataFileLoader.get(DataFiles.BLOCK_STATE_ENUM_PROPERTY_TYPES).get(rawClass);
}
@Override

View File

@@ -18,14 +18,14 @@ public class IntegerPropertyWriter extends PropertyWriter<Integer> {
}
@Override
public void addExtras(TypeSpec.Builder builder, FieldSpec field, CraftBlockDataGenerator<?> generator, NamingManager naming) {
public void addExtras(TypeSpec.Builder builder, FieldSpec field, CraftBlockDataGenerator generator, NamingManager naming) {
if (Converters.has(this.property)) {
return;
}
IntegerProperty property = (IntegerProperty) this.property;
if (property.min != 0 || property.getName().equals(BlockStateProperties.LEVEL.getName())) { // special case (levelled: composter)
if (property.getPossibleValues().getFirst() != 0 || property.getName().equals(BlockStateProperties.LEVEL.getName())) { // special case (levelled: composter)
MethodSpec.Builder methodBuilder = generator.createMethod(naming.getterName(name -> true).pre("Minimum").concat());
methodBuilder.addStatement("return $N.min", field);
methodBuilder.returns(this.getApiType());

View File

@@ -23,7 +23,7 @@ import org.jspecify.annotations.NullMarked;
public class PropertyWriter<T extends Comparable<T>> implements PropertyMaker {
protected final Property<T> property;
private final Supplier<Class<?>> apiClassSupplier;
private final Supplier<TypeName> apiClassSupplier;
protected PropertyWriter(Property<T> property) {
this.property = property;
@@ -35,16 +35,16 @@ public class PropertyWriter<T extends Comparable<T>> implements PropertyMaker {
return TypeName.get(this.property.getClass());
}
protected Class<?> processApiType() {
protected TypeName processApiType() {
Class<T> apiClass = this.property.getValueClass();
if (Primitives.isWrapperType(apiClass)) {
apiClass = Primitives.unwrap(apiClass);
}
return apiClass;
return TypeName.get(apiClass);
}
@Override
public Class<?> getApiType() {
public TypeName getApiType() {
return this.apiClassSupplier.get();
}
@@ -59,24 +59,27 @@ public class PropertyWriter<T extends Comparable<T>> implements PropertyMaker {
}
@Override
public void addExtras(TypeSpec.Builder builder, FieldSpec field, CraftBlockDataGenerator<?> generator, NamingManager naming) {
public void addExtras(TypeSpec.Builder builder, FieldSpec field, CraftBlockDataGenerator generator, NamingManager naming) {
PropertyAppenders.ifPresent(this.property, appender -> appender.addExtras(builder, field, generator, naming));
}
public static Pair<Class<?>, String> referenceField(Class<? extends Block> from, Property<?> property, Map<Property<?>, Field> fields) {
Class<?> fieldAccess = from;
Field field = fields.get(property);
String fieldName;
if (field == null || !Modifier.isPublic(field.getModifiers())) {
fieldAccess = BlockStateProperties.class;
field = BlockStateMapping.FALLBACK_GENERIC_FIELDS.get(property);
fieldName = BlockStateMapping.GENERIC_FIELD_NAMES.get(property);
} else {
fieldName = field.getName();
}
return Pair.of(fieldAccess, field.getName());
return Pair.of(fieldAccess, fieldName);
}
public static Pair<Class<?>, String> referenceFieldFromVar(Class<? extends Block> from, Property<?> property, Map<Property<?>, Field> fields) {
Class<?> fieldAccess = from;
Field field = fields.get(property);
Field genericField = BlockStateMapping.FALLBACK_GENERIC_FIELDS.get(property);
Field genericField = BlockStateMapping.GENERIC_FIELDS.get(property);
if (field == null || !Modifier.isPublic(field.getModifiers()) || !genericField.getType().equals(field.getType())) {
// field type can differ from BlockStateProperties constants (that's the case for the shulker box (#FACING) and the vault (#STATE)) ref: 1.20.5
// in that case fallback to the more accurate type to avoid compile error

View File

@@ -9,5 +9,5 @@ import org.jspecify.annotations.NullMarked;
@NullMarked
public interface AppenderBase {
void addExtras(TypeSpec.Builder builder, FieldSpec field, CraftBlockDataGenerator<?> generator, NamingManager naming);
void addExtras(TypeSpec.Builder builder, FieldSpec field, CraftBlockDataGenerator generator, NamingManager naming);
}

View File

@@ -1,8 +1,10 @@
package io.papermc.generator.types.craftblockdata.property.appender;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator;
import io.papermc.generator.utils.NamingManager;
@@ -12,13 +14,13 @@ import net.minecraft.world.level.block.state.properties.EnumProperty;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class EnumValuesAppender<T extends Enum<T> & StringRepresentable, A extends Enum<A>> implements PropertyAppender<T, A> {
public class EnumValuesAppender<T extends Enum<T> & StringRepresentable> implements PropertyAppender<T> {
private final EnumProperty<T> property;
private final Class<A> apiType;
private final TypeName apiType;
private final String methodName;
public EnumValuesAppender(EnumProperty<T> property, Class<A> apiType, String methodName) {
public EnumValuesAppender(EnumProperty<T> property, TypeName apiType, String methodName) {
this.property = property;
this.apiType = apiType;
this.methodName = methodName;
@@ -30,15 +32,15 @@ public class EnumValuesAppender<T extends Enum<T> & StringRepresentable, A exten
}
@Override
public Class<A> getApiType() {
public TypeName getApiType() {
return this.apiType;
}
@Override
public void addExtras(TypeSpec.Builder builder, FieldSpec field, CraftBlockDataGenerator<?> generator, NamingManager naming) {
public void addExtras(TypeSpec.Builder builder, FieldSpec field, CraftBlockDataGenerator generator, NamingManager naming) {
MethodSpec.Builder methodBuilder = generator.createMethod(this.methodName);
methodBuilder.addStatement("return this.getValues($N, $T.class)", field, this.apiType);
methodBuilder.returns(ParameterizedTypeName.get(Set.class, this.apiType));
methodBuilder.returns(ParameterizedTypeName.get(ClassName.get(Set.class), this.apiType));
builder.addMethod(methodBuilder.build());
}

View File

@@ -1,12 +1,13 @@
package io.papermc.generator.types.craftblockdata.property.appender;
import com.squareup.javapoet.TypeName;
import net.minecraft.world.level.block.state.properties.Property;
import org.jspecify.annotations.NullMarked;
@NullMarked
public interface PropertyAppender<T extends Comparable<T>, A> extends AppenderBase {
public interface PropertyAppender<T extends Comparable<T>> extends AppenderBase {
Property<T> getProperty();
Class<A> getApiType();
TypeName getApiType();
}

View File

@@ -1,28 +1,26 @@
package io.papermc.generator.types.craftblockdata.property.appender;
import io.papermc.generator.types.Types;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.Property;
import org.bukkit.Axis;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Rail;
import org.jspecify.annotations.NullMarked;
@NullMarked
public final class PropertyAppenders {
private static final Map<Property<?>, AppenderBase> APPENDERS = Stream.of(
new EnumValuesAppender<>(BlockStateProperties.AXIS, Axis.class, "getAxes"),
new EnumValuesAppender<>(BlockStateProperties.HORIZONTAL_AXIS, Axis.class, "getAxes"),
new EnumValuesAppender<>(BlockStateProperties.FACING, BlockFace.class, "getFaces"),
new EnumValuesAppender<>(BlockStateProperties.HORIZONTAL_FACING, BlockFace.class, "getFaces"),
new EnumValuesAppender<>(BlockStateProperties.FACING_HOPPER, BlockFace.class, "getFaces"),
new EnumValuesAppender<>(BlockStateProperties.RAIL_SHAPE, Rail.Shape.class, "getShapes"),
new EnumValuesAppender<>(BlockStateProperties.RAIL_SHAPE_STRAIGHT, Rail.Shape.class, "getShapes"),
new EnumValuesAppender<>(BlockStateProperties.VERTICAL_DIRECTION, BlockFace.class, "getVerticalDirections")
new EnumValuesAppender<>(BlockStateProperties.AXIS, Types.AXIS, "getAxes"),
new EnumValuesAppender<>(BlockStateProperties.HORIZONTAL_AXIS, Types.AXIS, "getAxes"),
new EnumValuesAppender<>(BlockStateProperties.FACING, Types.BLOCK_FACE, "getFaces"),
new EnumValuesAppender<>(BlockStateProperties.HORIZONTAL_FACING, Types.BLOCK_FACE, "getFaces"),
new EnumValuesAppender<>(BlockStateProperties.FACING_HOPPER, Types.BLOCK_FACE, "getFaces"),
new EnumValuesAppender<>(BlockStateProperties.RAIL_SHAPE, Types.BLOCK_DATA_RAIL_SHAPE, "getShapes"),
new EnumValuesAppender<>(BlockStateProperties.RAIL_SHAPE_STRAIGHT, Types.BLOCK_DATA_RAIL_SHAPE, "getShapes"),
new EnumValuesAppender<>(BlockStateProperties.VERTICAL_DIRECTION, Types.BLOCK_FACE, "getVerticalDirections")
).collect(Collectors.toUnmodifiableMap(PropertyAppender::getProperty, key -> key));
public static void ifPresent(Property<?> property, Consumer<AppenderBase> callback) {

View File

@@ -1,13 +1,14 @@
package io.papermc.generator.types.craftblockdata.property.converter;
import com.squareup.javapoet.TypeName;
import net.minecraft.world.level.block.state.properties.Property;
import org.jspecify.annotations.NullMarked;
@NullMarked
public interface Converter<T extends Comparable<T>, A> extends ConverterBase {
public interface Converter<T extends Comparable<T>> extends ConverterBase {
Property<T> getProperty();
@Override
Class<A> getApiType();
TypeName getApiType();
}

View File

@@ -3,12 +3,13 @@ package io.papermc.generator.types.craftblockdata.property.converter;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import org.jspecify.annotations.NullMarked;
@NullMarked
public interface ConverterBase {
Class<?> getApiType();
TypeName getApiType();
default void convertSetter(MethodSpec.Builder method, FieldSpec field, ParameterSpec parameter) {
method.addStatement(this.rawSetExprent().formatted("$N"), field, parameter);

View File

@@ -2,13 +2,14 @@ package io.papermc.generator.types.craftblockdata.property.converter;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import io.papermc.generator.types.Types;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.Property;
import org.bukkit.Note;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class NoteConverter implements Converter<Integer, Note> {
public class NoteConverter implements Converter<Integer> {
@Override
public Property<Integer> getProperty() {
@@ -16,8 +17,8 @@ public class NoteConverter implements Converter<Integer, Note> {
}
@Override
public Class<Note> getApiType() {
return Note.class;
public TypeName getApiType() {
return Types.NOTE;
}
@Override

View File

@@ -3,15 +3,15 @@ package io.papermc.generator.types.craftblockdata.property.converter;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import io.papermc.generator.types.Types;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.block.state.properties.RotationSegment;
import org.bukkit.block.BlockFace;
import org.bukkit.util.Vector;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class RotationConverter implements Converter<Integer, BlockFace> {
public class RotationConverter implements Converter<Integer> {
private static final String DIRECTION_VAR = "dir";
private static final String ANGLE_VAR = "angle";
@@ -22,13 +22,13 @@ public class RotationConverter implements Converter<Integer, BlockFace> {
}
@Override
public Class<BlockFace> getApiType() {
return BlockFace.class;
public TypeName getApiType() {
return Types.BLOCK_FACE;
}
@Override
public void convertSetter(MethodSpec.Builder method, FieldSpec field, ParameterSpec parameter) {
method.addStatement("$T $L = $N.getDirection()", Vector.class, DIRECTION_VAR, parameter);
method.addStatement("$T $L = $N.getDirection()", Types.VECTOR, DIRECTION_VAR, parameter);
method.addStatement("$1T $2L = ($1T) -$3T.toDegrees($3T.atan2($4L.getX(), $4L.getZ()))", Float.TYPE, ANGLE_VAR, Math.class, DIRECTION_VAR);
method.addStatement(this.rawSetExprent().formatted("$N", ANGLE_VAR), field, RotationSegment.class);
}

View File

@@ -2,6 +2,7 @@ package io.papermc.generator.types.craftblockdata.property.holder;
import com.mojang.datafixers.util.Either;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.TypeName;
import io.papermc.generator.types.craftblockdata.property.holder.appender.DataAppender;
import java.lang.reflect.Field;
import java.util.Collection;
@@ -15,7 +16,7 @@ public interface DataPropertyMaker extends DataAppender {
FieldSpec.Builder getOrCreateField(Map<Property<?>, Field> fields);
Class<?> getIndexClass();
TypeName getIndexClass();
@Override
DataHolderType getType();

View File

@@ -7,11 +7,12 @@ import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import io.papermc.generator.resources.DataFileLoader;
import io.papermc.generator.resources.DataFiles;
import io.papermc.generator.types.Types;
import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator;
import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase;
import io.papermc.generator.types.craftblockdata.property.holder.appender.DataAppenders;
import io.papermc.generator.utils.BlockStateMapping;
import io.papermc.generator.utils.ClassHelper;
import io.papermc.generator.utils.CommonVariable;
import io.papermc.generator.utils.NamingManager;
@@ -28,7 +29,6 @@ import net.minecraft.world.level.block.ChiseledBookShelfBlock;
import net.minecraft.world.level.block.MossyCarpetBlock;
import net.minecraft.world.level.block.WallBlock;
import net.minecraft.world.level.block.state.properties.Property;
import org.bukkit.block.BlockFace;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.jspecify.annotations.NullMarked;
@@ -58,7 +58,8 @@ public class DataPropertyWriter extends DataPropertyWriterBase {
protected final Field field;
protected @MonotonicNonNull DataHolderType type;
protected @MonotonicNonNull Class<?> indexClass, internalIndexClass;
protected @MonotonicNonNull TypeName indexClass;
protected @MonotonicNonNull Class<?> internalIndexClass;
protected @MonotonicNonNull TypeName fieldType;
protected DataPropertyWriter(Field field, Collection<? extends Property<?>> properties, Class<? extends Block> blockClass) {
@@ -72,22 +73,26 @@ public class DataPropertyWriter extends DataPropertyWriterBase {
if (field.getType().isArray()) {
this.type = DataHolderType.ARRAY;
this.indexClass = Integer.TYPE;
this.indexClass = TypeName.INT;
} else if (List.class.isAssignableFrom(field.getType())) {
this.type = DataHolderType.LIST;
this.indexClass = Integer.TYPE;
this.indexClass = TypeName.INT;
} else if (Map.class.isAssignableFrom(field.getType()) && field.getGenericType() instanceof ParameterizedType complexType) {
this.type = DataHolderType.MAP;
this.internalIndexClass = ClassHelper.eraseType(complexType.getActualTypeArguments()[0]);
if (this.internalIndexClass.isEnum()) {
this.indexClass = BlockStateMapping.ENUM_BRIDGE.getOrDefault(this.internalIndexClass, (Class<? extends Enum<?>>) this.internalIndexClass);
TypeName indexClass = DataFileLoader.get(DataFiles.BLOCK_STATE_ENUM_PROPERTY_TYPES).get(this.internalIndexClass);
if (indexClass == null) {
indexClass = TypeName.get(this.internalIndexClass);
}
this.indexClass = indexClass;
this.fieldType = ParameterizedTypeName.get(
ClassName.get(field.getType()),
ClassName.get(this.indexClass),
ClassName.get(complexType.getActualTypeArguments()[1])
this.indexClass,
TypeName.get(complexType.getActualTypeArguments()[1])
);
} else {
this.indexClass = this.internalIndexClass;
this.indexClass = TypeName.get(this.internalIndexClass);
}
} else {
throw new IllegalStateException("Don't know how to turn " + field + " into api");
@@ -100,7 +105,7 @@ public class DataPropertyWriter extends DataPropertyWriterBase {
if (Modifier.isPublic(this.field.getModifiers())) {
// accessible phew
if (this.type == DataHolderType.MAP &&
this.internalIndexClass == Direction.class && this.indexClass == BlockFace.class) { // Direction -> BlockFace
this.internalIndexClass == Direction.class && this.indexClass.equals(Types.BLOCK_FACE)) { // Direction -> BlockFace
// convert the key manually only this one is needed for now
fieldBuilder.initializer("$[$1T.$2L.entrySet().stream()\n.collect($3T.toMap($4L -> $5T.notchToBlockFace($4L.getKey()), $4L -> $4L.getValue()))$]",
this.blockClass, this.field.getName(), Collectors.class, CommonVariable.MAP_ENTRY, Types.CRAFT_BLOCK);
@@ -122,7 +127,7 @@ public class DataPropertyWriter extends DataPropertyWriterBase {
}
@Override
public Class<?> getIndexClass() {
public TypeName getIndexClass() {
return this.indexClass;
}
@@ -158,7 +163,7 @@ public class DataPropertyWriter extends DataPropertyWriterBase {
}
@Override
public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase childConverter, CraftBlockDataGenerator<?> generator, NamingManager baseNaming) {
public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase childConverter, CraftBlockDataGenerator generator, NamingManager baseNaming) {
DataAppenders.ifPresent(this.type, appender -> appender.addExtras(builder, field, indexParameter, childConverter, generator, baseNaming));
}
}

View File

@@ -1,6 +1,7 @@
package io.papermc.generator.types.craftblockdata.property.holder;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.TypeName;
import io.papermc.generator.types.craftblockdata.property.PropertyWriter;
import io.papermc.generator.utils.Formatting;
import it.unimi.dsi.fastutil.Pair;
@@ -46,7 +47,7 @@ public abstract class DataPropertyWriterBase implements DataPropertyMaker {
code.unindent().add(isArray ? "}" : ")");
}
protected void createSyntheticMap(CodeBlock.Builder code, Class<?> indexClass, Map<Property<?>, Field> fields) {
protected void createSyntheticMap(CodeBlock.Builder code, TypeName indexClass, Map<Property<?>, Field> fields) {
// assume indexClass is an enum with its values matching the property names
code.add("$T.of(\n", Map.class).indent();
Iterator<? extends Property<?>> properties = this.properties.iterator();
@@ -64,5 +65,5 @@ public abstract class DataPropertyWriterBase implements DataPropertyMaker {
}
@Override
public abstract Class<?> getIndexClass();
public abstract TypeName getIndexClass();
}

View File

@@ -1,15 +1,17 @@
package io.papermc.generator.types.craftblockdata.property.holder;
import com.squareup.javapoet.ArrayTypeName;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import io.papermc.generator.resources.DataFileLoader;
import io.papermc.generator.resources.DataFiles;
import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator;
import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase;
import io.papermc.generator.utils.BlockStateMapping;
import io.papermc.generator.utils.NamingManager;
import java.lang.reflect.Field;
import java.util.Collection;
@@ -28,7 +30,7 @@ import static javax.lang.model.element.Modifier.STATIC;
public class VirtualDataPropertyWriter extends DataPropertyWriterBase {
private final VirtualField virtualField;
protected @MonotonicNonNull Class<?> indexClass;
protected @MonotonicNonNull TypeName indexClass;
protected @MonotonicNonNull TypeName fieldType;
protected VirtualDataPropertyWriter(VirtualField virtualField, Collection<? extends Property<?>> properties, Class<? extends Block> blockClass) {
@@ -40,23 +42,25 @@ public class VirtualDataPropertyWriter extends DataPropertyWriterBase {
protected void computeTypes(VirtualField virtualField) {
switch (virtualField.holderType()) {
case ARRAY -> {
this.indexClass = Integer.TYPE;
this.indexClass = TypeName.INT;
this.fieldType = ArrayTypeName.of(virtualField.valueType());
}
case LIST -> {
this.indexClass = Integer.TYPE;
this.indexClass = TypeName.INT;
this.fieldType = ParameterizedTypeName.get(List.class, virtualField.valueType());
}
case MAP -> {
if (virtualField.keyClass() != null) {
this.indexClass = virtualField.keyClass();
this.indexClass = TypeName.get(virtualField.keyClass());
} else {
this.indexClass = this.properties.iterator().next().getValueClass();
if (this.indexClass.isEnum()) {
this.indexClass = BlockStateMapping.ENUM_BRIDGE.getOrDefault(this.indexClass, (Class<? extends Enum<?>>) this.indexClass);
Class<?> valueClass = this.properties.iterator().next().getValueClass();
if (valueClass.isEnum()) {
this.indexClass = DataFileLoader.get(DataFiles.BLOCK_STATE_ENUM_PROPERTY_TYPES).get(valueClass);
} else {
this.indexClass = TypeName.get(valueClass);
}
}
this.fieldType = ParameterizedTypeName.get(Map.class, this.indexClass, virtualField.valueType());
this.fieldType = ParameterizedTypeName.get(ClassName.get(Map.class), this.indexClass, TypeName.get(virtualField.valueType()));
}
}
}
@@ -78,7 +82,7 @@ public class VirtualDataPropertyWriter extends DataPropertyWriterBase {
}
@Override
public Class<?> getIndexClass() {
public TypeName getIndexClass() {
return this.indexClass;
}
@@ -93,7 +97,7 @@ public class VirtualDataPropertyWriter extends DataPropertyWriterBase {
}
@Override
public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase converter, CraftBlockDataGenerator<?> generator, NamingManager baseNaming) {
public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase converter, CraftBlockDataGenerator generator, NamingManager baseNaming) {
}
}

View File

@@ -48,9 +48,9 @@ public record VirtualField(
private final String baseName;
private final @Nullable Class<?> keyClass;
private @Nullable Collection<T> values;
private @Nullable Collection<T> properties;
public FieldValue(String name, TypeToken<T> valueTypeToken, DataHolderType holderType, String baseName, @Nullable Class<?> keyClass) {
private FieldValue(String name, TypeToken<T> valueTypeToken, DataHolderType holderType, String baseName, @Nullable Class<?> keyClass) {
this.name = name;
this.valueTypeToken = valueTypeToken;
this.holderType = holderType;
@@ -59,14 +59,15 @@ public record VirtualField(
}
@Contract(value = "_ -> this", mutates = "this")
public FieldValue<T> withValues(Collection<T> properties) {
this.values = List.copyOf(properties);
public FieldValue<T> group(Collection<T> properties) {
this.properties = List.copyOf(properties);
return this;
}
@Contract(value = "-> new", pure = true)
public VirtualField make() {
Preconditions.checkState(this.values != null && !this.values.isEmpty(), "The field should doesn't have any content");
return new VirtualField(this.name, this.valueTypeToken.getType(), this.holderType, this.baseName, this.keyClass, this.values);
Preconditions.checkState(this.properties != null && !this.properties.isEmpty(), "The field doesn't have any content");
return new VirtualField(this.name, this.valueTypeToken.getType(), this.holderType, this.baseName, this.keyClass, this.properties);
}
}
}

View File

@@ -5,6 +5,7 @@ import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator;
import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase;
@@ -23,8 +24,8 @@ public class ArrayAppender implements DataAppender {
}
@Override
public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase childConverter, CraftBlockDataGenerator<?> generator, NamingManager baseNaming) {
if (childConverter.getApiType() == Boolean.TYPE) {
public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase childConverter, CraftBlockDataGenerator generator, NamingManager baseNaming) {
if (childConverter.getApiType().equals(TypeName.BOOLEAN)) {
String collectVarName = baseNaming.getVariableNameWrapper().post("s").concat();
MethodSpec.Builder methodBuilder = generator.createMethod(baseNaming.getMethodNameWrapper().post("s").concat());
methodBuilder.addStatement("$T $L = $T.builder()", ParameterizedTypeName.get(ImmutableSet.Builder.class, Integer.class), collectVarName, ImmutableSet.class);

View File

@@ -14,5 +14,5 @@ public interface DataAppender {
DataHolderType getType();
void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase converter, CraftBlockDataGenerator<?> generator, NamingManager baseNaming);
void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase converter, CraftBlockDataGenerator generator, NamingManager baseNaming);
}

View File

@@ -5,6 +5,7 @@ import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator;
import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase;
@@ -28,16 +29,16 @@ public class ListAppender implements DataAppender {
}
@Override
public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase childConverter, CraftBlockDataGenerator<?> generator, NamingManager baseNaming) {
public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase childConverter, CraftBlockDataGenerator generator, NamingManager baseNaming) {
NamingManager.NameWrapper methodName = NamingManager.NameWrapper.wrap("get", METHOD_BASE_RENAMES.getOrDefault(baseNaming.getMethodBaseName(), baseNaming.getMethodBaseName()));
if (childConverter.getApiType() == Boolean.TYPE) {
if (childConverter.getApiType().equals(TypeName.BOOLEAN)) {
String collectVarName = baseNaming.getVariableNameWrapper().post("s").concat();
MethodSpec.Builder methodBuilder = generator.createMethod(methodName.post("s").concat());
methodBuilder.addStatement("$T $L = $T.builder()", ParameterizedTypeName.get(ImmutableSet.Builder.class, Integer.class), collectVarName, ImmutableSet.class);
methodBuilder.beginControlFlow("for (int $1L = 0, size = $2N.size(); $1L < size; $1L++)", CommonVariable.INDEX, field);
{
methodBuilder.beginControlFlow("if (" + childConverter.rawGetExprent().formatted("$N.get($N)") + ")", field, indexParameter);
methodBuilder.beginControlFlow("if (" + childConverter.rawGetExprent().formatted("$N.get($N)") + ")", field, CommonVariable.INDEX);
{
methodBuilder.addStatement("$L.add($L)", collectVarName, CommonVariable.INDEX);
}

View File

@@ -1,62 +1,49 @@
package io.papermc.generator.types.craftblockdata.property.holder.appender;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import io.papermc.generator.resources.DataFileLoader;
import io.papermc.generator.resources.DataFiles;
import io.papermc.generator.resources.predicate.BlockPredicate;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator;
import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase;
import io.papermc.generator.types.craftblockdata.property.holder.DataHolderType;
import io.papermc.generator.utils.BlockStateMapping;
import io.papermc.generator.utils.CommonVariable;
import io.papermc.generator.utils.NamingManager;
import io.papermc.typewriter.ClassNamed;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.MultipleFacing;
import org.bukkit.block.data.type.RedstoneWire;
import net.minecraft.world.level.block.state.properties.Property;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class MapAppender implements DataAppender {
private static final Map<String, String> INDEX_NAMES = ImmutableMap.<String, String>builder()
.put(BlockFace.class.getSimpleName(), "Face")
.buildOrThrow();
// no real rule here some has some don't mossy carpet and wall could have it
private static final Set<Class<? extends BlockData>> HAS_ALLOWED_METHOD = Set.of(
MultipleFacing.class,
RedstoneWire.class
);
private static boolean supportsExtraMethod(Class<? extends BlockData> clazz) {
for (Class<? extends BlockData> supported : HAS_ALLOWED_METHOD) {
if (supported.isAssignableFrom(clazz)) {
return true;
}
}
return false;
}
@Override
public DataHolderType getType() {
return DataHolderType.MAP;
}
@Override
public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase childConverter, CraftBlockDataGenerator<?> generator, NamingManager baseNaming) {
if (childConverter.getApiType() == Boolean.TYPE) {
public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase childConverter, CraftBlockDataGenerator generator, NamingManager baseNaming) {
if (childConverter.getApiType().equals(TypeName.BOOLEAN)) {
String collectVarName = baseNaming.getVariableNameWrapper().post("s").concat();
MethodSpec.Builder methodBuilder = generator.createMethod(baseNaming.getMethodNameWrapper().post("s").concat());
methodBuilder.addStatement("$T $L = $T.builder()", ParameterizedTypeName.get(ClassName.get(ImmutableSet.Builder.class), indexParameter.type), collectVarName, ImmutableSet.class);
methodBuilder.beginControlFlow("for ($T $N : $N.entrySet())", ParameterizedTypeName.get(ClassName.get(Map.Entry.class), indexParameter.type, ClassName.get(BooleanProperty.class)), CommonVariable.MAP_ENTRY, field);
methodBuilder.beginControlFlow("for ($T $N : $N.entrySet())", ParameterizedTypeName.get(ClassName.get(Map.Entry.class), indexParameter.type, TypeName.get(BooleanProperty.class)), CommonVariable.MAP_ENTRY, field);
{
methodBuilder.beginControlFlow("if (" + childConverter.rawGetExprent().formatted("$L.getValue()") + ")", CommonVariable.MAP_ENTRY);
{
@@ -71,15 +58,33 @@ public class MapAppender implements DataAppender {
builder.addMethod(methodBuilder.build());
}
if (supportsExtraMethod(generator.getBaseClass()) &&
indexParameter.type instanceof ClassName className && !className.isPrimitive() && !className.isBoxedPrimitive()) {
NamingManager.NameWrapper indexNaming = NamingManager.NameWrapper.wrap("get", INDEX_NAMES.getOrDefault(className.simpleName(), className.simpleName()));
if (indexParameter.type instanceof ClassName className) {
if (generator.getBaseClass().equals(Types.BLOCK_DATA_MULTIPLE_FACING) ||
generator.getBaseClass().equals(Types.BLOCK_DATA_REDSTONE_WIRE) ||
isImplementing(generator.getBlock(), Types.BLOCK_DATA_MULTIPLE_FACING)) {
MethodSpec.Builder methodBuilder = generator.createMethod(indexNaming.pre("Allowed").post("s").concat());
methodBuilder.addStatement("return $T.unmodifiableSet($N.keySet())", Collections.class, field);
methodBuilder.returns(ParameterizedTypeName.get(ClassName.get(Set.class), className));
MethodSpec.Builder methodBuilder = generator.createMethod(baseNaming.getMethodNameWrapper().pre("Allowed").post("s").concat());
methodBuilder.addStatement("return $T.unmodifiableSet($N.keySet())", Collections.class, field);
methodBuilder.returns(ParameterizedTypeName.get(ClassName.get(Set.class), className));
builder.addMethod(methodBuilder.build());
builder.addMethod(methodBuilder.build());
}
}
}
public boolean isImplementing(Class<? extends Block> block, ClassNamed type) {
Set<Property<?>> propertySet = new HashSet<>(BlockStateMapping.STATEFUL_BLOCKS.get(block));
for (Map.Entry<ClassNamed, List<BlockPredicate>> predicateEntry : DataFileLoader.get(DataFiles.BLOCK_STATE_PREDICATES).entrySet()) {
for (BlockPredicate predicate : predicateEntry.getValue()) {
if (!predicate.matches(block, propertySet)) {
continue;
}
if (predicateEntry.getKey().equals(type)) {
return true;
}
}
}
return false;
}
}

View File

@@ -0,0 +1,7 @@
package io.papermc.generator.types.goal;
import com.squareup.javapoet.ClassName;
import net.minecraft.resources.ResourceLocation;
record GoalKey(ClassName type, ResourceLocation key) {
}

View File

@@ -1,6 +1,5 @@
package io.papermc.generator.types.goal;
import com.destroystokyo.paper.entity.ai.GoalKey;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
@@ -12,6 +11,7 @@ import com.squareup.javapoet.TypeVariableName;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ScanResult;
import io.papermc.generator.types.SimpleGenerator;
import io.papermc.generator.types.Types;
import io.papermc.generator.utils.Annotations;
import io.papermc.generator.utils.Formatting;
import io.papermc.generator.utils.Javadocs;
@@ -22,8 +22,6 @@ import java.util.stream.Stream;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.ai.goal.GoalSelector;
import net.minecraft.world.entity.ai.goal.WrappedGoal;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Mob;
import org.jspecify.annotations.NullMarked;
import static javax.lang.model.element.Modifier.FINAL;
@@ -42,9 +40,9 @@ public class MobGoalGenerator extends SimpleGenerator {
@Override
protected TypeSpec getTypeSpec() {
TypeVariableName type = TypeVariableName.get("T", Mob.class);
TypeVariableName type = TypeVariableName.get("T", Types.MOB);
TypeSpec.Builder typeBuilder = TypeSpec.interfaceBuilder(this.className)
.addSuperinterface(ParameterizedTypeName.get(ClassName.get(com.destroystokyo.paper.entity.ai.Goal.class), type))
.addSuperinterface(ParameterizedTypeName.get(Types.GOAL, type))
.addModifiers(PUBLIC)
.addTypeVariable(type)
.addAnnotations(Annotations.CLASS_HEADER)
@@ -58,31 +56,31 @@ public class MobGoalGenerator extends SimpleGenerator {
.addModifiers(PRIVATE, STATIC)
.addParameter(keyParam)
.addParameter(typeParam)
.addCode("return $T.of($N, $T.minecraft($N));", GoalKey.class, typeParam, NamespacedKey.class, keyParam)
.addCode("return $T.of($N, $T.minecraft($N));", Types.GOAL_KEY, typeParam, Types.NAMESPACED_KEY, keyParam)
.addTypeVariable(type)
.returns(ParameterizedTypeName.get(ClassName.get(GoalKey.class), type));
.returns(ParameterizedTypeName.get(Types.GOAL_KEY, type));
List<Class<Goal>> classes;
try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages("net.minecraft").scan()) {
try (ScanResult scanResult = new ClassGraph().enableAllInfo().acceptPackages("net.minecraft").scan()) {
classes = scanResult.getSubclasses(Goal.class.getName()).loadClasses(Goal.class);
}
Stream<GoalKey<Mob>> vanillaGoals = classes.stream()
Stream<GoalKey> vanillaGoals = classes.stream()
.filter(clazz -> !java.lang.reflect.Modifier.isAbstract(clazz.getModifiers()))
.filter(clazz -> !clazz.isAnonymousClass() || ClassHelper.getTopLevelClass(clazz) != GoalSelector.class)
.filter(clazz -> !WrappedGoal.class.equals(clazz)) // TODO - properly fix
.map(MobGoalNames::getKey)
.sorted(Comparator.<GoalKey<?>, String>comparing(o -> o.getEntityClass().getSimpleName())
.thenComparing(vanillaGoalKey -> vanillaGoalKey.getNamespacedKey().getKey())
.sorted(Comparator.<GoalKey, String>comparing(o -> o.type().simpleName())
.thenComparing(vanillaGoalKey -> vanillaGoalKey.key().getPath())
);
vanillaGoals.forEach(goalKey -> {
String keyPath = goalKey.getNamespacedKey().getKey();
String keyPath = goalKey.key().getPath();
String fieldName = Formatting.formatKeyAsField(keyPath);
TypeName typedKey = ParameterizedTypeName.get(GoalKey.class, goalKey.getEntityClass());
TypeName typedKey = ParameterizedTypeName.get(Types.GOAL_KEY, goalKey.type());
FieldSpec.Builder fieldBuilder = FieldSpec.builder(typedKey, fieldName, PUBLIC, STATIC, FINAL)
.initializer("$N($S, $T.class)", createMethod.build(), keyPath, goalKey.getEntityClass());
.initializer("$N($S, $T.class)", createMethod.build(), keyPath, goalKey.type());
typeBuilder.addField(fieldBuilder.build());
});

View File

@@ -1,10 +1,11 @@
package io.papermc.generator.types.goal;
import com.destroystokyo.paper.entity.RangedEntity;
import com.destroystokyo.paper.entity.ai.GoalKey;
import com.google.common.base.CaseFormat;
import io.papermc.generator.resources.DataFileLoader;
import io.papermc.generator.resources.DataFiles;
import io.papermc.generator.resources.data.EntityClassData;
import io.papermc.generator.types.Types;
import io.papermc.generator.utils.Formatting;
import io.papermc.paper.entity.SchoolableFish;
import io.papermc.typewriter.util.ClassHelper;
import it.unimi.dsi.fastutil.ints.Int2BooleanFunction;
import java.lang.reflect.Constructor;
@@ -12,260 +13,29 @@ import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import net.minecraft.Util;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.monster.RangedAttackMob;
import org.apache.commons.lang3.math.NumberUtils;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.AbstractCow;
import org.bukkit.entity.AbstractHorse;
import org.bukkit.entity.AbstractSkeleton;
import org.bukkit.entity.AbstractVillager;
import org.bukkit.entity.Ageable;
import org.bukkit.entity.Allay;
import org.bukkit.entity.Ambient;
import org.bukkit.entity.Animals;
import org.bukkit.entity.Armadillo;
import org.bukkit.entity.Axolotl;
import org.bukkit.entity.Bat;
import org.bukkit.entity.Bee;
import org.bukkit.entity.Blaze;
import org.bukkit.entity.Bogged;
import org.bukkit.entity.Breeze;
import org.bukkit.entity.Cat;
import org.bukkit.entity.CaveSpider;
import org.bukkit.entity.ChestedHorse;
import org.bukkit.entity.Chicken;
import org.bukkit.entity.Cod;
import org.bukkit.entity.Cow;
import org.bukkit.entity.Creaking;
import org.bukkit.entity.Creature;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.Dolphin;
import org.bukkit.entity.Donkey;
import org.bukkit.entity.Drowned;
import org.bukkit.entity.ElderGuardian;
import org.bukkit.entity.EnderDragon;
import org.bukkit.entity.Enderman;
import org.bukkit.entity.Endermite;
import org.bukkit.entity.Evoker;
import org.bukkit.entity.Fish;
import org.bukkit.entity.Fox;
import org.bukkit.entity.Frog;
import org.bukkit.entity.Ghast;
import org.bukkit.entity.Giant;
import org.bukkit.entity.GlowSquid;
import org.bukkit.entity.Goat;
import org.bukkit.entity.Golem;
import org.bukkit.entity.Guardian;
import org.bukkit.entity.HappyGhast;
import org.bukkit.entity.Hoglin;
import org.bukkit.entity.Horse;
import org.bukkit.entity.Husk;
import org.bukkit.entity.Illager;
import org.bukkit.entity.Illusioner;
import org.bukkit.entity.IronGolem;
import org.bukkit.entity.Llama;
import org.bukkit.entity.MagmaCube;
import org.bukkit.entity.Mob;
import org.bukkit.entity.Monster;
import org.bukkit.entity.Mule;
import org.bukkit.entity.MushroomCow;
import org.bukkit.entity.Ocelot;
import org.bukkit.entity.Panda;
import org.bukkit.entity.Parrot;
import org.bukkit.entity.Phantom;
import org.bukkit.entity.Pig;
import org.bukkit.entity.PigZombie;
import org.bukkit.entity.Piglin;
import org.bukkit.entity.PiglinAbstract;
import org.bukkit.entity.PiglinBrute;
import org.bukkit.entity.Pillager;
import org.bukkit.entity.PolarBear;
import org.bukkit.entity.PufferFish;
import org.bukkit.entity.Rabbit;
import org.bukkit.entity.Raider;
import org.bukkit.entity.Ravager;
import org.bukkit.entity.Salmon;
import org.bukkit.entity.Sheep;
import org.bukkit.entity.Shulker;
import org.bukkit.entity.Silverfish;
import org.bukkit.entity.Skeleton;
import org.bukkit.entity.SkeletonHorse;
import org.bukkit.entity.Slime;
import org.bukkit.entity.Sniffer;
import org.bukkit.entity.Snowman;
import org.bukkit.entity.Spellcaster;
import org.bukkit.entity.Spider;
import org.bukkit.entity.Squid;
import org.bukkit.entity.Stray;
import org.bukkit.entity.Strider;
import org.bukkit.entity.Tadpole;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.TraderLlama;
import org.bukkit.entity.TropicalFish;
import org.bukkit.entity.Turtle;
import org.bukkit.entity.Vex;
import org.bukkit.entity.Villager;
import org.bukkit.entity.Vindicator;
import org.bukkit.entity.WanderingTrader;
import org.bukkit.entity.Warden;
import org.bukkit.entity.WaterMob;
import org.bukkit.entity.Witch;
import org.bukkit.entity.Wither;
import org.bukkit.entity.WitherSkeleton;
import org.bukkit.entity.Wolf;
import org.bukkit.entity.Zoglin;
import org.bukkit.entity.Zombie;
import org.bukkit.entity.ZombieHorse;
import org.bukkit.entity.ZombieVillager;
import org.jspecify.annotations.NullMarked;
@NullMarked
public final class MobGoalNames { // todo sync with MobGoalHelper ideally this should not be duplicated
private static final Map<Class<? extends Goal>, Class<? extends Mob>> GENERIC_TYPE_CACHE = new HashMap<>();
public static final Map<Class<? extends net.minecraft.world.entity.Mob>, Class<? extends Mob>> BUKKIT_BRIDGE = Util.make(new LinkedHashMap<>(), map -> {
//<editor-fold defaultstate="collapsed" desc="bukkitMap Entities">
map.put(net.minecraft.world.entity.Mob.class, Mob.class);
map.put(net.minecraft.world.entity.AgeableMob.class, Ageable.class);
map.put(net.minecraft.world.entity.ambient.AmbientCreature.class, Ambient.class);
map.put(net.minecraft.world.entity.animal.Animal.class, Animals.class);
map.put(net.minecraft.world.entity.ambient.Bat.class, Bat.class);
map.put(net.minecraft.world.entity.animal.Bee.class, Bee.class);
map.put(net.minecraft.world.entity.monster.Blaze.class, Blaze.class);
map.put(net.minecraft.world.entity.animal.Cat.class, Cat.class);
map.put(net.minecraft.world.entity.monster.CaveSpider.class, CaveSpider.class);
map.put(net.minecraft.world.entity.animal.Chicken.class, Chicken.class);
map.put(net.minecraft.world.entity.animal.Cod.class, Cod.class);
map.put(net.minecraft.world.entity.animal.Cow.class, Cow.class);
map.put(net.minecraft.world.entity.PathfinderMob.class, Creature.class);
map.put(net.minecraft.world.entity.monster.Creeper.class, Creeper.class);
map.put(net.minecraft.world.entity.animal.Dolphin.class, Dolphin.class);
map.put(net.minecraft.world.entity.monster.Drowned.class, Drowned.class);
map.put(net.minecraft.world.entity.boss.enderdragon.EnderDragon.class, EnderDragon.class);
map.put(net.minecraft.world.entity.monster.EnderMan.class, Enderman.class);
map.put(net.minecraft.world.entity.monster.Endermite.class, Endermite.class);
map.put(net.minecraft.world.entity.monster.Evoker.class, Evoker.class);
map.put(net.minecraft.world.entity.animal.AbstractFish.class, Fish.class);
map.put(net.minecraft.world.entity.animal.AbstractSchoolingFish.class, SchoolableFish.class);
map.put(net.minecraft.world.entity.animal.Fox.class, Fox.class);
map.put(net.minecraft.world.entity.monster.Ghast.class, Ghast.class);
map.put(net.minecraft.world.entity.monster.Giant.class, Giant.class);
map.put(net.minecraft.world.entity.animal.AbstractGolem.class, Golem.class);
map.put(net.minecraft.world.entity.monster.Guardian.class, Guardian.class);
map.put(net.minecraft.world.entity.monster.ElderGuardian.class, ElderGuardian.class);
map.put(net.minecraft.world.entity.animal.horse.Horse.class, Horse.class);
map.put(net.minecraft.world.entity.animal.horse.AbstractHorse.class, AbstractHorse.class);
map.put(net.minecraft.world.entity.animal.horse.AbstractChestedHorse.class, ChestedHorse.class);
map.put(net.minecraft.world.entity.animal.horse.Donkey.class, Donkey.class);
map.put(net.minecraft.world.entity.animal.horse.Mule.class, Mule.class);
map.put(net.minecraft.world.entity.animal.horse.SkeletonHorse.class, SkeletonHorse.class);
map.put(net.minecraft.world.entity.animal.horse.ZombieHorse.class, ZombieHorse.class);
map.put(net.minecraft.world.entity.animal.camel.Camel.class, org.bukkit.entity.Camel.class);
map.put(net.minecraft.world.entity.monster.AbstractIllager.class, Illager.class);
map.put(net.minecraft.world.entity.monster.Illusioner.class, Illusioner.class);
map.put(net.minecraft.world.entity.monster.SpellcasterIllager.class, Spellcaster.class);
map.put(net.minecraft.world.entity.animal.IronGolem.class, IronGolem.class);
map.put(net.minecraft.world.entity.animal.horse.Llama.class, Llama.class);
map.put(net.minecraft.world.entity.animal.horse.TraderLlama.class, TraderLlama.class);
map.put(net.minecraft.world.entity.monster.MagmaCube.class, MagmaCube.class);
map.put(net.minecraft.world.entity.monster.Monster.class, Monster.class);
map.put(net.minecraft.world.entity.monster.PatrollingMonster.class, Raider.class); // close enough
map.put(net.minecraft.world.entity.animal.MushroomCow.class, MushroomCow.class);
map.put(net.minecraft.world.entity.animal.Ocelot.class, Ocelot.class);
map.put(net.minecraft.world.entity.animal.Panda.class, Panda.class);
map.put(net.minecraft.world.entity.animal.Parrot.class, Parrot.class);
map.put(net.minecraft.world.entity.animal.ShoulderRidingEntity.class, Parrot.class); // close enough
map.put(net.minecraft.world.entity.monster.Phantom.class, Phantom.class);
map.put(net.minecraft.world.entity.animal.Pig.class, Pig.class);
map.put(net.minecraft.world.entity.monster.ZombifiedPiglin.class, PigZombie.class);
map.put(net.minecraft.world.entity.monster.Pillager.class, Pillager.class);
map.put(net.minecraft.world.entity.animal.PolarBear.class, PolarBear.class);
map.put(net.minecraft.world.entity.animal.Pufferfish.class, PufferFish.class);
map.put(net.minecraft.world.entity.animal.Rabbit.class, Rabbit.class);
map.put(net.minecraft.world.entity.raid.Raider.class, Raider.class);
map.put(net.minecraft.world.entity.monster.Ravager.class, Ravager.class);
map.put(net.minecraft.world.entity.animal.Salmon.class, Salmon.class);
map.put(net.minecraft.world.entity.animal.sheep.Sheep.class, Sheep.class);
map.put(net.minecraft.world.entity.monster.Shulker.class, Shulker.class);
map.put(net.minecraft.world.entity.monster.Silverfish.class, Silverfish.class);
map.put(net.minecraft.world.entity.monster.Skeleton.class, Skeleton.class);
map.put(net.minecraft.world.entity.monster.AbstractSkeleton.class, AbstractSkeleton.class);
map.put(net.minecraft.world.entity.monster.Stray.class, Stray.class);
map.put(net.minecraft.world.entity.monster.WitherSkeleton.class, WitherSkeleton.class);
map.put(net.minecraft.world.entity.monster.Slime.class, Slime.class);
map.put(net.minecraft.world.entity.animal.SnowGolem.class, Snowman.class);
map.put(net.minecraft.world.entity.monster.Spider.class, Spider.class);
map.put(net.minecraft.world.entity.animal.Squid.class, Squid.class);
map.put(net.minecraft.world.entity.TamableAnimal.class, Tameable.class);
map.put(net.minecraft.world.entity.animal.TropicalFish.class, TropicalFish.class);
map.put(net.minecraft.world.entity.animal.Turtle.class, Turtle.class);
map.put(net.minecraft.world.entity.monster.Vex.class, Vex.class);
map.put(net.minecraft.world.entity.npc.Villager.class, Villager.class);
map.put(net.minecraft.world.entity.npc.AbstractVillager.class, AbstractVillager.class);
map.put(net.minecraft.world.entity.npc.WanderingTrader.class, WanderingTrader.class);
map.put(net.minecraft.world.entity.monster.Vindicator.class, Vindicator.class);
map.put(net.minecraft.world.entity.animal.WaterAnimal.class, WaterMob.class);
map.put(net.minecraft.world.entity.monster.Witch.class, Witch.class);
map.put(net.minecraft.world.entity.boss.wither.WitherBoss.class, Wither.class);
map.put(net.minecraft.world.entity.animal.wolf.Wolf.class, Wolf.class);
map.put(net.minecraft.world.entity.monster.Zombie.class, Zombie.class);
map.put(net.minecraft.world.entity.monster.Husk.class, Husk.class);
map.put(net.minecraft.world.entity.monster.ZombieVillager.class, ZombieVillager.class);
map.put(net.minecraft.world.entity.monster.hoglin.Hoglin.class, Hoglin.class);
map.put(net.minecraft.world.entity.monster.piglin.Piglin.class, Piglin.class);
map.put(net.minecraft.world.entity.monster.piglin.AbstractPiglin.class, PiglinAbstract.class);
map.put(net.minecraft.world.entity.monster.piglin.PiglinBrute.class, PiglinBrute.class);
map.put(net.minecraft.world.entity.monster.Strider.class, Strider.class);
map.put(net.minecraft.world.entity.monster.Zoglin.class, Zoglin.class);
map.put(net.minecraft.world.entity.GlowSquid.class, GlowSquid.class);
map.put(net.minecraft.world.entity.animal.axolotl.Axolotl.class, Axolotl.class);
map.put(net.minecraft.world.entity.animal.goat.Goat.class, Goat.class);
map.put(net.minecraft.world.entity.animal.frog.Frog.class, Frog.class);
map.put(net.minecraft.world.entity.animal.frog.Tadpole.class, Tadpole.class);
map.put(net.minecraft.world.entity.monster.warden.Warden.class, Warden.class);
map.put(net.minecraft.world.entity.animal.allay.Allay.class, Allay.class);
map.put(net.minecraft.world.entity.animal.sniffer.Sniffer.class, Sniffer.class);
map.put(net.minecraft.world.entity.monster.breeze.Breeze.class, Breeze.class);
map.put(net.minecraft.world.entity.animal.armadillo.Armadillo.class, Armadillo.class);
map.put(net.minecraft.world.entity.monster.Bogged.class, Bogged.class);
map.put(net.minecraft.world.entity.monster.creaking.Creaking.class, Creaking.class);
map.put(net.minecraft.world.entity.animal.AgeableWaterCreature.class, Squid.class); // close enough
map.put(net.minecraft.world.entity.animal.AbstractCow.class, AbstractCow.class);
map.put(net.minecraft.world.entity.animal.HappyGhast.class, HappyGhast.class);
//</editor-fold>
});
private static final Map<Class<? extends Goal>, EntityClassData> GENERIC_TYPE_CACHE = new HashMap<>();
// TODO these kinda should be checked on each release, in case nested classes changes
private static final Map<String, String> NESTED_CLASS_NAMES = Util.make(new HashMap<>(), map -> {
private static final Map<String, String> RENAMES = Util.make(new HashMap<>(), map -> {
map.put("AbstractSkeleton$1", "AbstractSkeletonMelee");
// remove duplicate
map.put("TraderLlama$TraderLlamaDefendWanderingTraderGoal", "TraderLlamaDefendWanderingTraderGoal");
map.put("AbstractIllager$RaiderOpenDoorGoal", "RaiderOpenDoorGoal");
// weird enderman case
map.put("EnderMan.EndermanFreezeWhenLookedAt", "EndermanFreezeWhenLookedAt");
map.put("EnderMan.EndermanLeaveBlockGoal", "EndermanLeaveBlockGoal");
map.put("EnderMan.EndermanTakeBlockGoal", "EndermanTakeBlockGoal");
map.put("EnderMan.EndermanLookForPlayerGoal", "EndermanLookForPlayerGoal");
});
private static final Set<Class<? extends Mob>> NO_SPECIFIER = Set.of(
Mob.class,
Creature.class,
Animals.class,
RangedEntity.class,
Tameable.class,
Monster.class,
PufferFish.class // weird case
);
private static String getPathName(Class<? extends Mob> type, Class<?> holderClass, String name) {
private static String getPathName(EntityClassData type, Class<?> holderClass, String name) {
String pathName = name.substring(name.lastIndexOf('.') + 1);
boolean needRename = false;
@@ -279,18 +49,18 @@ public final class MobGoalNames { // todo sync with MobGoalHelper ideally this s
break;
}
}
if (!needRename && !NESTED_CLASS_NAMES.containsKey(pathName)) {
if (!needRename && !RENAMES.containsKey(pathName)) {
pathName = innerClassNames;
}
}
if (!NESTED_CLASS_NAMES.containsKey(pathName)) {
if (!RENAMES.containsKey(pathName)) {
if (needRename) {
throw new IllegalStateException("need to map " + name + " (" + pathName + ")");
}
String prefix = null;
if (!NO_SPECIFIER.contains(type)) {
prefix = type.getSimpleName();
if (type.hasSpecifier()) {
prefix = type.name().simpleName();
} else if (!net.minecraft.world.entity.Mob.class.isAssignableFrom(holderClass)) {
prefix = holderClass.getSimpleName();
}
@@ -298,22 +68,21 @@ public final class MobGoalNames { // todo sync with MobGoalHelper ideally this s
pathName = prefix + pathName;
}
} else {
pathName = NESTED_CLASS_NAMES.get(pathName);
pathName = RENAMES.get(pathName);
}
pathName = Formatting.stripWordOfCamelCaseName(pathName, "TargetGoal", true); // replace last? reverse search?
pathName = Formatting.stripWordOfCamelCaseName(pathName, "Goal", true);
pathName = Formatting.stripWordOfCamelCaseName(pathName, "Abstract", true);
pathName = Formatting.stripInitialWord(pathName, "Abstract");
pathName = pathName.replaceAll("TargetGoal|Goal", "");
pathName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, pathName);
return pathName;
}
public static <T extends Mob> GoalKey<T> getKey(Class<? extends Goal> goalClass) {
Class<T> type = getGenericType(goalClass);
static GoalKey getKey(Class<? extends Goal> goalClass) {
EntityClassData classData = getGenericType(goalClass);
Class<?> holderClass = ClassHelper.getTopLevelClass(goalClass);
String name = getPathName(type, holderClass, goalClass.getName());
return GoalKey.of(type, NamespacedKey.minecraft(name));
String name = getPathName(classData, holderClass, goalClass.getName());
return new GoalKey(classData.name(), ResourceLocation.withDefaultNamespace(name));
}
private static final Int2BooleanFunction[] VISIBILITY_SEARCH_STEP = {
@@ -334,19 +103,18 @@ public final class MobGoalNames { // todo sync with MobGoalHelper ideally this s
throw new UnsupportedOperationException("Unknown visibility: " + mod);
});
private static <T extends Mob> Class<T> getGenericType(Class<? extends Goal> goalClass) {
//noinspection unchecked
return (Class<T>) GENERIC_TYPE_CACHE.computeIfAbsent(goalClass, key -> {
private static EntityClassData getGenericType(Class<? extends Goal> goalClass) {
return GENERIC_TYPE_CACHE.computeIfAbsent(goalClass, key -> {
Constructor<?>[] constructors = key.getDeclaredConstructors();
Arrays.sort(constructors, VISIBILITY_ORDER);
for (Constructor<?> constructor : constructors) {
for (Class<?> paramType : constructor.getParameterTypes()) {
if (net.minecraft.world.entity.Mob.class.isAssignableFrom(paramType)) {
for (Class<?> param : constructor.getParameterTypes()) {
if (net.minecraft.world.entity.Mob.class.isAssignableFrom(param)) {
//noinspection unchecked
return toBukkitClass((Class<? extends net.minecraft.world.entity.Mob>) paramType);
} else if (RangedAttackMob.class.isAssignableFrom(paramType)) {
return RangedEntity.class;
return toBukkitClassData((Class<? extends net.minecraft.world.entity.Mob>) param);
} else if (RangedAttackMob.class.isAssignableFrom(param)) {
return new EntityClassData(Types.RANGED_ENTITY, false); // todo move outside
}
}
}
@@ -354,11 +122,11 @@ public final class MobGoalNames { // todo sync with MobGoalHelper ideally this s
});
}
private static Class<? extends Mob> toBukkitClass(Class<? extends net.minecraft.world.entity.Mob> internalClass) {
Class<? extends Mob> bukkitClass = BUKKIT_BRIDGE.get(internalClass);
if (bukkitClass == null) {
private static EntityClassData toBukkitClassData(Class<? extends net.minecraft.world.entity.Mob> internalClass) {
EntityClassData data = DataFileLoader.get(DataFiles.ENTITY_CLASS_NAMES).get(internalClass);
if (data == null) {
throw new IllegalStateException("Can't figure out applicable bukkit entity for internal entity " + internalClass); // maybe just return Mob?
}
return bukkitClass;
return data;
}
}

View File

@@ -9,19 +9,19 @@ import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import io.papermc.generator.registry.RegistryEntry;
import io.papermc.generator.registry.RegistryIdentifiable;
import io.papermc.generator.types.SimpleGenerator;
import io.papermc.generator.types.Types;
import io.papermc.generator.utils.Annotations;
import io.papermc.generator.utils.Formatting;
import io.papermc.generator.utils.Javadocs;
import io.papermc.generator.utils.experimental.ExperimentalCollector;
import io.papermc.generator.utils.experimental.SingleFlagHolder;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.TypedKey;
import java.util.Map;
import java.util.function.Supplier;
import javax.lang.model.SourceVersion;
import net.kyori.adventure.key.Key;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.flag.FeatureElement;
import net.minecraft.world.flag.FeatureFlags;
@@ -37,7 +37,7 @@ import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
@NullMarked
public class GeneratedKeyType<T> extends SimpleGenerator {
public class GeneratedKeyType<T> extends SimpleGenerator implements RegistryIdentifiable<T> {
private final RegistryEntry<T> entry;
private final Supplier<Map<ResourceKey<T>, SingleFlagHolder>> experimentalKeys;
@@ -47,20 +47,25 @@ public class GeneratedKeyType<T> extends SimpleGenerator {
super(entry.keyClassName().concat("Keys"), packageName);
this.entry = entry;
this.experimentalKeys = Suppliers.memoize(() -> ExperimentalCollector.collectDataDrivenElementIds(entry.registry()));
this.isFilteredRegistry = FeatureElement.FILTERED_REGISTRIES.contains(entry.registryKey());
this.isFilteredRegistry = FeatureElement.FILTERED_REGISTRIES.contains(entry.getRegistryKey());
}
@Override
public ResourceKey<? extends Registry<T>> getRegistryKey() {
return this.entry.getRegistryKey();
}
private MethodSpec.Builder createMethod(TypeName returnType) {
boolean publicCreateKeyMethod = this.entry.allowCustomKeys();
ParameterSpec keyParam = ParameterSpec.builder(Key.class, "key", FINAL).build();
ParameterSpec keyParam = ParameterSpec.builder(Types.KEY, "key", FINAL).build();
MethodSpec.Builder create = MethodSpec.methodBuilder("create")
.addModifiers(publicCreateKeyMethod ? PUBLIC : PRIVATE, STATIC)
.addParameter(keyParam)
.addCode("return $T.create($T.$L, $N);", TypedKey.class, RegistryKey.class, this.entry.registryKeyField(), keyParam)
.addCode("return $T.create($T.$L, $N);", Types.TYPED_KEY, Types.REGISTRY_KEY, this.entry.registryKeyField(), keyParam)
.returns(returnType);
if (publicCreateKeyMethod) {
create.addJavadoc(Javadocs.CREATE_TYPED_KEY_JAVADOC, this.entry.apiClass(), this.entry.registryKey().location().toString());
create.addJavadoc(Javadocs.CREATE_TYPED_KEY_JAVADOC, Types.typed(this.entry.data().api().klass().name()), this.entry.getRegistryKey().location().toString());
}
return create;
}
@@ -68,7 +73,7 @@ public class GeneratedKeyType<T> extends SimpleGenerator {
private TypeSpec.Builder keyHolderType() {
return classBuilder(this.className)
.addModifiers(PUBLIC, FINAL)
.addJavadoc(Javadocs.getVersionDependentClassHeader("keys", "{@link $T#$L}"), RegistryKey.class, this.entry.registryKeyField())
.addJavadoc(Javadocs.getVersionDependentClassHeader("keys", "{@link $T#$L}"), Types.REGISTRY_KEY, this.entry.registryKeyField())
.addAnnotations(Annotations.CLASS_HEADER)
.addMethod(MethodSpec.constructorBuilder()
.addModifiers(PRIVATE)
@@ -78,7 +83,7 @@ public class GeneratedKeyType<T> extends SimpleGenerator {
@Override
protected TypeSpec getTypeSpec() {
TypeName typedKeyType = ParameterizedTypeName.get(TypedKey.class, this.entry.apiClass());
TypeName typedKeyType = ParameterizedTypeName.get(Types.TYPED_KEY, this.entry.data().api().klass().getType());
TypeSpec.Builder typeBuilder = this.keyHolderType();
MethodSpec.Builder createMethod = this.createMethod(typedKeyType);
@@ -114,7 +119,7 @@ public class GeneratedKeyType<T> extends SimpleGenerator {
@Override
protected JavaFile.Builder file(JavaFile.Builder builder) {
return builder.addStaticImport(Key.class, "key");
return builder.addStaticImport(Types.KEY, "key");
}
protected @Nullable SingleFlagHolder getRequiredFeature(Holder.Reference<T> reference) {

View File

@@ -9,15 +9,16 @@ import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import io.papermc.generator.Main;
import io.papermc.generator.registry.RegistryEntry;
import io.papermc.generator.registry.RegistryIdentifiable;
import io.papermc.generator.types.SimpleGenerator;
import io.papermc.generator.types.Types;
import io.papermc.generator.utils.Annotations;
import io.papermc.generator.utils.Formatting;
import io.papermc.generator.utils.Javadocs;
import io.papermc.generator.utils.experimental.SingleFlagHolder;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.tag.TagKey;
import java.util.concurrent.atomic.AtomicBoolean;
import net.kyori.adventure.key.Key;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import org.jspecify.annotations.NullMarked;
import static com.squareup.javapoet.TypeSpec.classBuilder;
@@ -29,26 +30,31 @@ import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
@NullMarked
public class GeneratedTagKeyType extends SimpleGenerator {
public class GeneratedTagKeyType<T> extends SimpleGenerator implements RegistryIdentifiable<T> {
private final RegistryEntry<?> entry;
private final RegistryEntry<T> entry;
public GeneratedTagKeyType(RegistryEntry<?> entry, String packageName) {
public GeneratedTagKeyType(RegistryEntry<T> entry, String packageName) {
super(entry.keyClassName().concat("TagKeys"), packageName);
this.entry = entry;
}
@Override
public ResourceKey<? extends Registry<T>> getRegistryKey() {
return this.entry.getRegistryKey();
}
private MethodSpec.Builder createMethod(TypeName returnType) {
boolean publicCreateKeyMethod = true; // tag lifecycle event exists
ParameterSpec keyParam = ParameterSpec.builder(Key.class, "key", FINAL).build();
ParameterSpec keyParam = ParameterSpec.builder(Types.KEY, "key", FINAL).build();
MethodSpec.Builder create = MethodSpec.methodBuilder("create")
.addModifiers(publicCreateKeyMethod ? PUBLIC : PRIVATE, STATIC)
.addParameter(keyParam)
.addCode("return $T.create($T.$L, $N);", TagKey.class, RegistryKey.class, this.entry.registryKeyField(), keyParam)
.addCode("return $T.create($T.$L, $N);", Types.TAG_KEY, Types.REGISTRY_KEY, this.entry.registryKeyField(), keyParam)
.returns(returnType);
if (publicCreateKeyMethod) {
create.addJavadoc(Javadocs.CREATED_TAG_KEY_JAVADOC, this.entry.apiClass(), this.entry.registryKey().location().toString());
create.addJavadoc(Javadocs.CREATED_TAG_KEY_JAVADOC, Types.typed(this.entry.data().api().klass().name()), this.entry.getRegistryKey().location().toString());
}
return create;
}
@@ -56,7 +62,7 @@ public class GeneratedTagKeyType extends SimpleGenerator {
private TypeSpec.Builder keyHolderType() {
return classBuilder(this.className)
.addModifiers(PUBLIC, FINAL)
.addJavadoc(Javadocs.getVersionDependentClassHeader("tag keys", "{@link $T#$L}"), RegistryKey.class, this.entry.registryKeyField())
.addJavadoc(Javadocs.getVersionDependentClassHeader("tag keys", "{@link $T#$L}"), Types.REGISTRY_KEY, this.entry.registryKeyField())
.addAnnotations(Annotations.CLASS_HEADER)
.addMethod(MethodSpec.constructorBuilder()
.addModifiers(PRIVATE)
@@ -66,7 +72,7 @@ public class GeneratedTagKeyType extends SimpleGenerator {
@Override
protected TypeSpec getTypeSpec() {
TypeName tagKeyType = ParameterizedTypeName.get(TagKey.class, this.entry.apiClass());
TypeName tagKeyType = ParameterizedTypeName.get(Types.TAG_KEY, this.entry.data().api().klass().getType());
TypeSpec.Builder typeBuilder = this.keyHolderType();
MethodSpec.Builder createMethod = this.createMethod(tagKeyType);
@@ -95,6 +101,6 @@ public class GeneratedTagKeyType extends SimpleGenerator {
@Override
protected JavaFile.Builder file(JavaFile.Builder builder) {
return builder.addStaticImport(Key.class, "key");
return builder.addStaticImport(Types.KEY, "key");
}
}

View File

@@ -1,20 +1,18 @@
package io.papermc.generator.utils;
import com.squareup.javapoet.AnnotationSpec;
import io.papermc.generator.types.Types;
import io.papermc.generator.utils.experimental.SingleFlagHolder;
import io.papermc.paper.generated.GeneratedFrom;
import java.util.List;
import net.minecraft.SharedConstants;
import org.bukkit.MinecraftExperimental;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
@NullMarked
public final class Annotations {
public static List<AnnotationSpec> experimentalAnnotations(SingleFlagHolder requiredFeature) {
AnnotationSpec.Builder builder = AnnotationSpec.builder(MinecraftExperimental.class);
builder.addMember("value", "$T.$L", MinecraftExperimental.Requires.class, requiredFeature.asAnnotationMember().name());
AnnotationSpec.Builder builder = AnnotationSpec.builder(Types.MINECRAFT_EXPERIMENTAL);
builder.addMember("value", "$T.$L", Types.MINECRAFT_EXPERIMENTAL_REQUIRES, requiredFeature.asAnnotationMember());
return List.of(
AnnotationSpec.builder(ApiStatus.Experimental.class).build(),
@@ -34,7 +32,7 @@ public final class Annotations {
public static final AnnotationSpec EXPERIMENTAL_API_ANNOTATION = AnnotationSpec.builder(ApiStatus.Experimental.class).build();
public static final AnnotationSpec NULL_MARKED = AnnotationSpec.builder(NullMarked.class).build();
public static final AnnotationSpec OVERRIDE = AnnotationSpec.builder(Override.class).build();
public static final AnnotationSpec GENERATED_FROM = AnnotationSpec.builder(GeneratedFrom.class)
public static final AnnotationSpec GENERATED_FROM = AnnotationSpec.builder(Types.GENERATED_FROM)
.addMember("value", "$S", SharedConstants.getCurrentVersion().id())
.build();
public static final Iterable<AnnotationSpec> CLASS_HEADER = List.of(

View File

@@ -0,0 +1,33 @@
package io.papermc.generator.utils;
import com.squareup.javapoet.ClassName;
import io.papermc.typewriter.ClassNamed;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.Nullable;
public record BasePackage(String name) {
public static final BasePackage PAPER = new BasePackage("io.papermc.paper");
public static final BasePackage BUKKIT = new BasePackage("org.bukkit");
public static final BasePackage CRAFT_BUKKIT = new BasePackage("org.bukkit.craftbukkit");
@ApiStatus.Obsolete
public static final BasePackage PAPER_LEGACY = new BasePackage("com.destroystokyo.paper");
@Deprecated
public static final BasePackage SPIGOT = new BasePackage("org.spigotmc");
public ClassName rootClass(String simpleName, String... simpleNames) {
return relativeClass(null, simpleName, simpleNames);
}
public ClassName relativeClass(@Nullable String packageName, String simpleName, String... simpleNames) {
return ClassName.get(packageName == null ? this.name : String.join(".", this.name, packageName), simpleName, simpleNames);
}
public ClassNamed rootClassNamed(String simpleName, String... simpleNames) {
return relativeClassNamed(null, simpleName, simpleNames);
}
public ClassNamed relativeClassNamed(@Nullable String packageName, String simpleName, String... simpleNames) {
return ClassNamed.of(packageName == null ? this.name : String.join(".", this.name, packageName), simpleName, simpleNames);
}
}

View File

@@ -8,9 +8,7 @@ import java.util.Map;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.block.entity.BlockEntityType;
import org.jspecify.annotations.NullMarked;
@NullMarked
public final class BlockEntityMapping {
// if this become painful/too weird like the blockdata just rename the impl directly again

Some files were not shown because too many files have changed in this diff Show More