Skip to content

BlockProperty API #11963

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.papermc.paper;

import io.papermc.paper.block.property.EnumBlockProperty;
import net.kyori.adventure.util.Services;
import org.bukkit.damage.DamageEffect;
import org.jetbrains.annotations.ApiStatus;
Expand Down Expand Up @@ -35,5 +36,15 @@ class Holder {
* @return the damage effect.
*/
DamageEffect getDamageEffect(String key);

/**
* Gets the string representation for this bukkit enum.
*
* @param enumProperty the enum data property
* @param bukkitEnum the enum to get the string representation of
* @param <B> the bukkit enum type
* @return the string representation of the supplied enum
*/
<B extends Enum<B>> String getPropertyEnumName(EnumBlockProperty<B> enumProperty, B bukkitEnum);
}

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.papermc.paper.block.fluid;

import io.papermc.paper.block.property.BlockPropertyHolder;
import org.bukkit.Fluid;
import org.bukkit.Location;
import org.bukkit.util.Vector;
Expand All @@ -11,7 +12,7 @@
* This type is not linked to a specific location and hence mostly resembles a {@link org.bukkit.block.data.BlockData}.
*/
@NullMarked
public interface FluidData extends Cloneable {
public interface FluidData extends Cloneable, BlockPropertyHolder {

/**
* Gets the fluid type of this fluid data.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.papermc.paper.block.property;

import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import java.util.function.IntFunction;
import org.jetbrains.annotations.ApiStatus;

@ApiStatus.Internal
sealed interface AsIntegerProperty<T extends Comparable<T>> extends BlockProperty<T> permits NoteBlockProperty, RotationBlockProperty {

static <T extends Comparable<T>> BiMap<Integer, T> createCache(final int max, final IntFunction<? extends T> function) {
final ImmutableBiMap.Builder<Integer, T> builder = ImmutableBiMap.builder();
for (int i = 0; i <= max; i++) {
builder.put(i, function.apply(i));
}
return builder.buildOrThrow();
}

BiMap<Integer, T> cache();

default int toIntValue(final T value) {
if (!this.cache().inverse().containsKey(value)) {
throw ExceptionCreator.INSTANCE.create(value, ExceptionCreator.Type.VALUE, this);
}
return this.cache().inverse().get(value);
}

default T fromIntValue(final int value) {
if (!this.cache().containsKey(value)) {
throw ExceptionCreator.INSTANCE.create(value, ExceptionCreator.Type.VALUE, this);
}
return this.cache().get(value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
package io.papermc.paper.block.property;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import java.util.Arrays;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.bukkit.Axis;
import org.bukkit.Instrument;
import org.bukkit.Note;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.FaceAttachable;
import org.bukkit.block.data.Rail;
import org.bukkit.block.data.type.Bamboo;
import org.bukkit.block.data.type.Bed;
import org.bukkit.block.data.type.Bell;
import org.bukkit.block.data.type.BigDripleaf;
import org.bukkit.block.data.type.Chest;
import org.bukkit.block.data.type.Comparator;
import org.bukkit.block.data.type.CreakingHeart;
import org.bukkit.block.data.type.Door;
import org.bukkit.block.data.type.Jigsaw;
import org.bukkit.block.data.type.PointedDripstone;
import org.bukkit.block.data.type.RedstoneWire;
import org.bukkit.block.data.type.SculkSensor;
import org.bukkit.block.data.type.Slab;
import org.bukkit.block.data.type.Stairs;
import org.bukkit.block.data.type.StructureBlock;
import org.bukkit.block.data.type.TechnicalPiston;
import org.bukkit.block.data.type.TrialSpawner;
import org.bukkit.block.data.type.Vault;
import org.bukkit.block.data.type.Wall;

/**
* All block properties applicable to {@link BlockPropertyHolder}s.
*/
public final class BlockProperties {

static final Multimap<String, BlockProperty<?>> PROPERTIES = HashMultimap.create();

public static final BooleanBlockProperty ATTACHED = bool("attached");
public static final BooleanBlockProperty BOTTOM = bool("bottom");
public static final BooleanBlockProperty CONDITIONAL = bool("conditional");
public static final BooleanBlockProperty CRACKED = bool("cracked");
public static final BooleanBlockProperty DISARMED = bool("disarmed");
public static final BooleanBlockProperty DRAG = bool("drag");
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_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 HAS_BOOK = bool("has_book");
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 OCCUPIED = bool("occupied");
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 SIGNAL_FIRE = bool("signal_fire");
public static final BooleanBlockProperty SNOWY = bool("snowy");
public static final BooleanBlockProperty TRIGGERED = bool("triggered");
public static final BooleanBlockProperty UNSTABLE = bool("unstable");
public static final BooleanBlockProperty WATERLOGGED = bool("waterlogged");
public static final BooleanBlockProperty BERRIES = bool("berries");
public static final BooleanBlockProperty BLOOM = bool("bloom");
public static final BooleanBlockProperty SHRIEKING = bool("shrieking");
public static final BooleanBlockProperty CAN_SUMMON = bool("can_summon");
public static final BooleanBlockProperty UP = bool("up");
public static final BooleanBlockProperty DOWN = bool("down");
public static final BooleanBlockProperty NORTH = bool("north");
public static final BooleanBlockProperty EAST = bool("east");
public static final BooleanBlockProperty SOUTH = bool("south");
public static final BooleanBlockProperty WEST = bool("west");
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 CRAFTING = bool("crafting");
public static final BooleanBlockProperty OMINOUS = bool("ominous");
public static final BooleanBlockProperty TIP = bool("tip");
public static final BooleanBlockProperty ACTIVE = bool("active");
public static final BooleanBlockProperty NATURAL = bool("natural");

public static final IntegerBlockProperty AGE_1 = integer("age", 0, 1);
public static final IntegerBlockProperty AGE_2 = integer("age", 0, 2);
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 AGE_15 = integer("age", 0, 15);
public static final IntegerBlockProperty AGE_25 = integer("age", 0, 25);
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 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_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 LEVEL = integer("level", 0, 15);
public static final IntegerBlockProperty MOISTURE = integer("moisture", 0, 7);
public static final BlockProperty<Note> NOTE = register(new NoteBlockProperty("note")); // is stored as int, but represented as object
public static final IntegerBlockProperty PICKLES = integer("pickles", 1, 4);
public static final IntegerBlockProperty POWER = integer("power", 0, 15);
public static final IntegerBlockProperty STAGE = integer("stage", 0, 1);
public static final IntegerBlockProperty STABILITY_DISTANCE = integer("distance", 0, 7);
public static final IntegerBlockProperty RESPAWN_ANCHOR_CHARGES = integer("charges", 0, 4);

public static final EnumBlockProperty<BlockFace> ROTATION_16 = register(new RotationBlockProperty("rotation")); // is stored as int, but represented as enum
public static final EnumBlockProperty<Axis> HORIZONTAL_AXIS = enumeration("axis", Axis.class, Axis.X, Axis.Z);
public static final EnumBlockProperty<Axis> AXIS = enumeration("axis", Axis.class);
public static final EnumBlockProperty<BlockFace> FACING = enumeration("facing", BlockFace.class, BlockFace::isCartesian);
public static final EnumBlockProperty<BlockFace> FACING_HOPPER = enumeration("facing", BlockFace.class, ((Predicate<BlockFace>) BlockFace::isCartesian).and(face -> face != BlockFace.UP));
public static final EnumBlockProperty<BlockFace> HORIZONTAL_FACING = enumeration("facing", BlockFace.class, BlockFace::isCardinal);
public static final EnumBlockProperty<Jigsaw.Orientation> ORIENTATION = enumeration("orientation", Jigsaw.Orientation.class);
public static final EnumBlockProperty<FaceAttachable.AttachedFace> ATTACH_FACE = enumeration("face", FaceAttachable.AttachedFace.class);
public static final EnumBlockProperty<Bell.Attachment> BELL_ATTACHMENT = enumeration("attachment", Bell.Attachment.class);
public static final EnumBlockProperty<Wall.Height> EAST_WALL = enumeration("east", Wall.Height.class);
public static final EnumBlockProperty<Wall.Height> NORTH_WALL = enumeration("north", Wall.Height.class);
public static final EnumBlockProperty<Wall.Height> SOUTH_WALL = enumeration("south", Wall.Height.class);
public static final EnumBlockProperty<Wall.Height> WEST_WALL = enumeration("west", Wall.Height.class);
public static final EnumBlockProperty<RedstoneWire.Connection> EAST_REDSTONE = enumeration("east", RedstoneWire.Connection.class);
public static final EnumBlockProperty<RedstoneWire.Connection> NORTH_REDSTONE = enumeration("north", RedstoneWire.Connection.class);
public static final EnumBlockProperty<RedstoneWire.Connection> SOUTH_REDSTONE = enumeration("south", RedstoneWire.Connection.class);
public static final EnumBlockProperty<RedstoneWire.Connection> WEST_REDSTONE = enumeration("west", RedstoneWire.Connection.class);
public static final EnumBlockProperty<Bisected.Half> DOUBLE_BLOCK_HALF = enumeration("half", Bisected.Half.class);
public static final EnumBlockProperty<Bisected.Half> HALF = enumeration("half", Bisected.Half.class);
public static final EnumBlockProperty<Rail.Shape> RAIL_SHAPE = enumeration("shape", Rail.Shape.class);
public static final EnumBlockProperty<Rail.Shape> RAIL_SHAPE_STRAIGHT = enumeration("shape", Rail.Shape.class, Rail.Shape::isStraight);
public static final EnumBlockProperty<Bed.Part> BED_PART = enumeration("part", Bed.Part.class);
public static final EnumBlockProperty<Chest.Type> CHEST_TYPE = enumeration("type", Chest.Type.class);
public static final EnumBlockProperty<Comparator.Mode> MODE_COMPARATOR = enumeration("mode", Comparator.Mode.class);
public static final EnumBlockProperty<Door.Hinge> DOOR_HINGE = enumeration("hinge", Door.Hinge.class);
public static final EnumBlockProperty<Instrument> NOTEBLOCK_INSTRUMENT = enumeration("instrument", Instrument.class);
public static final EnumBlockProperty<TechnicalPiston.Type> PISTON_TYPE = enumeration("type", TechnicalPiston.Type.class);
public static final EnumBlockProperty<Slab.Type> SLAB_TYPE = enumeration("type", Slab.Type.class);
public static final EnumBlockProperty<Stairs.Shape> STAIRS_SHAPE = enumeration("shape", Stairs.Shape.class);
public static final EnumBlockProperty<StructureBlock.Mode> STRUCTUREBLOCK_MODE = enumeration("mode", StructureBlock.Mode.class);
public static final EnumBlockProperty<Bamboo.Leaves> BAMBOO_LEAVES = enumeration("leaves", Bamboo.Leaves.class);
public static final EnumBlockProperty<BigDripleaf.Tilt> TILT = enumeration("tilt", BigDripleaf.Tilt.class);
public static final EnumBlockProperty<BlockFace> VERTICAL_DIRECTION = enumeration("vertical_direction", BlockFace.class, face -> Math.abs(face.getModY()) > 0);
public static final EnumBlockProperty<PointedDripstone.Thickness> DRIPSTONE_THICKNESS = enumeration("thickness", PointedDripstone.Thickness.class);
public static final EnumBlockProperty<SculkSensor.Phase> SCULK_SENSOR_PHASE = enumeration("sculk_sensor_phase", SculkSensor.Phase.class);
public static final EnumBlockProperty<TrialSpawner.State> TRIAL_SPAWNER_STATE = enumeration("trial_spawner_state", TrialSpawner.State.class);
public static final EnumBlockProperty<Vault.State> VAULT_STATE = enumeration("vault_state", Vault.State.class);

private BlockProperties() {
}

//<editor-fold defaultstate="collapsed" desc="static factory methods">
private static IntegerBlockProperty integer(final String name, final int min, final int max) {
return register(new IntegerBlockPropertyImpl(name, min, max));
}

private static BooleanBlockProperty bool(final String name) {
return register(new BooleanBlockPropertyImpl(name));
}

private static <E extends Enum<E>> EnumBlockProperty<E> enumeration(final String name, final Class<E> enumClass) {
return register(new EnumBlockPropertyImpl<>(name, enumClass, Set.of(enumClass.getEnumConstants())));
}

@SuppressWarnings("SameParameterValue")
@SafeVarargs
private static <E extends Enum<E>> EnumBlockProperty<E> enumeration(final String name, final Class<E> enumClass, final E... values) {
return register(new EnumBlockPropertyImpl<>(name, enumClass, Set.of(values)));
}

private static <E extends Enum<E>> EnumBlockProperty<E> enumeration(final String name, final Class<E> enumClass, final Predicate<E> test) {
return register(new EnumBlockPropertyImpl<>(name, enumClass, Arrays.stream(enumClass.getEnumConstants()).filter(test).collect(Collectors.toSet())));
}

private static <V extends Comparable<V>, P extends BlockProperty<V>> P register(final P property) {
PROPERTIES.put(property.name(), property);
return property;
}
//</editor-fold>
}
Loading