CraftBlockData mapping

This commit is contained in:
Lulu13022002 2024-03-16 19:37:55 +01:00
parent 6ff47f215f
commit 59252a0fd1
No known key found for this signature in database
GPG Key ID: 491C8F0B8ACDEB01
31 changed files with 1064 additions and 69 deletions

View File

@ -26,13 +26,16 @@ tasks.register<JavaExec>("generate") {
classpath(sourceSets.main.map { it.runtimeClasspath })
args(file("generated").toString(),
project(":paper-api").sourceSets["main"].java.srcDirs.first().toString(),
file("generatedServerTest").toString())
file("generatedServerTest").toString(),
project(":paper-server").sourceSets["main"].java.srcDirs.first().toString())
}
tasks.test {
useJUnitPlatform()
systemProperty("paper.generator.rewriter.container", file("generated").toString()) // todo move to the sourceset
systemProperty("paper.generator.rewriter.container.api", file("generated").toString()) // todo move to the sourceset
systemProperty("paper.generator.rewriter.container.server", file("generatedServerTest").toString()) // todo move to the sourceset
inputs.dir("generated")
inputs.dir("generatedServerTest")
}
group = "io.papermc.paper"

View File

@ -0,0 +1,769 @@
package org.bukkit.craftbukkit.block.data;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import net.minecraft.commands.arguments.blocks.BlockStateParser;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.state.StateHolder;
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.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.SoundGroup;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.BlockSupport;
import org.bukkit.block.PistonMoveReaction;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.structure.Mirror;
import org.bukkit.block.structure.StructureRotation;
import org.bukkit.craftbukkit.CraftSoundGroup;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.block.CraftBlock;
import org.bukkit.craftbukkit.block.CraftBlockStates;
import org.bukkit.craftbukkit.block.CraftBlockSupport;
import org.bukkit.craftbukkit.block.CraftBlockType;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.inventory.CraftItemType;
import org.bukkit.craftbukkit.util.CraftLocation;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
public class CraftBlockData implements BlockData {
private net.minecraft.world.level.block.state.BlockState state;
private Map<Property<?>, Comparable<?>> parsedStates;
protected CraftBlockData() {
throw new AssertionError("Template Constructor");
}
protected CraftBlockData(net.minecraft.world.level.block.state.BlockState state) {
this.state = state;
}
@Override
public Material getMaterial() {
return this.state.getBukkitMaterial(); // Paper - optimise getType calls
}
public net.minecraft.world.level.block.state.BlockState getState() {
return this.state;
}
/**
* Get a given BlockStateEnum's value as its Bukkit counterpart.
*
* @param nms the NMS state to convert
* @param bukkit the Bukkit class
* @param <B> the type
* @return the matching Bukkit type
*/
protected <B extends Enum<B>> B get(EnumProperty<?> nms, Class<B> bukkit) {
return CraftBlockData.toBukkit(this.state.getValue(nms), bukkit);
}
/**
* Convert all values from the given BlockStateEnum to their appropriate
* Bukkit counterpart.
*
* @param nms the NMS state to get values from
* @param bukkit the bukkit class to convert the values to
* @param <B> the bukkit class type
* @return an immutable Set of values in their appropriate Bukkit type
*/
@SuppressWarnings("unchecked")
protected <B extends Enum<B>> Set<B> getValues(EnumProperty<?> nms, Class<B> bukkit) {
ImmutableSet.Builder<B> values = ImmutableSet.builder();
for (Enum<?> e : nms.getPossibleValues()) {
values.add(CraftBlockData.toBukkit(e, bukkit));
}
return values.build();
}
/**
* Set a given {@link EnumProperty} with the matching enum from Bukkit.
*
* @param nms the NMS BlockStateEnum to set
* @param bukkit the matching Bukkit Enum
* @param <B> the Bukkit type
* @param <N> the NMS type
*/
protected <B extends Enum<B>, N extends Enum<N> & StringRepresentable> void set(EnumProperty<N> nms, Enum<B> bukkit) {
this.parsedStates = null;
this.state = this.state.setValue(nms, CraftBlockData.toNMS(bukkit, nms.getValueClass()));
}
@Override
public BlockData merge(BlockData data) {
CraftBlockData craft = (CraftBlockData) data;
Preconditions.checkArgument(craft.parsedStates != null, "Data not created via string parsing");
Preconditions.checkArgument(this.state.getBlock() == craft.state.getBlock(), "States have different types (got %s, expected %s)", data, this);
CraftBlockData clone = (CraftBlockData) this.clone();
clone.parsedStates = null;
for (Property parsed : craft.parsedStates.keySet()) {
clone.state = clone.state.setValue(parsed, craft.state.getValue(parsed));
}
return clone;
}
@Override
public boolean matches(BlockData data) {
if (data == null) {
return false;
}
if (!(data instanceof CraftBlockData)) {
return false;
}
CraftBlockData craft = (CraftBlockData) data;
if (this.state.getBlock() != craft.state.getBlock()) {
return false;
}
// Fastpath an exact match
boolean exactMatch = this.equals(data);
// If that failed, do a merge and check
if (!exactMatch && craft.parsedStates != null) {
return this.merge(data).equals(this);
}
return exactMatch;
}
private static final Map<Class<? extends Enum<?>>, Enum<?>[]> ENUM_VALUES = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - cache block data strings; make thread safe
/**
* Convert an NMS Enum (usually a BlockStateEnum) to its appropriate Bukkit
* enum from the given class.
*
* @throws IllegalStateException if the Enum could not be converted
*/
@SuppressWarnings("unchecked")
private static <B extends Enum<B>> B toBukkit(Enum<?> nms, Class<B> bukkit) {
if (nms instanceof Direction) {
return (B) CraftBlock.notchToBlockFace((Direction) nms);
}
return (B) CraftBlockData.ENUM_VALUES.computeIfAbsent(bukkit, Class::getEnumConstants)[nms.ordinal()];
}
/**
* Convert a given Bukkit enum to its matching NMS enum type.
*
* @param bukkit the Bukkit enum to convert
* @param nms the NMS class
* @return the matching NMS type
* @throws IllegalStateException if the Enum could not be converted
*/
@SuppressWarnings("unchecked")
public static <N extends Enum<N> & StringRepresentable> N toNMS(Enum<?> bukkit, Class<N> nms) {
if (bukkit instanceof BlockFace) {
return (N) CraftBlock.blockFaceToNotch((BlockFace) bukkit);
}
return (N) CraftBlockData.ENUM_VALUES.computeIfAbsent(nms, Class::getEnumConstants)[bukkit.ordinal()];
}
/**
* Get the current value of a given state.
*
* @param ibs the state to check
* @param <T> the type
* @return the current value of the given state
*/
protected <T extends Comparable<T>> T get(Property<T> ibs) {
// Straight integer or boolean getter
return this.state.getValue(ibs);
}
/**
* Set the specified state's value.
*
* @param ibs the state to set
* @param v the new value
* @param <T> the state's type
* @param <V> the value's type. Must match the state's type.
*/
public <T extends Comparable<T>, V extends T> void set(Property<T> ibs, V v) {
// Straight integer or boolean setter
this.parsedStates = null;
this.state = this.state.setValue(ibs, v);
}
@Override
public String getAsString() {
return this.toString(this.state.getValues());
}
@Override
public String getAsString(boolean hideUnspecified) {
return (hideUnspecified && this.parsedStates != null) ? this.toString(this.parsedStates) : this.getAsString();
}
@Override
public BlockData clone() {
try {
return (BlockData) super.clone();
} catch (CloneNotSupportedException ex) {
throw new AssertionError("Clone not supported", ex);
}
}
@Override
public String toString() {
return "CraftBlockData{" + this.getAsString() + "}";
}
// Mimicked from BlockDataAbstract#toString()
public String toString(Map<Property<?>, Comparable<?>> states) {
StringBuilder stateString = new StringBuilder(BuiltInRegistries.BLOCK.getKey(this.state.getBlock()).toString());
if (!states.isEmpty()) {
stateString.append('[');
stateString.append(states.entrySet().stream().map(StateHolder.PROPERTY_ENTRY_TO_STRING_FUNCTION).collect(Collectors.joining(",")));
stateString.append(']');
}
return stateString.toString();
}
public CompoundTag toStates() {
CompoundTag compound = new CompoundTag();
for (Map.Entry<Property<?>, Comparable<?>> entry : this.state.getValues().entrySet()) {
Property iblockstate = (Property) entry.getKey();
compound.putString(iblockstate.getName(), iblockstate.getName(entry.getValue()));
}
return compound;
}
@Override
public boolean equals(Object obj) {
return obj instanceof CraftBlockData && this.state.equals(((CraftBlockData) obj).state);
}
@Override
public int hashCode() {
return this.state.hashCode();
}
protected static BooleanProperty getBoolean(String name) {
throw new AssertionError("Template Method");
}
protected static BooleanProperty getBoolean(String name, boolean optional) {
throw new AssertionError("Template Method");
}
protected static EnumProperty<?> getEnum(String name) {
throw new AssertionError("Template Method");
}
protected static IntegerProperty getInteger(String name) {
throw new AssertionError("Template Method");
}
protected static BooleanProperty getBoolean(Class<? extends Block> block, String name) {
return (BooleanProperty) CraftBlockData.getState(block, name, false);
}
protected static BooleanProperty getBoolean(Class<? extends Block> block, String name, boolean optional) {
return (BooleanProperty) CraftBlockData.getState(block, name, optional);
}
protected static EnumProperty<?> getEnum(Class<? extends Block> block, String name) {
return (EnumProperty<?>) CraftBlockData.getState(block, name, false);
}
protected static IntegerProperty getInteger(Class<? extends Block> block, String name) {
return (IntegerProperty) CraftBlockData.getState(block, name, false);
}
/**
* Get a specified {@link Property} from a given block's class with a
* given name
*
* @param block the class to retrieve the state from
* @param name the name of the state to retrieve
* @param optional if the state can be null
* @return the specified state or null
* @throws IllegalStateException if the state is null and {@code optional}
* is false.
*/
private static Property<?> getState(Class<? extends Block> block, String name, boolean optional) {
Property<?> state = null;
for (Block instance : BuiltInRegistries.BLOCK) {
if (instance.getClass() == block) {
if (state == null) {
state = instance.getStateDefinition().getProperty(name);
} else {
Property<?> newState = instance.getStateDefinition().getProperty(name);
Preconditions.checkState(state == newState, "State mistmatch %s,%s", state, newState);
}
}
}
Preconditions.checkState(optional || state != null, "Null state for %s,%s", block, name);
return state;
}
/**
* Get the minimum value allowed by the BlockStateInteger.
*
* @param state the state to check
* @return the minimum value allowed
*/
protected static int getMin(IntegerProperty state) {
return state.min;
}
/**
* Get the maximum value allowed by the BlockStateInteger.
*
* @param state the state to check
* @return the maximum value allowed
*/
protected static int getMax(IntegerProperty state) {
return state.max;
}
public static final BlockFace[] ROTATION_CYCLE = {
BlockFace.SOUTH, BlockFace.SOUTH_SOUTH_WEST, BlockFace.SOUTH_WEST, BlockFace.WEST_SOUTH_WEST,
BlockFace.WEST, BlockFace.WEST_NORTH_WEST, BlockFace.NORTH_WEST, BlockFace.NORTH_NORTH_WEST,
BlockFace.NORTH, BlockFace.NORTH_NORTH_EAST, BlockFace.NORTH_EAST, BlockFace.EAST_NORTH_EAST,
BlockFace.EAST, BlockFace.EAST_SOUTH_EAST, BlockFace.SOUTH_EAST, BlockFace.SOUTH_SOUTH_EAST
};
//
private static final Map<Class<? extends Block>, Function<net.minecraft.world.level.block.state.BlockState, CraftBlockData>> MAP = new HashMap<>();
static {
//<editor-fold desc="CraftBlockData Registration" defaultstate="collapsed">
// Paper start - Generated/CraftBlockData#MAP
// @GeneratedFrom 1.20.4
register(net.minecraft.world.level.block.AmethystClusterBlock.class, org.bukkit.craftbukkit.block.impl.CraftAmethystCluster::new);
register(net.minecraft.world.level.block.AnvilBlock.class, org.bukkit.craftbukkit.block.impl.CraftAnvil::new);
register(net.minecraft.world.level.block.AttachedStemBlock.class, org.bukkit.craftbukkit.block.impl.CraftAttachedStem::new);
register(net.minecraft.world.level.block.BambooStalkBlock.class, org.bukkit.craftbukkit.block.impl.CraftBambooStalk::new);
register(net.minecraft.world.level.block.BannerBlock.class, org.bukkit.craftbukkit.block.impl.CraftBanner::new);
register(net.minecraft.world.level.block.BarrelBlock.class, org.bukkit.craftbukkit.block.impl.CraftBarrel::new);
register(net.minecraft.world.level.block.BarrierBlock.class, org.bukkit.craftbukkit.block.impl.CraftBarrier::new);
register(net.minecraft.world.level.block.BaseCoralFanBlock.class, org.bukkit.craftbukkit.block.impl.CraftBaseCoralFan::new);
register(net.minecraft.world.level.block.BaseCoralPlantBlock.class, org.bukkit.craftbukkit.block.impl.CraftBaseCoralPlant::new);
register(net.minecraft.world.level.block.BaseCoralWallFanBlock.class, org.bukkit.craftbukkit.block.impl.CraftBaseCoralWallFan::new);
register(net.minecraft.world.level.block.BedBlock.class, org.bukkit.craftbukkit.block.impl.CraftBed::new);
register(net.minecraft.world.level.block.BeehiveBlock.class, org.bukkit.craftbukkit.block.impl.CraftBeehive::new);
register(net.minecraft.world.level.block.BeetrootBlock.class, org.bukkit.craftbukkit.block.impl.CraftBeetroot::new);
register(net.minecraft.world.level.block.BellBlock.class, org.bukkit.craftbukkit.block.impl.CraftBell::new);
register(net.minecraft.world.level.block.BigDripleafBlock.class, org.bukkit.craftbukkit.block.impl.CraftBigDripleaf::new);
register(net.minecraft.world.level.block.BigDripleafStemBlock.class, org.bukkit.craftbukkit.block.impl.CraftBigDripleafStem::new);
register(net.minecraft.world.level.block.BlastFurnaceBlock.class, org.bukkit.craftbukkit.block.impl.CraftBlastFurnace::new);
register(net.minecraft.world.level.block.BrewingStandBlock.class, org.bukkit.craftbukkit.block.impl.CraftBrewingStand::new);
register(net.minecraft.world.level.block.BrushableBlock.class, org.bukkit.craftbukkit.block.impl.CraftBrushable::new);
register(net.minecraft.world.level.block.BubbleColumnBlock.class, org.bukkit.craftbukkit.block.impl.CraftBubbleColumn::new);
register(net.minecraft.world.level.block.ButtonBlock.class, org.bukkit.craftbukkit.block.impl.CraftButton::new);
register(net.minecraft.world.level.block.CactusBlock.class, org.bukkit.craftbukkit.block.impl.CraftCactus::new);
register(net.minecraft.world.level.block.CakeBlock.class, org.bukkit.craftbukkit.block.impl.CraftCake::new);
register(net.minecraft.world.level.block.CalibratedSculkSensorBlock.class, org.bukkit.craftbukkit.block.impl.CraftCalibratedSculkSensor::new);
register(net.minecraft.world.level.block.CampfireBlock.class, org.bukkit.craftbukkit.block.impl.CraftCampfire::new);
register(net.minecraft.world.level.block.CandleBlock.class, org.bukkit.craftbukkit.block.impl.CraftCandle::new);
register(net.minecraft.world.level.block.CandleCakeBlock.class, org.bukkit.craftbukkit.block.impl.CraftCandleCake::new);
register(net.minecraft.world.level.block.CarrotBlock.class, org.bukkit.craftbukkit.block.impl.CraftCarrot::new);
register(net.minecraft.world.level.block.CarvedPumpkinBlock.class, org.bukkit.craftbukkit.block.impl.CraftCarvedPumpkin::new);
register(net.minecraft.world.level.block.CaveVinesBlock.class, org.bukkit.craftbukkit.block.impl.CraftCaveVines::new);
register(net.minecraft.world.level.block.CaveVinesPlantBlock.class, org.bukkit.craftbukkit.block.impl.CraftCaveVinesPlant::new);
register(net.minecraft.world.level.block.CeilingHangingSignBlock.class, org.bukkit.craftbukkit.block.impl.CraftCeilingHangingSign::new);
register(net.minecraft.world.level.block.ChainBlock.class, org.bukkit.craftbukkit.block.impl.CraftChain::new);
register(net.minecraft.world.level.block.CherryLeavesBlock.class, org.bukkit.craftbukkit.block.impl.CraftCherryLeaves::new);
register(net.minecraft.world.level.block.ChestBlock.class, org.bukkit.craftbukkit.block.impl.CraftChest::new);
register(net.minecraft.world.level.block.ChiseledBookShelfBlock.class, org.bukkit.craftbukkit.block.impl.CraftChiseledBookShelf::new);
register(net.minecraft.world.level.block.ChorusFlowerBlock.class, org.bukkit.craftbukkit.block.impl.CraftChorusFlower::new);
register(net.minecraft.world.level.block.ChorusPlantBlock.class, org.bukkit.craftbukkit.block.impl.CraftChorusPlant::new);
register(net.minecraft.world.level.block.CocoaBlock.class, org.bukkit.craftbukkit.block.impl.CraftCocoa::new);
register(net.minecraft.world.level.block.CommandBlock.class, org.bukkit.craftbukkit.block.impl.CraftCommandBlock::new);
register(net.minecraft.world.level.block.ComparatorBlock.class, org.bukkit.craftbukkit.block.impl.CraftComparator::new);
register(net.minecraft.world.level.block.ComposterBlock.class, org.bukkit.craftbukkit.block.impl.CraftComposter::new);
register(net.minecraft.world.level.block.ConduitBlock.class, org.bukkit.craftbukkit.block.impl.CraftConduit::new);
register(net.minecraft.world.level.block.CopperBulbBlock.class, org.bukkit.craftbukkit.block.impl.CraftCopperBulb::new);
register(net.minecraft.world.level.block.CoralFanBlock.class, org.bukkit.craftbukkit.block.impl.CraftCoralFan::new);
register(net.minecraft.world.level.block.CoralPlantBlock.class, org.bukkit.craftbukkit.block.impl.CraftCoralPlant::new);
register(net.minecraft.world.level.block.CoralWallFanBlock.class, org.bukkit.craftbukkit.block.impl.CraftCoralWallFan::new);
register(net.minecraft.world.level.block.CrafterBlock.class, org.bukkit.craftbukkit.block.impl.CraftCrafter::new);
register(net.minecraft.world.level.block.CropBlock.class, org.bukkit.craftbukkit.block.impl.CraftCrop::new);
register(net.minecraft.world.level.block.DaylightDetectorBlock.class, org.bukkit.craftbukkit.block.impl.CraftDaylightDetector::new);
register(net.minecraft.world.level.block.DecoratedPotBlock.class, org.bukkit.craftbukkit.block.impl.CraftDecoratedPot::new);
register(net.minecraft.world.level.block.DetectorRailBlock.class, org.bukkit.craftbukkit.block.impl.CraftDetectorRail::new);
register(net.minecraft.world.level.block.DispenserBlock.class, org.bukkit.craftbukkit.block.impl.CraftDispenser::new);
register(net.minecraft.world.level.block.DoorBlock.class, org.bukkit.craftbukkit.block.impl.CraftDoor::new);
register(net.minecraft.world.level.block.DoublePlantBlock.class, org.bukkit.craftbukkit.block.impl.CraftDoublePlant::new);
register(net.minecraft.world.level.block.DropperBlock.class, org.bukkit.craftbukkit.block.impl.CraftDropper::new);
register(net.minecraft.world.level.block.EndPortalFrameBlock.class, org.bukkit.craftbukkit.block.impl.CraftEndPortalFrame::new);
register(net.minecraft.world.level.block.EndRodBlock.class, org.bukkit.craftbukkit.block.impl.CraftEndRod::new);
register(net.minecraft.world.level.block.EnderChestBlock.class, org.bukkit.craftbukkit.block.impl.CraftEnderChest::new);
register(net.minecraft.world.level.block.EquipableCarvedPumpkinBlock.class, org.bukkit.craftbukkit.block.impl.CraftEquipableCarvedPumpkin::new);
register(net.minecraft.world.level.block.FarmBlock.class, org.bukkit.craftbukkit.block.impl.CraftFarm::new);
register(net.minecraft.world.level.block.FenceBlock.class, org.bukkit.craftbukkit.block.impl.CraftFence::new);
register(net.minecraft.world.level.block.FenceGateBlock.class, org.bukkit.craftbukkit.block.impl.CraftFenceGate::new);
register(net.minecraft.world.level.block.FireBlock.class, org.bukkit.craftbukkit.block.impl.CraftFire::new);
register(net.minecraft.world.level.block.FrostedIceBlock.class, org.bukkit.craftbukkit.block.impl.CraftFrostedIce::new);
register(net.minecraft.world.level.block.FurnaceBlock.class, org.bukkit.craftbukkit.block.impl.CraftFurnace::new);
register(net.minecraft.world.level.block.GlazedTerracottaBlock.class, org.bukkit.craftbukkit.block.impl.CraftGlazedTerracotta::new);
register(net.minecraft.world.level.block.GlowLichenBlock.class, org.bukkit.craftbukkit.block.impl.CraftGlowLichen::new);
register(net.minecraft.world.level.block.GrassBlock.class, org.bukkit.craftbukkit.block.impl.CraftGrass::new);
register(net.minecraft.world.level.block.GrindstoneBlock.class, org.bukkit.craftbukkit.block.impl.CraftGrindstone::new);
register(net.minecraft.world.level.block.HangingRootsBlock.class, org.bukkit.craftbukkit.block.impl.CraftHangingRoots::new);
register(net.minecraft.world.level.block.HayBlock.class, org.bukkit.craftbukkit.block.impl.CraftHay::new);
register(net.minecraft.world.level.block.HopperBlock.class, org.bukkit.craftbukkit.block.impl.CraftHopper::new);
register(net.minecraft.world.level.block.HugeMushroomBlock.class, org.bukkit.craftbukkit.block.impl.CraftHugeMushroom::new);
register(net.minecraft.world.level.block.InfestedRotatedPillarBlock.class, org.bukkit.craftbukkit.block.impl.CraftInfestedRotatedPillar::new);
register(net.minecraft.world.level.block.IronBarsBlock.class, org.bukkit.craftbukkit.block.impl.CraftIronBars::new);
register(net.minecraft.world.level.block.JigsawBlock.class, org.bukkit.craftbukkit.block.impl.CraftJigsaw::new);
register(net.minecraft.world.level.block.JukeboxBlock.class, org.bukkit.craftbukkit.block.impl.CraftJukebox::new);
register(net.minecraft.world.level.block.KelpBlock.class, org.bukkit.craftbukkit.block.impl.CraftKelp::new);
register(net.minecraft.world.level.block.LadderBlock.class, org.bukkit.craftbukkit.block.impl.CraftLadder::new);
register(net.minecraft.world.level.block.LanternBlock.class, org.bukkit.craftbukkit.block.impl.CraftLantern::new);
register(net.minecraft.world.level.block.LayeredCauldronBlock.class, org.bukkit.craftbukkit.block.impl.CraftLayeredCauldron::new);
register(net.minecraft.world.level.block.LeavesBlock.class, org.bukkit.craftbukkit.block.impl.CraftLeaves::new);
register(net.minecraft.world.level.block.LecternBlock.class, org.bukkit.craftbukkit.block.impl.CraftLectern::new);
register(net.minecraft.world.level.block.LeverBlock.class, org.bukkit.craftbukkit.block.impl.CraftLever::new);
register(net.minecraft.world.level.block.LightBlock.class, org.bukkit.craftbukkit.block.impl.CraftLight::new);
register(net.minecraft.world.level.block.LightningRodBlock.class, org.bukkit.craftbukkit.block.impl.CraftLightningRod::new);
register(net.minecraft.world.level.block.LiquidBlock.class, org.bukkit.craftbukkit.block.impl.CraftLiquid::new);
register(net.minecraft.world.level.block.LoomBlock.class, org.bukkit.craftbukkit.block.impl.CraftLoom::new);
register(net.minecraft.world.level.block.MangroveLeavesBlock.class, org.bukkit.craftbukkit.block.impl.CraftMangroveLeaves::new);
register(net.minecraft.world.level.block.MangrovePropaguleBlock.class, org.bukkit.craftbukkit.block.impl.CraftMangrovePropagule::new);
register(net.minecraft.world.level.block.MangroveRootsBlock.class, org.bukkit.craftbukkit.block.impl.CraftMangroveRoots::new);
register(net.minecraft.world.level.block.MyceliumBlock.class, org.bukkit.craftbukkit.block.impl.CraftMycelium::new);
register(net.minecraft.world.level.block.NetherPortalBlock.class, org.bukkit.craftbukkit.block.impl.CraftNetherPortal::new);
register(net.minecraft.world.level.block.NetherWartBlock.class, org.bukkit.craftbukkit.block.impl.CraftNetherWart::new);
register(net.minecraft.world.level.block.NoteBlock.class, org.bukkit.craftbukkit.block.impl.CraftNoteBlock::new);
register(net.minecraft.world.level.block.ObserverBlock.class, org.bukkit.craftbukkit.block.impl.CraftObserver::new);
register(net.minecraft.world.level.block.PiglinWallSkullBlock.class, org.bukkit.craftbukkit.block.impl.CraftPiglinWallSkull::new);
register(net.minecraft.world.level.block.PinkPetalsBlock.class, org.bukkit.craftbukkit.block.impl.CraftPinkPetals::new);
register(net.minecraft.world.level.block.PitcherCropBlock.class, org.bukkit.craftbukkit.block.impl.CraftPitcherCrop::new);
register(net.minecraft.world.level.block.PlayerHeadBlock.class, org.bukkit.craftbukkit.block.impl.CraftPlayerHead::new);
register(net.minecraft.world.level.block.PlayerWallHeadBlock.class, org.bukkit.craftbukkit.block.impl.CraftPlayerWallHead::new);
register(net.minecraft.world.level.block.PointedDripstoneBlock.class, org.bukkit.craftbukkit.block.impl.CraftPointedDripstone::new);
register(net.minecraft.world.level.block.PotatoBlock.class, org.bukkit.craftbukkit.block.impl.CraftPotato::new);
register(net.minecraft.world.level.block.PoweredRailBlock.class, org.bukkit.craftbukkit.block.impl.CraftPoweredRail::new);
register(net.minecraft.world.level.block.PressurePlateBlock.class, org.bukkit.craftbukkit.block.impl.CraftPressurePlate::new);
register(net.minecraft.world.level.block.RailBlock.class, org.bukkit.craftbukkit.block.impl.CraftRail::new);
register(net.minecraft.world.level.block.RedStoneOreBlock.class, org.bukkit.craftbukkit.block.impl.CraftRedStoneOre::new);
register(net.minecraft.world.level.block.RedStoneWireBlock.class, org.bukkit.craftbukkit.block.impl.CraftRedStoneWire::new);
register(net.minecraft.world.level.block.RedstoneLampBlock.class, org.bukkit.craftbukkit.block.impl.CraftRedstoneLamp::new);
register(net.minecraft.world.level.block.RedstoneTorchBlock.class, org.bukkit.craftbukkit.block.impl.CraftRedstoneTorch::new);
register(net.minecraft.world.level.block.RedstoneWallTorchBlock.class, org.bukkit.craftbukkit.block.impl.CraftRedstoneWallTorch::new);
register(net.minecraft.world.level.block.RepeaterBlock.class, org.bukkit.craftbukkit.block.impl.CraftRepeater::new);
register(net.minecraft.world.level.block.RespawnAnchorBlock.class, org.bukkit.craftbukkit.block.impl.CraftRespawnAnchor::new);
register(net.minecraft.world.level.block.RotatedPillarBlock.class, org.bukkit.craftbukkit.block.impl.CraftRotatedPillar::new);
register(net.minecraft.world.level.block.SaplingBlock.class, org.bukkit.craftbukkit.block.impl.CraftSapling::new);
register(net.minecraft.world.level.block.ScaffoldingBlock.class, org.bukkit.craftbukkit.block.impl.CraftScaffolding::new);
register(net.minecraft.world.level.block.SculkCatalystBlock.class, org.bukkit.craftbukkit.block.impl.CraftSculkCatalyst::new);
register(net.minecraft.world.level.block.SculkSensorBlock.class, org.bukkit.craftbukkit.block.impl.CraftSculkSensor::new);
register(net.minecraft.world.level.block.SculkShriekerBlock.class, org.bukkit.craftbukkit.block.impl.CraftSculkShrieker::new);
register(net.minecraft.world.level.block.SculkVeinBlock.class, org.bukkit.craftbukkit.block.impl.CraftSculkVein::new);
register(net.minecraft.world.level.block.SeaPickleBlock.class, org.bukkit.craftbukkit.block.impl.CraftSeaPickle::new);
register(net.minecraft.world.level.block.ShulkerBoxBlock.class, org.bukkit.craftbukkit.block.impl.CraftShulkerBox::new);
register(net.minecraft.world.level.block.SkullBlock.class, org.bukkit.craftbukkit.block.impl.CraftSkull::new);
register(net.minecraft.world.level.block.SlabBlock.class, org.bukkit.craftbukkit.block.impl.CraftSlab::new);
register(net.minecraft.world.level.block.SmallDripleafBlock.class, org.bukkit.craftbukkit.block.impl.CraftSmallDripleaf::new);
register(net.minecraft.world.level.block.SmokerBlock.class, org.bukkit.craftbukkit.block.impl.CraftSmoker::new);
register(net.minecraft.world.level.block.SnifferEggBlock.class, org.bukkit.craftbukkit.block.impl.CraftSnifferEgg::new);
register(net.minecraft.world.level.block.SnowLayerBlock.class, org.bukkit.craftbukkit.block.impl.CraftSnowLayer::new);
register(net.minecraft.world.level.block.SnowyDirtBlock.class, org.bukkit.craftbukkit.block.impl.CraftSnowyDirt::new);
register(net.minecraft.world.level.block.StainedGlassPaneBlock.class, org.bukkit.craftbukkit.block.impl.CraftStainedGlassPane::new);
register(net.minecraft.world.level.block.StairBlock.class, org.bukkit.craftbukkit.block.impl.CraftStair::new);
register(net.minecraft.world.level.block.StandingSignBlock.class, org.bukkit.craftbukkit.block.impl.CraftStandingSign::new);
register(net.minecraft.world.level.block.StemBlock.class, org.bukkit.craftbukkit.block.impl.CraftStem::new);
register(net.minecraft.world.level.block.StonecutterBlock.class, org.bukkit.craftbukkit.block.impl.CraftStonecutter::new);
register(net.minecraft.world.level.block.StructureBlock.class, org.bukkit.craftbukkit.block.impl.CraftStructureBlock::new);
register(net.minecraft.world.level.block.SugarCaneBlock.class, org.bukkit.craftbukkit.block.impl.CraftSugarCane::new);
register(net.minecraft.world.level.block.SweetBerryBushBlock.class, org.bukkit.craftbukkit.block.impl.CraftSweetBerryBush::new);
register(net.minecraft.world.level.block.TallFlowerBlock.class, org.bukkit.craftbukkit.block.impl.CraftTallFlower::new);
register(net.minecraft.world.level.block.TallSeagrassBlock.class, org.bukkit.craftbukkit.block.impl.CraftTallSeagrass::new);
register(net.minecraft.world.level.block.TargetBlock.class, org.bukkit.craftbukkit.block.impl.CraftTarget::new);
register(net.minecraft.world.level.block.TntBlock.class, org.bukkit.craftbukkit.block.impl.CraftTnt::new);
register(net.minecraft.world.level.block.TorchflowerCropBlock.class, org.bukkit.craftbukkit.block.impl.CraftTorchflowerCrop::new);
register(net.minecraft.world.level.block.TrapDoorBlock.class, org.bukkit.craftbukkit.block.impl.CraftTrapDoor::new);
register(net.minecraft.world.level.block.TrappedChestBlock.class, org.bukkit.craftbukkit.block.impl.CraftTrappedChest::new);
register(net.minecraft.world.level.block.TrialSpawnerBlock.class, org.bukkit.craftbukkit.block.impl.CraftTrialSpawner::new);
register(net.minecraft.world.level.block.TripWireBlock.class, org.bukkit.craftbukkit.block.impl.CraftTripWire::new);
register(net.minecraft.world.level.block.TripWireHookBlock.class, org.bukkit.craftbukkit.block.impl.CraftTripWireHook::new);
register(net.minecraft.world.level.block.TurtleEggBlock.class, org.bukkit.craftbukkit.block.impl.CraftTurtleEgg::new);
register(net.minecraft.world.level.block.TwistingVinesBlock.class, org.bukkit.craftbukkit.block.impl.CraftTwistingVines::new);
register(net.minecraft.world.level.block.VineBlock.class, org.bukkit.craftbukkit.block.impl.CraftVine::new);
register(net.minecraft.world.level.block.WallBannerBlock.class, org.bukkit.craftbukkit.block.impl.CraftWallBanner::new);
register(net.minecraft.world.level.block.WallBlock.class, org.bukkit.craftbukkit.block.impl.CraftWall::new);
register(net.minecraft.world.level.block.WallHangingSignBlock.class, org.bukkit.craftbukkit.block.impl.CraftWallHangingSign::new);
register(net.minecraft.world.level.block.WallSignBlock.class, org.bukkit.craftbukkit.block.impl.CraftWallSign::new);
register(net.minecraft.world.level.block.WallSkullBlock.class, org.bukkit.craftbukkit.block.impl.CraftWallSkull::new);
register(net.minecraft.world.level.block.WallTorchBlock.class, org.bukkit.craftbukkit.block.impl.CraftWallTorch::new);
register(net.minecraft.world.level.block.WaterloggedTransparentBlock.class, org.bukkit.craftbukkit.block.impl.CraftWaterloggedTransparent::new);
register(net.minecraft.world.level.block.WeatheringCopperBulbBlock.class, org.bukkit.craftbukkit.block.impl.CraftWeatheringCopperBulb::new);
register(net.minecraft.world.level.block.WeatheringCopperDoorBlock.class, org.bukkit.craftbukkit.block.impl.CraftWeatheringCopperDoor::new);
register(net.minecraft.world.level.block.WeatheringCopperGrateBlock.class, org.bukkit.craftbukkit.block.impl.CraftWeatheringCopperGrate::new);
register(net.minecraft.world.level.block.WeatheringCopperSlabBlock.class, org.bukkit.craftbukkit.block.impl.CraftWeatheringCopperSlab::new);
register(net.minecraft.world.level.block.WeatheringCopperStairBlock.class, org.bukkit.craftbukkit.block.impl.CraftWeatheringCopperStair::new);
register(net.minecraft.world.level.block.WeatheringCopperTrapDoorBlock.class, org.bukkit.craftbukkit.block.impl.CraftWeatheringCopperTrapDoor::new);
register(net.minecraft.world.level.block.WeepingVinesBlock.class, org.bukkit.craftbukkit.block.impl.CraftWeepingVines::new);
register(net.minecraft.world.level.block.WeightedPressurePlateBlock.class, org.bukkit.craftbukkit.block.impl.CraftWeightedPressurePlate::new);
register(net.minecraft.world.level.block.WitherSkullBlock.class, org.bukkit.craftbukkit.block.impl.CraftWitherSkull::new);
register(net.minecraft.world.level.block.WitherWallSkullBlock.class, org.bukkit.craftbukkit.block.impl.CraftWitherWallSkull::new);
register(net.minecraft.world.level.block.piston.MovingPistonBlock.class, org.bukkit.craftbukkit.block.impl.CraftMovingPiston::new);
register(net.minecraft.world.level.block.piston.PistonBaseBlock.class, org.bukkit.craftbukkit.block.impl.CraftPistonBase::new);
register(net.minecraft.world.level.block.piston.PistonHeadBlock.class, org.bukkit.craftbukkit.block.impl.CraftPistonHead::new);
// Paper end - Generated/CraftBlockData#MAP
//</editor-fold>
}
private static void register(Class<? extends Block> nms, Function<net.minecraft.world.level.block.state.BlockState, CraftBlockData> bukkit) {
Preconditions.checkState(CraftBlockData.MAP.put(nms, bukkit) == null, "Duplicate mapping %s->%s", nms, bukkit);
}
// Paper start - cache block data strings
private static Map<String, CraftBlockData> stringDataCache = new java.util.concurrent.ConcurrentHashMap<>();
static {
// cache all of the default states at startup, will not cache ones with the custom states inside of the
// brackets in a different order, though
reloadCache();
}
public static void reloadCache() {
stringDataCache.clear();
Block.BLOCK_STATE_REGISTRY.forEach(blockData -> stringDataCache.put(blockData.toString(), blockData.createCraftBlockData()));
}
// Paper end - cache block data strings
public static CraftBlockData newData(Material material, String data) {
Preconditions.checkArgument(material == null || material.isBlock(), "Cannot get data for not block %s", material);
// Paper start - cache block data strings
if (material != null) {
Block block = CraftBlockType.bukkitToMinecraft(material);
if (block != null) {
net.minecraft.resources.ResourceLocation key = BuiltInRegistries.BLOCK.getKey(block);
data = data == null ? key.toString() : key + data;
}
}
CraftBlockData cached = stringDataCache.computeIfAbsent(data, s -> createNewData(null, s));
return (CraftBlockData) cached.clone();
}
private static CraftBlockData createNewData(Material material, String data) {
// Paper end - cache block data strings
net.minecraft.world.level.block.state.BlockState blockData;
Block block = CraftBlockType.bukkitToMinecraft(material);
Map<Property<?>, Comparable<?>> parsed = null;
// Data provided, use it
if (data != null) {
try {
// Material provided, force that material in
if (block != null) {
data = BuiltInRegistries.BLOCK.getKey(block) + data;
}
StringReader reader = new StringReader(data);
BlockStateParser.BlockResult arg = BlockStateParser.parseForBlock(BuiltInRegistries.BLOCK.asLookup(), reader, false);
Preconditions.checkArgument(!reader.canRead(), "Spurious trailing data: " + data);
blockData = arg.blockState();
parsed = arg.properties();
} catch (CommandSyntaxException ex) {
throw new IllegalArgumentException("Could not parse data: " + data, ex);
}
} else {
blockData = block.defaultBlockState();
}
CraftBlockData craft = CraftBlockData.fromData(blockData);
craft.parsedStates = parsed;
return craft;
}
// Paper start - optimize creating BlockData to not need a map lookup
static {
// Initialize cached data for all IBlockData instances after registration
Block.BLOCK_STATE_REGISTRY.iterator().forEachRemaining(net.minecraft.world.level.block.state.BlockState::createCraftBlockData);
}
public static CraftBlockData fromData(net.minecraft.world.level.block.state.BlockState data) {
return data.createCraftBlockData();
}
public static CraftBlockData createData(net.minecraft.world.level.block.state.BlockState data) {
// Paper end
return CraftBlockData.MAP.getOrDefault(data.getBlock().getClass(), CraftBlockData::new).apply(data);
}
@Override
public SoundGroup getSoundGroup() {
return CraftSoundGroup.getSoundGroup(this.state.getSoundType());
}
@Override
public int getLightEmission() {
return this.state.getLightEmission();
}
@Override
public boolean isOccluding() {
return this.state.canOcclude();
}
@Override
public boolean requiresCorrectToolForDrops() {
return this.state.requiresCorrectToolForDrops();
}
@Override
public boolean isPreferredTool(ItemStack tool) {
Preconditions.checkArgument(tool != null, "tool must not be null");
net.minecraft.world.item.ItemStack nms = CraftItemStack.asNMSCopy(tool);
return CraftBlockData.isPreferredTool(this.state, nms);
}
public static boolean isPreferredTool(net.minecraft.world.level.block.state.BlockState iblockdata, net.minecraft.world.item.ItemStack nmsItem) {
return !iblockdata.requiresCorrectToolForDrops() || nmsItem.isCorrectToolForDrops(iblockdata);
}
@Override
public PistonMoveReaction getPistonMoveReaction() {
return PistonMoveReaction.getById(this.state.getPistonPushReaction().ordinal());
}
@Override
public boolean isSupported(org.bukkit.block.Block block) {
Preconditions.checkArgument(block != null, "block must not be null");
CraftBlock craftBlock = (CraftBlock) block;
return this.state.canSurvive(craftBlock.getCraftWorld().getHandle(), craftBlock.getPosition());
}
@Override
public boolean isSupported(Location location) {
Preconditions.checkArgument(location != null, "location must not be null");
CraftWorld world = (CraftWorld) location.getWorld();
Preconditions.checkArgument(world != null, "location must not have a null world");
BlockPos position = CraftLocation.toBlockPosition(location);
return this.state.canSurvive(world.getHandle(), position);
}
@Override
public boolean isFaceSturdy(BlockFace face, BlockSupport support) {
Preconditions.checkArgument(face != null, "face must not be null");
Preconditions.checkArgument(support != null, "support must not be null");
return this.state.isFaceSturdy(EmptyBlockGetter.INSTANCE, BlockPos.ZERO, CraftBlock.blockFaceToNotch(face), CraftBlockSupport.toNMS(support));
}
// Paper start
@Override
public org.bukkit.util.VoxelShape getCollisionShape(Location location) {
Preconditions.checkArgument(location != null, "location must not be null");
CraftWorld world = (CraftWorld) location.getWorld();
Preconditions.checkArgument(world != null, "location must not have a null world");
BlockPos position = CraftLocation.toBlockPosition(location);
net.minecraft.world.phys.shapes.VoxelShape shape = this.state.getCollisionShape(world.getHandle(), position);
return new org.bukkit.craftbukkit.util.CraftVoxelShape(shape);
}
// Paper end
@Override
public Color getMapColor() {
return Color.fromRGB(this.state.getMapColor(null, null).col);
}
@Override
public Material getPlacementMaterial() {
return CraftItemType.minecraftToBukkit(this.state.getBlock().asItem());
}
@Override
public void rotate(StructureRotation rotation) {
this.state = this.state.rotate(Rotation.valueOf(rotation.name()));
}
@Override
public void mirror(Mirror mirror) {
this.state = this.state.mirror(net.minecraft.world.level.block.Mirror.valueOf(mirror.name()));
}
@Override
public void copyTo(BlockData blockData) {
CraftBlockData other = (CraftBlockData) blockData;
net.minecraft.world.level.block.state.BlockState nms = other.state;
for (Property<?> property : this.state.getBlock().getStateDefinition().getProperties()) {
if (nms.hasProperty(property)) {
nms = this.copyProperty(this.state, nms, property);
}
}
other.state = nms;
}
private <T extends Comparable<T>> net.minecraft.world.level.block.state.BlockState copyProperty(net.minecraft.world.level.block.state.BlockState source, net.minecraft.world.level.block.state.BlockState target, Property<T> property) {
return target.setValue(property, source.getValue(property));
}
@NotNull
@Override
public BlockState createBlockState() {
return CraftBlockStates.getBlockState(this.state, null);
}
// Paper start - destroy speed API
@Override
public float getDestroySpeed(final ItemStack itemStack, final boolean considerEnchants) {
net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.unwrap(itemStack);
float speed = nmsItemStack.getDestroySpeed(this.state);
if (speed > 1.0F && considerEnchants) {
int enchantLevel = net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.BLOCK_EFFICIENCY, nmsItemStack);
if (enchantLevel > 0) {
speed += enchantLevel * enchantLevel + 1;
}
}
return speed;
}
// Paper end - destroy speed API
// Paper start - Block tick API
@Override
public boolean isRandomlyTicked() {
return this.state.isRandomlyTicking();
}
// Paper end - Block tick API
}

View File

@ -4,6 +4,7 @@ import io.papermc.generator.rewriter.CompositeRewriter;
import io.papermc.generator.rewriter.SourceRewriter;
import io.papermc.generator.rewriter.types.EnumCloneRewriter;
import io.papermc.generator.rewriter.types.EnumRegistryRewriter;
import io.papermc.generator.rewriter.types.simple.CraftBlockDataMapping;
import io.papermc.generator.rewriter.types.simple.MapPaletteRewriter;
import io.papermc.generator.rewriter.types.RegistryFieldRewriter;
import io.papermc.generator.rewriter.types.TagRewriter;
@ -194,6 +195,10 @@ public interface Generators {
new MapPaletteRewriter("MapPalette#colors"),
};
SourceRewriter[] SERVER_REWRITE = {
new CraftBlockDataMapping("CraftBlockData#MAP")
};
private static <T, A> SourceGenerator simpleKey(final String className, final Class<A> apiType, final ResourceKey<? extends Registry<T>> registryKey, final RegistryKey<A> apiRegistryKey, final boolean publicCreateKeyMethod) {
return new GeneratedKeyType<>(className, apiType, "io.papermc.paper.registry.keys", registryKey, apiRegistryKey, publicCreateKeyMethod);
}

View File

@ -35,6 +35,7 @@ public final class Main {
public static final RegistryAccess.Frozen REGISTRY_ACCESS;
public static final TagResult EXPERIMENTAL_TAGS;
public static Path generatedPath;
public static Path generatedServerPath;
static {
SharedConstants.tryDetectVersion();
@ -59,10 +60,13 @@ public final class Main {
LOGGER.info("Running API generators...");
Main.generatedPath = Path.of(args[0]); // todo remove
Main.generatedServerPath = Path.of(args[2]); // todo remove
try {
generate(Main.generatedPath, Generators.API);
apply(Path.of(args[1]), Generators.API_REWRITE);
generateCraftBlockData(Path.of(args[2]));
generateCraftBlockData(Main.generatedServerPath);
apply(Path.of(args[3]), Generators.SERVER_REWRITE);
} catch (final RuntimeException ex) {
throw ex;
} catch (IOException e) {

View File

@ -0,0 +1,52 @@
package io.papermc.generator.rewriter;
import io.papermc.generator.utils.ClassHelper;
import org.jetbrains.annotations.Nullable;
public record ClassNamed(String packageName, String simpleName, String dottedNestedName, @Nullable Class<?> clazz) {
public ClassNamed(Class<?> clazz) {
this(clazz.getPackageName(), clazz.getSimpleName(), ClassHelper.retrieveFullNestedName(clazz), clazz);
}
// the class name shouldn't have any '$' char in it
// otherwise it will be interpreted as a nested class
public static ClassNamed of(String packageName, String name) {
int nestedIndex = name.lastIndexOf('$');
final String simpleName;
final String nestedName;
if (nestedIndex != -1) {
simpleName = name.substring(nestedIndex + 1);
nestedName = name.replace('$', '.');
} else {
simpleName = name;
nestedName = name;
}
return new ClassNamed(packageName, simpleName, nestedName, null);
}
public String rootClassSimpleName() {
if (this.clazz != null) {
return ClassHelper.getRootClass(this.clazz).getSimpleName();
}
int dotIndex = this.dottedNestedName.indexOf('.');
if (dotIndex != -1) {
return this.dottedNestedName.substring(0, dotIndex);
}
return this.dottedNestedName;
}
public String rootClassCanonicalName() {
return this.packageName + '.' + this.rootClassSimpleName();
}
public String canonicalName() {
if (this.clazz != null) {
return this.clazz.getCanonicalName();
}
return this.packageName + '.' + this.dottedNestedName;
}
}

View File

@ -1,7 +1,6 @@
package io.papermc.generator.rewriter;
import com.google.common.base.Preconditions;
import io.papermc.generator.utils.ClassHelper;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Arrays;
@ -14,7 +13,7 @@ public class CompositeRewriter extends SearchReplaceRewriter {
private final Map<String, SearchReplaceRewriter> patternsInfo;
private CompositeRewriter(Class<?> rewriteClass, List<SearchReplaceRewriter> rewriters) {
private CompositeRewriter(ClassNamed rewriteClass, List<SearchReplaceRewriter> rewriters) {
super(rewriteClass, null, false);
this.patternsInfo = rewriters.stream().collect(Collectors.toMap(rewriter -> rewriter.pattern, rewriter -> rewriter));
}
@ -32,13 +31,14 @@ public class CompositeRewriter extends SearchReplaceRewriter {
public static CompositeRewriter bind(List<SearchReplaceRewriter> rewriters) {
Preconditions.checkArgument(!rewriters.isEmpty(), "Rewriter list cannot be empty!");
Class<?> rewriteClass = rewriters.get(0).rewriteClass;
Class<?> rootClass = ClassHelper.getRootClass(rewriteClass);
ClassNamed rewriteClass = rewriters.get(0).rewriteClass;
String rootClassName = rewriteClass.rootClassCanonicalName();
for (SearchReplaceRewriter rewriter : rewriters) {
Preconditions.checkState(!(rewriter instanceof CompositeRewriter), "Nested composite rewriters are not allowed!");
Preconditions.checkArgument(rewriter.pattern != null, "Rewriter pattern cannot be null!");
Preconditions.checkState(rewriteClass.getPackageName().equals(rewriter.rewriteClass.getPackageName()) &&
rootClass == ClassHelper.getRootClass(rewriter.rewriteClass), "Composite rewriter only works for one file!");
Preconditions.checkState(rewriteClass.packageName().equals(rewriter.rewriteClass.packageName()) &&
rootClassName.equals(rewriter.rewriteClass.rootClassCanonicalName()), "Composite rewriter only works for one file!");
}
return new CompositeRewriter(rewriteClass, rewriters);

View File

@ -1,6 +1,6 @@
package io.papermc.generator.rewriter;
import io.papermc.generator.rewriter.utils.ImportCollector;
import io.papermc.generator.rewriter.context.ImportCollector;
public record SearchMetadata(ImportCollector importCollector, String indent, String replacedContent, int line) {
}

View File

@ -4,8 +4,9 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import io.papermc.generator.Main;
import io.papermc.generator.rewriter.utils.Annotations;
import io.papermc.generator.rewriter.context.ImportCollector;
import io.papermc.generator.rewriter.context.ImportTypeCollector;
import io.papermc.generator.utils.ClassHelper;
import io.papermc.generator.rewriter.utils.ImportCollector;
import io.papermc.generator.utils.Formatting;
import io.papermc.paper.generated.GeneratedFrom;
import net.minecraft.SharedConstants;
@ -33,11 +34,15 @@ public class SearchReplaceRewriter implements SourceRewriter {
@VisibleForTesting
public static final String GENERATED_COMMENT_FORMAT = "// %s - Generated/%s"; // {0} = PAPER_START_FORMAT|PAPER_END_FORMAT {1} = pattern
protected final Class<?> rewriteClass;
protected final ClassNamed rewriteClass;
protected final String pattern;
protected final boolean equalsSize;
public SearchReplaceRewriter(Class<?> rewriteClass, String pattern, boolean equalsSize) {
this(new ClassNamed(rewriteClass), pattern, equalsSize);
}
public SearchReplaceRewriter(ClassNamed rewriteClass, String pattern, boolean equalsSize) {
this.rewriteClass = rewriteClass;
this.pattern = pattern;
this.equalsSize = equalsSize;
@ -67,11 +72,18 @@ public class SearchReplaceRewriter implements SourceRewriter {
Set<String> foundPatterns = new HashSet<>();
StringBuilder strippedContent = null;
Class<?> rootClass = ClassHelper.getRootClass(this.rewriteClass);
ImportCollector importCollector = new ImportCollector(rootClass);
final ImportCollector importCollector;
String rootClassDeclaration = null;
String indent = Formatting.incrementalIndent(INDENT_UNIT, rootClass);
String rootClassDeclaration = "%s %s".formatted(ClassHelper.getDeclaredType(rootClass), rootClass.getSimpleName());
if (this.rewriteClass.clazz() != null) {
Class<?> rootClass = ClassHelper.getRootClass(this.rewriteClass.clazz());
importCollector = new ImportTypeCollector(rootClass);
rootClassDeclaration = "%s %s".formatted(ClassHelper.getDeclaredType(rootClass), this.rewriteClass.rootClassSimpleName());
} else {
importCollector = ImportCollector.NO_OP; // for now skip the import collector for server gen
}
String indent = Formatting.incrementalIndent(INDENT_UNIT, this.rewriteClass);
boolean inBody = false;
int i = 0;
while (true) {
@ -81,9 +93,9 @@ public class SearchReplaceRewriter implements SourceRewriter {
}
// collect import to avoid fqn when not needed
if (!inBody) {
if (importCollector != ImportCollector.NO_OP && !inBody) {
if (line.startsWith("import ") && line.endsWith(";")) {
importCollector.consume(line);
((ImportTypeCollector) importCollector).consume(line);
}
if (line.contains(rootClassDeclaration)) { // might fail on comments but good enough
inBody = true;
@ -93,7 +105,7 @@ public class SearchReplaceRewriter implements SourceRewriter {
Optional<String> endPattern = this.searchPattern(line, indent, PAPER_END_FORMAT, patterns);
if (endPattern.isPresent()) {
if (this.foundRewriter == null) {
throw new IllegalStateException("Start generated comment missing for pattern " + endPattern.get() + " in class " + this.rewriteClass.getSimpleName() + " at line " + (i + 1));
throw new IllegalStateException("Start generated comment missing for pattern " + endPattern.get() + " in class " + this.rewriteClass.simpleName() + " at line " + (i + 1));
}
if (this.foundRewriter.pattern.equals(endPattern.get())) {
if (!this.foundRewriter.equalsSize) {
@ -104,7 +116,7 @@ public class SearchReplaceRewriter implements SourceRewriter {
}
this.foundRewriter = null;
} else {
throw new IllegalStateException("End generated comment doesn't match for pattern " + this.foundRewriter.pattern + " in " + this.rewriteClass.getSimpleName() + " at line " + (i + 1));
throw new IllegalStateException("End generated comment doesn't match for pattern " + this.foundRewriter.pattern + " in " + this.rewriteClass.simpleName() + " at line " + (i + 1));
}
}
@ -125,7 +137,7 @@ public class SearchReplaceRewriter implements SourceRewriter {
Optional<String> startPattern = this.searchPattern(line, null, PAPER_START_FORMAT, patterns);
if (startPattern.isPresent()) {
if (this.foundRewriter != null) {
throw new IllegalStateException("Nested generated comments are not allowed for " + this.rewriteClass.getSimpleName() + " at line " + (i + 1));
throw new IllegalStateException("Nested generated comments are not allowed for " + this.rewriteClass.simpleName() + " at line " + (i + 1));
}
int startPatternIndex = line.indexOf(GENERATED_COMMENT_FORMAT.formatted(PAPER_START_FORMAT, startPattern.get()));
indent = " ".repeat(startPatternIndex); // update indent based on the comments for flexibility
@ -143,7 +155,7 @@ public class SearchReplaceRewriter implements SourceRewriter {
}
if (this.foundRewriter != null) {
throw new IllegalStateException("End generated comment " + this.foundRewriter.pattern + " missing for " + this.rewriteClass.getSimpleName());
throw new IllegalStateException("End generated comment " + this.foundRewriter.pattern + " missing for " + this.rewriteClass.simpleName());
}
Set<String> diff = Sets.difference(patterns, foundPatterns);
@ -155,8 +167,8 @@ public class SearchReplaceRewriter implements SourceRewriter {
@Override
public void writeToFile(Path parent) throws IOException {
String filePath = "%s/%s.java".formatted(
this.rewriteClass.getPackageName().replace('.', '/'),
ClassHelper.getRootClass(this.rewriteClass).getSimpleName()
this.rewriteClass.packageName().replace('.', '/'),
this.rewriteClass.rootClassSimpleName()
);
Path path = parent.resolve(filePath);
@ -166,7 +178,12 @@ public class SearchReplaceRewriter implements SourceRewriter {
}
// Files.writeString(path, content.toString(), StandardCharsets.UTF_8); // todo
Path createdPath = Main.generatedPath.resolve(filePath);
Path createdPath;
if (path.toString().contains("Paper/Paper-API/src/")) {
createdPath = Main.generatedPath.resolve(filePath);
} else {
createdPath = Main.generatedServerPath.resolve(filePath);
}
Files.createDirectories(createdPath.getParent());
Files.writeString(createdPath, content.toString(), StandardCharsets.UTF_8);
}

View File

@ -0,0 +1,21 @@
package io.papermc.generator.rewriter.context;
public interface ImportCollector {
ImportCollector NO_OP = new ImportCollector() {
@Override
public String getStaticAlias(final String fqn) {
return fqn;
}
@Override
public String getTypeName(final Class<?> clazz) {
return clazz.getCanonicalName();
}
};
String getStaticAlias(String fqn);
String getTypeName(Class<?> clazz);
}

View File

@ -1,4 +1,4 @@
package io.papermc.generator.rewriter.utils;
package io.papermc.generator.rewriter.context;
import io.papermc.generator.utils.ClassHelper;
import org.jetbrains.annotations.VisibleForTesting;
@ -7,7 +7,7 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class ImportCollector {
public class ImportTypeCollector implements ImportCollector {
private final Map<Class<?>, String> typeCache = new HashMap<>();
@ -17,7 +17,7 @@ public class ImportCollector {
private final Class<?> rewriteClass;
public ImportCollector(Class<?> rewriteClass) {
public ImportTypeCollector(Class<?> rewriteClass) {
this.rewriteClass = rewriteClass;
}

View File

@ -1,5 +1,6 @@
package io.papermc.generator.rewriter.types;
import io.papermc.generator.rewriter.ClassNamed;
import java.util.Arrays;
public class EnumCloneRewriter<T extends Enum<T>, A extends Enum<A>> extends EnumRewriter<T, A> { // not really a clone anymore
@ -7,6 +8,10 @@ public class EnumCloneRewriter<T extends Enum<T>, A extends Enum<A>> extends Enu
private final Class<T> basedOn;
public EnumCloneRewriter(final Class<A> rewriteClass, final Class<T> basedOn, final String pattern, boolean equalsSize) {
this(new ClassNamed(rewriteClass), basedOn, pattern, equalsSize);
}
public EnumCloneRewriter(final ClassNamed rewriteClass, final Class<T> basedOn, final String pattern, boolean equalsSize) {
super(rewriteClass, pattern, equalsSize);
this.basedOn = basedOn;
}

View File

@ -4,6 +4,7 @@ import com.google.common.base.Suppliers;
import io.papermc.generator.Main;
import io.papermc.generator.rewriter.SearchMetadata;
import io.papermc.generator.rewriter.utils.Annotations;
import io.papermc.generator.rewriter.ClassNamed;
import io.papermc.generator.utils.Formatting;
import io.papermc.generator.utils.RegistryUtils;
import net.minecraft.core.Holder;
@ -25,6 +26,10 @@ public class EnumRegistryRewriter<T, A extends Enum<A>> extends EnumRewriter<Hol
private final boolean hasParams;
public EnumRegistryRewriter(final Class<A> rewriteClass, final ResourceKey<? extends Registry<T>> registryKey, final String pattern, final boolean hasParams) {
this(new ClassNamed(rewriteClass), registryKey, pattern, hasParams);
}
public EnumRegistryRewriter(final ClassNamed rewriteClass, final ResourceKey<? extends Registry<T>> registryKey, final String pattern, final boolean hasParams) {
super(rewriteClass, pattern, false);
this.registry = Main.REGISTRY_ACCESS.registryOrThrow(registryKey);
this.experimentalKeys = Suppliers.memoize(() -> RegistryUtils.collectExperimentalDataDrivenKeys(this.registry));

View File

@ -2,6 +2,7 @@ package io.papermc.generator.rewriter.types;
import io.papermc.generator.rewriter.SearchMetadata;
import io.papermc.generator.rewriter.SearchReplaceRewriter;
import io.papermc.generator.rewriter.ClassNamed;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Iterator;
@ -15,6 +16,10 @@ public abstract class EnumRewriter<T, A extends Enum<A>> extends SearchReplaceRe
super(rewriteClass, pattern, equalsSize);
}
protected EnumRewriter(final ClassNamed rewriteClass, final String pattern, final boolean equalsSize) {
super(rewriteClass, pattern, equalsSize);
}
protected abstract Iterable<T> getValues();
protected abstract String rewriteEnumName(T item);

View File

@ -1,5 +1,6 @@
package io.papermc.generator.rewriter.types;
import com.google.common.base.Preconditions;
import com.google.common.base.Suppliers;
import io.papermc.generator.Main;
import io.papermc.generator.rewriter.SearchMetadata;
@ -19,7 +20,6 @@ import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
@ -68,8 +68,9 @@ public class RegistryFieldRewriter<T, A> extends SearchReplaceRewriter {
return;
}
Preconditions.checkState(this.rewriteClass.clazz() != null, "This rewriter doesn't support server gen!");
try {
this.rewriteClass.getDeclaredMethod(this.fetchMethod, String.class);
this.rewriteClass.clazz().getDeclaredMethod(this.fetchMethod, String.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
@ -93,10 +94,10 @@ public class RegistryFieldRewriter<T, A> extends SearchReplaceRewriter {
if (!this.isInterface) {
builder.append("%s %s %s ".formatted(PUBLIC, STATIC, FINAL));
}
builder.append(this.rewriteClass.getSimpleName()).append(' ').append(this.rewriteFieldName(reference));
builder.append(this.rewriteClass.simpleName()).append(' ').append(this.rewriteFieldName(reference));
builder.append(" = ");
if (this.fetchMethod == null) {
builder.append("%s.%s.get(%s.minecraft(%s))".formatted(org.bukkit.Registry.class.getSimpleName(), REGISTRY_FIELD_NAMES.get(this.rewriteClass), NamespacedKey.class.getSimpleName(), quoted(pathKey)));
builder.append("%s.%s.get(%s.minecraft(%s))".formatted(org.bukkit.Registry.class.getSimpleName(), REGISTRY_FIELD_NAMES.get(this.rewriteClass.clazz()), NamespacedKey.class.getSimpleName(), quoted(pathKey)));
} else {
builder.append("%s(%s)".formatted(this.fetchMethod, quoted(pathKey)));
}

View File

@ -2,6 +2,7 @@ package io.papermc.generator.rewriter.types;
import io.papermc.generator.rewriter.SearchMetadata;
import io.papermc.generator.rewriter.SearchReplaceRewriter;
import io.papermc.generator.rewriter.ClassNamed;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import java.util.Iterator;
@ -14,6 +15,10 @@ public abstract class SwitchCaseRewriter extends SearchReplaceRewriter {
super(rewriteClass, pattern, equalsSize);
}
protected SwitchCaseRewriter(final ClassNamed rewriteClass, final String pattern, final boolean equalsSize) {
super(rewriteClass, pattern, equalsSize);
}
protected abstract Iterable<String> getCases();
@Override

View File

@ -1,6 +1,7 @@
package io.papermc.generator.rewriter.types;
import com.google.common.collect.Multimap;
import io.papermc.generator.rewriter.ClassNamed;
import io.papermc.generator.rewriter.SearchMetadata;
import io.papermc.generator.rewriter.SearchReplaceRewriter;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@ -15,6 +16,10 @@ public abstract class SwitchRewriter<T> extends SearchReplaceRewriter {
super(rewriteClass, pattern, equalsSize);
}
protected SwitchRewriter(final ClassNamed rewriteClass, final String pattern, final boolean equalsSize) {
super(rewriteClass, pattern, equalsSize);
}
protected record Return<T>(T object, String code) {}
protected Return<T> returnOf(T object, String code) {

View File

@ -4,6 +4,7 @@ import io.papermc.generator.Main;
import io.papermc.generator.rewriter.SearchMetadata;
import io.papermc.generator.rewriter.SearchReplaceRewriter;
import io.papermc.generator.rewriter.utils.Annotations;
import io.papermc.generator.rewriter.ClassNamed;
import io.papermc.generator.utils.Formatting;
import java.util.Collection;
import java.util.Iterator;
@ -39,6 +40,10 @@ public class TagRewriter extends SearchReplaceRewriter {
super(rewriteClass, pattern, false);
}
public TagRewriter(final ClassNamed rewriteClass, final String pattern) {
super(rewriteClass, pattern, false);
}
@Override
protected void insert(final SearchMetadata metadata, final StringBuilder builder) {
for (int i = 0, len = TAG_REGISTRIES.size(); i < len; i++) {
@ -71,7 +76,7 @@ public class TagRewriter extends SearchReplaceRewriter {
}
builder.append(metadata.indent());
builder.append("%s<%s>".formatted(this.rewriteClass.getSimpleName(), tagRegistry.apiType().getSimpleName())).append(' ').append(fieldName);
builder.append("%s<%s>".formatted(this.rewriteClass.simpleName(), tagRegistry.apiType().getSimpleName())).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()));
builder.append(';');

View File

@ -0,0 +1,14 @@
package io.papermc.generator.rewriter.types;
import io.papermc.generator.rewriter.ClassNamed;
public final class Types {
public static final String BASE_PACKAGE = "org.bukkit.craftbukkit";
public static final String BLOCKDATA_IMPL_PACKAGE = BASE_PACKAGE + ".block.impl";
public static final ClassNamed CRAFT_BLOCKDATA = ClassNamed.of(BASE_PACKAGE + ".block.data", "CraftBlockData");
public static final ClassNamed CRAFT_BLOCK = ClassNamed.of(BASE_PACKAGE + ".block", "CraftBlock");
}

View File

@ -0,0 +1,23 @@
package io.papermc.generator.rewriter.types.simple;
import io.papermc.generator.rewriter.SearchMetadata;
import io.papermc.generator.rewriter.SearchReplaceRewriter;
import io.papermc.generator.rewriter.types.Types;
import io.papermc.generator.utils.BlockStateMapping;
import io.papermc.generator.utils.Formatting;
public class CraftBlockDataMapping extends SearchReplaceRewriter {
public CraftBlockDataMapping(final String pattern) {
super(Types.CRAFT_BLOCKDATA, pattern, false);
}
@Override
protected void insert(final SearchMetadata metadata, final StringBuilder builder) {
BlockStateMapping.MAPPING.entrySet().stream().sorted(Formatting.alphabeticKeyOrder(entry -> entry.getKey().getCanonicalName())).forEach(entry -> {
builder.append(metadata.indent());
builder.append("register(%s.class, %s.%s::new);".formatted(entry.getKey().getCanonicalName(), Types.BLOCKDATA_IMPL_PACKAGE, entry.getValue().impl()));
builder.append('\n');
});
}
}

View File

@ -141,9 +141,9 @@ public class MemoryKeyRewriter extends SearchReplaceRewriter {
builder.append(metadata.indent());
builder.append("%s %s %s ".formatted(PUBLIC, STATIC, FINAL));
builder.append("%s<%s>".formatted(this.rewriteClass.getSimpleName(), apiMemoryType.getSimpleName())).append(' ').append(this.rewriteFieldName(reference));
builder.append("%s<%s>".formatted(this.rewriteClass.simpleName(), apiMemoryType.getSimpleName())).append(' ').append(this.rewriteFieldName(reference));
builder.append(" = ");
builder.append("new %s<>(%s.minecraft(%s), %s.class)".formatted(this.rewriteClass.getSimpleName(), NamespacedKey.class.getSimpleName(), quoted(pathKey), apiMemoryType.getSimpleName()));
builder.append("new %s<>(%s.minecraft(%s), %s.class)".formatted(this.rewriteClass.simpleName(), NamespacedKey.class.getSimpleName(), quoted(pathKey), apiMemoryType.getSimpleName()));
builder.append(';');
builder.append('\n');

View File

@ -1,6 +1,7 @@
package io.papermc.generator.rewriter.utils;
import io.papermc.generator.rewriter.SearchMetadata;
import io.papermc.generator.rewriter.context.ImportCollector;
import io.papermc.generator.utils.ClassHelper;
import io.papermc.generator.utils.Formatting;
import net.minecraft.world.flag.FeatureFlag;

View File

@ -1,4 +1,4 @@
package io.papermc.generator.types.craftblockdata;
package io.papermc.generator.types;
import com.squareup.javapoet.ClassName;
@ -9,7 +9,4 @@ public final class Types {
public static final ClassName CRAFT_BLOCKDATA = ClassName.get(BASE_PACKAGE + ".block.data", "CraftBlockData");
public static final ClassName CRAFT_BLOCK = ClassName.get(BASE_PACKAGE + ".block", "CraftBlock");
public static final String INDEX_VARIABLE = "index";
public static final String ENTRY_VARIABLE = "entry";
}

View File

@ -8,6 +8,7 @@ import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import io.papermc.generator.types.Types;
import io.papermc.generator.types.StructuredGenerator;
import io.papermc.generator.types.craftblockdata.property.holder.DataPropertyMaker;
import io.papermc.generator.types.craftblockdata.property.PropertyMaker;
@ -17,6 +18,7 @@ import io.papermc.generator.types.craftblockdata.property.holder.converter.DataC
import io.papermc.generator.types.craftblockdata.property.holder.converter.DataConverters;
import io.papermc.generator.utils.Annotations;
import io.papermc.generator.utils.BlockStateMapping;
import io.papermc.generator.utils.CommonVariable;
import io.papermc.generator.utils.NamingManager;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.BrewingStandBlock;
@ -182,7 +184,7 @@ public class CraftBlockDataGenerator<T extends BlockData> extends StructuredGene
NamingManager.AccessKeyword accessKeyword = FLUENT_KEYWORD.getOrDefault(firstProperty, dataPropertyMaker.getKeyword());
NamingManager naming = new NamingManager(accessKeyword, CaseFormat.UPPER_UNDERSCORE, NamingManager.stripFieldAccessKeyword(dataPropertyMaker.getBaseName()));
ParameterSpec indexParameter = ParameterSpec.builder(dataPropertyMaker.getIndexClass(), dataPropertyMaker.getIndexClass() == Integer.TYPE ? Types.INDEX_VARIABLE : naming.paramName(dataPropertyMaker.getIndexClass()), FINAL).build();
ParameterSpec indexParameter = ParameterSpec.builder(dataPropertyMaker.getIndexClass(), dataPropertyMaker.getIndexClass() == Integer.TYPE ? CommonVariable.INDEX : naming.paramName(dataPropertyMaker.getIndexClass()), FINAL).build();
// get
{

View File

@ -11,7 +11,7 @@ import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import io.papermc.generator.types.StructuredGenerator;
import io.papermc.generator.types.craftblockdata.Types;
import io.papermc.generator.types.Types;
import io.papermc.generator.types.craftblockdata.property.holder.appender.ArrayAppender;
import io.papermc.generator.types.craftblockdata.property.holder.appender.DataAppender;
import io.papermc.generator.types.craftblockdata.property.holder.appender.ListAppender;
@ -19,6 +19,7 @@ import io.papermc.generator.types.craftblockdata.property.holder.appender.MapApp
import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase;
import io.papermc.generator.utils.BlockStateMapping;
import io.papermc.generator.utils.ClassHelper;
import io.papermc.generator.utils.CommonVariable;
import io.papermc.generator.utils.NamingManager;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.state.properties.Property;
@ -80,8 +81,8 @@ public class DataPropertyWriter<T extends Property<?>> extends DataPropertyWrite
if (this.type == DataHolderType.MAP && ClassHelper.eraseType(((ParameterizedType) this.field.getGenericType()).getActualTypeArguments()[0]) == Direction.class &&
this.indexClass == BlockFace.class) { // Direction -> BlockFace
// convert the key manually only this one is needed for now
fieldBuilder.initializer("$[$T.$L.entrySet().stream()\n.collect($T.toMap(entry -> $T.notchToBlockFace(entry.getKey()), entry -> entry.getValue()))$]",
this.blockClass, this.field.getName(), Collectors.class, Types.CRAFT_BLOCK);
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);
} else {
fieldBuilder.initializer("$T.$L", this.blockClass, this.field.getName());
}

View File

@ -7,9 +7,9 @@ import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;
import io.papermc.generator.types.StructuredGenerator;
import io.papermc.generator.types.craftblockdata.Types;
import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase;
import io.papermc.generator.types.craftblockdata.property.holder.DataHolderType;
import io.papermc.generator.utils.CommonVariable;
import io.papermc.generator.utils.NamingManager;
import java.util.Set;
@ -26,11 +26,11 @@ public class ArrayAppender implements DataAppender {
String collectFieldName = naming.getVariableNameWrapper().post("s").concat();
MethodSpec.Builder methodBuilder = generator.createMethod(naming.getMethodNameWrapper().post("s").concat());
methodBuilder.addStatement("$T $L = $T.builder()", ParameterizedTypeName.get(ImmutableSet.Builder.class, Integer.class), collectFieldName, ImmutableSet.class);
methodBuilder.beginControlFlow("for (int $1L = 0, len = $2N.length; $1L < len; $1L++)", Types.INDEX_VARIABLE, field);
methodBuilder.beginControlFlow("for (int $1L = 0, len = $2N.length; $1L < len; $1L++)", CommonVariable.INDEX, field);
{
methodBuilder.beginControlFlow("if (" + childConverter.rawGetExprent().formatted("$N[$N]") + ")", field, indexParameter);
{
methodBuilder.addStatement("$L.add($L)", collectFieldName, Types.INDEX_VARIABLE);
methodBuilder.addStatement("$L.add($L)", collectFieldName, CommonVariable.INDEX);
}
methodBuilder.endControlFlow();
}

View File

@ -7,9 +7,9 @@ import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;
import io.papermc.generator.types.StructuredGenerator;
import io.papermc.generator.types.craftblockdata.Types;
import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase;
import io.papermc.generator.types.craftblockdata.property.holder.DataHolderType;
import io.papermc.generator.utils.CommonVariable;
import io.papermc.generator.utils.NamingManager;
import java.util.Map;
import java.util.Set;
@ -33,11 +33,11 @@ public class ListAppender implements DataAppender {
String collectFieldName = naming.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), collectFieldName, ImmutableSet.class);
methodBuilder.beginControlFlow("for (int $1L = 0, size = $2N.size(); $1L < size; $1L++)", Types.INDEX_VARIABLE, field);
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.addStatement("$L.add($L)", collectFieldName, Types.INDEX_VARIABLE);
methodBuilder.addStatement("$L.add($L)", collectFieldName, CommonVariable.INDEX);
}
methodBuilder.endControlFlow();
}

View File

@ -8,9 +8,9 @@ import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;
import io.papermc.generator.types.StructuredGenerator;
import io.papermc.generator.types.craftblockdata.Types;
import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase;
import io.papermc.generator.types.craftblockdata.property.holder.DataHolderType;
import io.papermc.generator.utils.CommonVariable;
import io.papermc.generator.utils.NamingManager;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import java.util.Collections;
@ -30,11 +30,11 @@ public class MapAppender implements DataAppender {
String collectFieldName = naming.getVariableNameWrapper().post("s").concat();
MethodSpec.Builder methodBuilder = generator.createMethod(naming.getMethodNameWrapper().post("s").concat());
methodBuilder.addStatement("$T $L = $T.builder()", ParameterizedTypeName.get(ClassName.get(ImmutableSet.Builder.class), indexParameter.type), collectFieldName, ImmutableSet.class);
methodBuilder.beginControlFlow("for ($T $N : $N.entrySet())", ParameterizedTypeName.get(ClassName.get(Map.Entry.class), indexParameter.type, ClassName.get(BooleanProperty.class)), Types.ENTRY_VARIABLE, field);
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("if (" + childConverter.rawGetExprent().formatted("$L.getValue()") + ")", Types.ENTRY_VARIABLE);
methodBuilder.beginControlFlow("if (" + childConverter.rawGetExprent().formatted("$L.getValue()") + ")", CommonVariable.MAP_ENTRY);
{
methodBuilder.addStatement("$L.add($N.getKey())", collectFieldName, Types.ENTRY_VARIABLE);
methodBuilder.addStatement("$L.add($N.getKey())", collectFieldName, CommonVariable.MAP_ENTRY);
}
methodBuilder.endControlFlow();
}

View File

@ -0,0 +1,8 @@
package io.papermc.generator.utils;
public final class CommonVariable {
public static final String INDEX = "index";
public static final String MAP_ENTRY = "entry";
}

View File

@ -1,6 +1,7 @@
package io.papermc.generator.utils;
import com.google.common.collect.HashBiMap;
import io.papermc.generator.rewriter.ClassNamed;
import java.util.Comparator;
import java.util.Locale;
import java.util.Map;
@ -71,14 +72,29 @@ public final class Formatting {
return Optional.of(resourcePath.substring(tagsIndex + tagDir.length() + 1, dotIndex)); // namespace/tags/registry_key/[tag_key].json
}
public static String incrementalIndent(String unit, Class<?> clazz) {
Class<?> parent = clazz.getEnclosingClass();
public static int countOccurrences(String value, char match) {
int count = 0;
for (int i = 0, len = value.length(); i < len; i++) {
if (value.charAt(i) == match) {
count++;
}
}
return count;
}
public static String incrementalIndent(String unit, ClassNamed classNamed) {
if (classNamed.clazz() == null) {
return unit.repeat(countOccurrences(classNamed.dottedNestedName(), '.'));
}
Class<?> parent = classNamed.clazz().getEnclosingClass();
StringBuilder indentBuilder = new StringBuilder(unit);
while (parent != null) {
indentBuilder.append(unit);
parent = parent.getEnclosingClass();
}
return indentBuilder.toString();
}
public static String quoted(String value) {

View File

@ -2,7 +2,6 @@ package io.papermc.generator.rewriter;
import io.papermc.generator.Generators;
import io.papermc.generator.rewriter.utils.Annotations;
import io.papermc.generator.utils.ClassHelper;
import io.papermc.paper.generated.GeneratedFrom;
import net.minecraft.SharedConstants;
import org.junit.jupiter.api.Assertions;
@ -16,7 +15,8 @@ import java.nio.file.Path;
public class OldGeneratedCodeTest {
private static final String CONTAINER = System.getProperty("paper.generator.rewriter.container");
private static final String API_CONTAINER = System.getProperty("paper.generator.rewriter.container.api");
private static final String SERVER_CONTAINER = System.getProperty("paper.generator.rewriter.container.server");
private static String CURRENT_VERSION;
@ -26,33 +26,32 @@ public class OldGeneratedCodeTest {
CURRENT_VERSION = SharedConstants.getCurrentVersion().getName();
}
private boolean versionDependant(SearchReplaceRewriter srt) {
private boolean versionDependent(SearchReplaceRewriter srt) {
if (srt instanceof CompositeRewriter compositeRewriter) {
boolean versionDependant = false;
boolean versionDependent = false;
for (SearchReplaceRewriter rewriter : compositeRewriter.getRewriters()) {
if (!rewriter.equalsSize) {
versionDependant = true;
versionDependent = true;
break;
}
}
return versionDependant;
return versionDependent;
}
return !srt.equalsSize;
}
@Test
public void testOutdatedCode() throws IOException {
for (SourceRewriter rewriter : Generators.API_REWRITE) {
if (!(rewriter instanceof SearchReplaceRewriter srt) || !versionDependant(srt)) {
private void checkOutdated(String container, SourceRewriter[] rewriters) throws IOException {
for (SourceRewriter rewriter : rewriters) {
if (!(rewriter instanceof SearchReplaceRewriter srt) || !versionDependent(srt)) {
continue;
}
String filePath = "%s/%s.java".formatted(
srt.rewriteClass.getPackageName().replace('.', '/'),
ClassHelper.getRootClass(srt.rewriteClass).getSimpleName()
srt.rewriteClass.packageName().replace('.', '/'),
srt.rewriteClass.rootClassSimpleName()
);
Path path = Path.of(CONTAINER, filePath);
Path path = Path.of(container, filePath);
if (!Files.exists(path)) {
continue;
}
@ -78,7 +77,7 @@ public class OldGeneratedCodeTest {
String generatedVersion = nextLine.substring(generatedIndex + generatedComment.length());
Assertions.assertEquals(CURRENT_VERSION, generatedVersion,
"Code at line %s in %s is marked as being generated in version %s when the current version is %s".formatted(
lineCount, srt.rewriteClass.getCanonicalName(),
lineCount, srt.rewriteClass.canonicalName(),
generatedVersion, CURRENT_VERSION));
}
}
@ -86,4 +85,10 @@ public class OldGeneratedCodeTest {
}
}
}
@Test
public void testOutdatedCode() throws IOException {
checkOutdated(API_CONTAINER, Generators.API_REWRITE);
checkOutdated(SERVER_CONTAINER, Generators.SERVER_REWRITE);
}
}

View File

@ -0,0 +1,26 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com>
Date: Sat, 16 Mar 2024 18:58:41 +0100
Subject: [PATCH] Code generation marker stub
diff --git a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java
index 80584646464b58406150f7146d68969a3353aaa8..ab4416b054612b831cd938b03ffcbfc3bc082ca2 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java
@@ -366,6 +366,7 @@ public class CraftBlockData implements BlockData {
static {
//<editor-fold desc="CraftBlockData Registration" defaultstate="collapsed">
+ // Paper start - Generated/CraftBlockData#MAP
register(net.minecraft.world.level.block.AmethystClusterBlock.class, org.bukkit.craftbukkit.block.impl.CraftAmethystCluster::new);
register(net.minecraft.world.level.block.BigDripleafBlock.class, org.bukkit.craftbukkit.block.impl.CraftBigDripleaf::new);
register(net.minecraft.world.level.block.BigDripleafStemBlock.class, org.bukkit.craftbukkit.block.impl.CraftBigDripleafStem::new);
@@ -537,6 +538,7 @@ public class CraftBlockData implements BlockData {
register(net.minecraft.world.level.block.piston.PistonBaseBlock.class, org.bukkit.craftbukkit.block.impl.CraftPistonBase::new);
register(net.minecraft.world.level.block.piston.PistonHeadBlock.class, org.bukkit.craftbukkit.block.impl.CraftPistonHead::new);
register(net.minecraft.world.level.block.piston.MovingPistonBlock.class, org.bukkit.craftbukkit.block.impl.CraftMovingPiston::new);
+ // Paper end - Generated/CraftBlockData#MAP
//</editor-fold>
}