2025-11-24 22:52:51 +03:00

588 lines
26 KiB
Java

/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* com.google.common.cache.CacheBuilder
* com.google.common.cache.CacheLoader
* com.google.common.cache.LoadingCache
* com.google.common.collect.ImmutableMap
* com.mojang.logging.LogUtils
* com.mojang.serialization.MapCodec
* it.unimi.dsi.fastutil.objects.Object2ByteLinkedOpenHashMap
* it.unimi.dsi.fastutil.objects.ObjectArrayList
* org.jspecify.annotations.Nullable
* org.slf4j.Logger
*/
package net.minecraft.world.level.block;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.mojang.logging.LogUtils;
import com.mojang.serialization.MapCodec;
import it.unimi.dsi.fastutil.objects.Object2ByteLinkedOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import net.minecraft.SharedConstants;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Holder;
import net.minecraft.core.IdMapper;
import net.minecraft.core.Vec3i;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.stats.Stats;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.util.valueproviders.IntProvider;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.ExperienceOrb;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.monster.piglin.PiglinAi;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.LeavesBlock;
import net.minecraft.world.level.block.SupportType;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.StateHolder;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.gamerules.GameRules;
import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.level.storage.loot.LootTable;
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.BooleanOp;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
public class Block
extends BlockBehaviour
implements ItemLike {
public static final MapCodec<Block> CODEC = Block.simpleCodec(Block::new);
private static final Logger LOGGER = LogUtils.getLogger();
private final Holder.Reference<Block> builtInRegistryHolder = BuiltInRegistries.BLOCK.createIntrusiveHolder(this);
public static final IdMapper<BlockState> BLOCK_STATE_REGISTRY = new IdMapper();
private static final LoadingCache<VoxelShape, Boolean> SHAPE_FULL_BLOCK_CACHE = CacheBuilder.newBuilder().maximumSize(512L).weakKeys().build((CacheLoader)new CacheLoader<VoxelShape, Boolean>(){
public Boolean load(VoxelShape shape) {
return !Shapes.joinIsNotEmpty(Shapes.block(), shape, BooleanOp.NOT_SAME);
}
});
public static final int UPDATE_NEIGHBORS = 1;
public static final int UPDATE_CLIENTS = 2;
public static final int UPDATE_INVISIBLE = 4;
public static final int UPDATE_IMMEDIATE = 8;
public static final int UPDATE_KNOWN_SHAPE = 16;
public static final int UPDATE_SUPPRESS_DROPS = 32;
public static final int UPDATE_MOVE_BY_PISTON = 64;
public static final int UPDATE_SKIP_SHAPE_UPDATE_ON_WIRE = 128;
public static final int UPDATE_SKIP_BLOCK_ENTITY_SIDEEFFECTS = 256;
public static final int UPDATE_SKIP_ON_PLACE = 512;
@UpdateFlags
public static final int UPDATE_NONE = 260;
@UpdateFlags
public static final int UPDATE_ALL = 3;
@UpdateFlags
public static final int UPDATE_ALL_IMMEDIATE = 11;
@UpdateFlags
public static final int UPDATE_SKIP_ALL_SIDEEFFECTS = 816;
public static final float INDESTRUCTIBLE = -1.0f;
public static final float INSTANT = 0.0f;
public static final int UPDATE_LIMIT = 512;
protected final StateDefinition<Block, BlockState> stateDefinition;
private BlockState defaultBlockState;
private @Nullable Item item;
private static final int CACHE_SIZE = 256;
private static final ThreadLocal<Object2ByteLinkedOpenHashMap<ShapePairKey>> OCCLUSION_CACHE = ThreadLocal.withInitial(() -> {
Object2ByteLinkedOpenHashMap<ShapePairKey> map = new Object2ByteLinkedOpenHashMap<ShapePairKey>(256, 0.25f){
protected void rehash(int newN) {
}
};
map.defaultReturnValue((byte)127);
return map;
});
@Override
protected MapCodec<? extends Block> codec() {
return CODEC;
}
public static int getId(@Nullable BlockState blockState) {
if (blockState == null) {
return 0;
}
int id = BLOCK_STATE_REGISTRY.getId(blockState);
return id == -1 ? 0 : id;
}
public static BlockState stateById(int idWithData) {
BlockState state = BLOCK_STATE_REGISTRY.byId(idWithData);
return state == null ? Blocks.AIR.defaultBlockState() : state;
}
public static Block byItem(@Nullable Item item) {
if (item instanceof BlockItem) {
return ((BlockItem)item).getBlock();
}
return Blocks.AIR;
}
public static BlockState pushEntitiesUp(BlockState state, BlockState newState, LevelAccessor level, BlockPos pos) {
VoxelShape offsetShape = Shapes.joinUnoptimized(state.getCollisionShape(level, pos), newState.getCollisionShape(level, pos), BooleanOp.ONLY_SECOND).move(pos);
if (offsetShape.isEmpty()) {
return newState;
}
List<Entity> collidingEntities = level.getEntities(null, offsetShape.bounds());
for (Entity collidingEntity : collidingEntities) {
double offset = Shapes.collide(Direction.Axis.Y, collidingEntity.getBoundingBox().move(0.0, 1.0, 0.0), List.of(offsetShape), -1.0);
collidingEntity.teleportRelative(0.0, 1.0 + offset, 0.0);
}
return newState;
}
public static VoxelShape box(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
return Shapes.box(minX / 16.0, minY / 16.0, minZ / 16.0, maxX / 16.0, maxY / 16.0, maxZ / 16.0);
}
public static VoxelShape[] boxes(int endInclusive, IntFunction<VoxelShape> voxelShapeFactory) {
return (VoxelShape[])IntStream.rangeClosed(0, endInclusive).mapToObj(voxelShapeFactory).toArray(VoxelShape[]::new);
}
public static VoxelShape cube(double size) {
return Block.cube(size, size, size);
}
public static VoxelShape cube(double sizeX, double sizeY, double sizeZ) {
double halfY = sizeY / 2.0;
return Block.column(sizeX, sizeZ, 8.0 - halfY, 8.0 + halfY);
}
public static VoxelShape column(double sizeXZ, double minY, double maxY) {
return Block.column(sizeXZ, sizeXZ, minY, maxY);
}
public static VoxelShape column(double sizeX, double sizeZ, double minY, double maxY) {
double halfX = sizeX / 2.0;
double halfZ = sizeZ / 2.0;
return Block.box(8.0 - halfX, minY, 8.0 - halfZ, 8.0 + halfX, maxY, 8.0 + halfZ);
}
public static VoxelShape boxZ(double sizeXY, double minZ, double maxZ) {
return Block.boxZ(sizeXY, sizeXY, minZ, maxZ);
}
public static VoxelShape boxZ(double sizeX, double sizeY, double minZ, double maxZ) {
double halfY = sizeY / 2.0;
return Block.boxZ(sizeX, 8.0 - halfY, 8.0 + halfY, minZ, maxZ);
}
public static VoxelShape boxZ(double sizeX, double minY, double maxY, double minZ, double maxZ) {
double halfX = sizeX / 2.0;
return Block.box(8.0 - halfX, minY, minZ, 8.0 + halfX, maxY, maxZ);
}
public static BlockState updateFromNeighbourShapes(BlockState state, LevelAccessor level, BlockPos pos) {
BlockState newState = state;
BlockPos.MutableBlockPos neighbourPos = new BlockPos.MutableBlockPos();
for (Direction direction : UPDATE_SHAPE_ORDER) {
neighbourPos.setWithOffset((Vec3i)pos, direction);
newState = newState.updateShape(level, level, pos, direction, neighbourPos, level.getBlockState(neighbourPos), level.getRandom());
}
return newState;
}
public static void updateOrDestroy(BlockState blockState, BlockState newState, LevelAccessor level, BlockPos blockPos, @UpdateFlags int updateFlags) {
Block.updateOrDestroy(blockState, newState, level, blockPos, updateFlags, 512);
}
public static void updateOrDestroy(BlockState blockState, BlockState newState, LevelAccessor level, BlockPos blockPos, @UpdateFlags int updateFlags, int updateLimit) {
if (newState != blockState) {
if (newState.isAir()) {
if (!level.isClientSide()) {
level.destroyBlock(blockPos, (updateFlags & 0x20) == 0, null, updateLimit);
}
} else {
level.setBlock(blockPos, newState, updateFlags & 0xFFFFFFDF, updateLimit);
}
}
}
public Block(BlockBehaviour.Properties properties) {
super(properties);
String className;
StateDefinition.Builder<Block, BlockState> builder = new StateDefinition.Builder<Block, BlockState>(this);
this.createBlockStateDefinition(builder);
this.stateDefinition = builder.create(Block::defaultBlockState, BlockState::new);
this.registerDefaultState(this.stateDefinition.any());
if (SharedConstants.IS_RUNNING_IN_IDE && !(className = this.getClass().getSimpleName()).endsWith("Block")) {
LOGGER.error("Block classes should end with Block and {} doesn't.", (Object)className);
}
}
public static boolean isExceptionForConnection(BlockState state) {
return state.getBlock() instanceof LeavesBlock || state.is(Blocks.BARRIER) || state.is(Blocks.CARVED_PUMPKIN) || state.is(Blocks.JACK_O_LANTERN) || state.is(Blocks.MELON) || state.is(Blocks.PUMPKIN) || state.is(BlockTags.SHULKER_BOXES);
}
protected static boolean dropFromBlockInteractLootTable(ServerLevel level, ResourceKey<LootTable> key, BlockState interactedBlockState, @Nullable BlockEntity interactedBlockEntity, @Nullable ItemStack tool, @Nullable Entity interactingEntity, BiConsumer<ServerLevel, ItemStack> consumer) {
return Block.dropFromLootTable(level, key, params -> params.withParameter(LootContextParams.BLOCK_STATE, interactedBlockState).withOptionalParameter(LootContextParams.BLOCK_ENTITY, interactedBlockEntity).withOptionalParameter(LootContextParams.INTERACTING_ENTITY, interactingEntity).withOptionalParameter(LootContextParams.TOOL, tool).create(LootContextParamSets.BLOCK_INTERACT), consumer);
}
protected static boolean dropFromLootTable(ServerLevel level, ResourceKey<LootTable> key, Function<LootParams.Builder, LootParams> paramsBuilder, BiConsumer<ServerLevel, ItemStack> consumer) {
LootParams params;
LootTable lootTable = level.getServer().reloadableRegistries().getLootTable(key);
ObjectArrayList<ItemStack> drops = lootTable.getRandomItems(params = paramsBuilder.apply(new LootParams.Builder(level)));
if (!drops.isEmpty()) {
drops.forEach(stack -> consumer.accept(level, (ItemStack)stack));
return true;
}
return false;
}
public static boolean shouldRenderFace(BlockState state, BlockState neighborState, Direction direction) {
VoxelShape occluder = neighborState.getFaceOcclusionShape(direction.getOpposite());
if (occluder == Shapes.block()) {
return false;
}
if (state.skipRendering(neighborState, direction)) {
return false;
}
if (occluder == Shapes.empty()) {
return true;
}
VoxelShape shape = state.getFaceOcclusionShape(direction);
if (shape == Shapes.empty()) {
return true;
}
ShapePairKey key = new ShapePairKey(shape, occluder);
Object2ByteLinkedOpenHashMap<ShapePairKey> cache = OCCLUSION_CACHE.get();
byte cached = cache.getAndMoveToFirst((Object)key);
if (cached != 127) {
return cached != 0;
}
boolean result = Shapes.joinIsNotEmpty(shape, occluder, BooleanOp.ONLY_FIRST);
if (cache.size() == 256) {
cache.removeLastByte();
}
cache.putAndMoveToFirst((Object)key, (byte)(result ? 1 : 0));
return result;
}
public static boolean canSupportRigidBlock(BlockGetter level, BlockPos below) {
return level.getBlockState(below).isFaceSturdy(level, below, Direction.UP, SupportType.RIGID);
}
public static boolean canSupportCenter(LevelReader level, BlockPos belowPos, Direction direction) {
BlockState state = level.getBlockState(belowPos);
if (direction == Direction.DOWN && state.is(BlockTags.UNSTABLE_BOTTOM_CENTER)) {
return false;
}
return state.isFaceSturdy(level, belowPos, direction, SupportType.CENTER);
}
public static boolean isFaceFull(VoxelShape shape, Direction direction) {
VoxelShape faceShape = shape.getFaceShape(direction);
return Block.isShapeFullBlock(faceShape);
}
public static boolean isShapeFullBlock(VoxelShape shape) {
return (Boolean)SHAPE_FULL_BLOCK_CACHE.getUnchecked((Object)shape);
}
public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
}
public void destroy(LevelAccessor level, BlockPos pos, BlockState state) {
}
public static List<ItemStack> getDrops(BlockState state, ServerLevel level, BlockPos pos, @Nullable BlockEntity blockEntity) {
LootParams.Builder params = new LootParams.Builder(level).withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(pos)).withParameter(LootContextParams.TOOL, ItemStack.EMPTY).withOptionalParameter(LootContextParams.BLOCK_ENTITY, blockEntity);
return state.getDrops(params);
}
public static List<ItemStack> getDrops(BlockState state, ServerLevel level, BlockPos pos, @Nullable BlockEntity blockEntity, @Nullable Entity breaker, ItemStack tool) {
LootParams.Builder params = new LootParams.Builder(level).withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(pos)).withParameter(LootContextParams.TOOL, tool).withOptionalParameter(LootContextParams.THIS_ENTITY, breaker).withOptionalParameter(LootContextParams.BLOCK_ENTITY, blockEntity);
return state.getDrops(params);
}
public static void dropResources(BlockState state, Level level, BlockPos pos) {
if (level instanceof ServerLevel) {
Block.getDrops(state, (ServerLevel)level, pos, null).forEach(stack -> Block.popResource(level, pos, stack));
state.spawnAfterBreak((ServerLevel)level, pos, ItemStack.EMPTY, true);
}
}
public static void dropResources(BlockState state, LevelAccessor level, BlockPos pos, @Nullable BlockEntity blockEntity) {
if (level instanceof ServerLevel) {
Block.getDrops(state, (ServerLevel)level, pos, blockEntity).forEach(stack -> Block.popResource((Level)((ServerLevel)level), pos, stack));
state.spawnAfterBreak((ServerLevel)level, pos, ItemStack.EMPTY, true);
}
}
public static void dropResources(BlockState state, Level level, BlockPos pos, @Nullable BlockEntity blockEntity, @Nullable Entity breaker, ItemStack tool) {
if (level instanceof ServerLevel) {
Block.getDrops(state, (ServerLevel)level, pos, blockEntity, breaker, tool).forEach(stack -> Block.popResource(level, pos, stack));
state.spawnAfterBreak((ServerLevel)level, pos, tool, true);
}
}
public static void popResource(Level level, BlockPos pos, ItemStack itemStack) {
double halfHeight = (double)EntityType.ITEM.getHeight() / 2.0;
double x = (double)pos.getX() + 0.5 + Mth.nextDouble(level.random, -0.25, 0.25);
double y = (double)pos.getY() + 0.5 + Mth.nextDouble(level.random, -0.25, 0.25) - halfHeight;
double z = (double)pos.getZ() + 0.5 + Mth.nextDouble(level.random, -0.25, 0.25);
Block.popResource(level, () -> new ItemEntity(level, x, y, z, itemStack), itemStack);
}
public static void popResourceFromFace(Level level, BlockPos pos, Direction face, ItemStack itemStack) {
int stepX = face.getStepX();
int stepY = face.getStepY();
int stepZ = face.getStepZ();
double halfWidth = (double)EntityType.ITEM.getWidth() / 2.0;
double halfHeight = (double)EntityType.ITEM.getHeight() / 2.0;
double x = (double)pos.getX() + 0.5 + (stepX == 0 ? Mth.nextDouble(level.random, -0.25, 0.25) : (double)stepX * (0.5 + halfWidth));
double y = (double)pos.getY() + 0.5 + (stepY == 0 ? Mth.nextDouble(level.random, -0.25, 0.25) : (double)stepY * (0.5 + halfHeight)) - halfHeight;
double z = (double)pos.getZ() + 0.5 + (stepZ == 0 ? Mth.nextDouble(level.random, -0.25, 0.25) : (double)stepZ * (0.5 + halfWidth));
double deltaX = stepX == 0 ? Mth.nextDouble(level.random, -0.1, 0.1) : (double)stepX * 0.1;
double deltaY = stepY == 0 ? Mth.nextDouble(level.random, 0.0, 0.1) : (double)stepY * 0.1 + 0.1;
double deltaZ = stepZ == 0 ? Mth.nextDouble(level.random, -0.1, 0.1) : (double)stepZ * 0.1;
Block.popResource(level, () -> new ItemEntity(level, x, y, z, itemStack, deltaX, deltaY, deltaZ), itemStack);
}
private static void popResource(Level level, Supplier<ItemEntity> entityFactory, ItemStack itemStack) {
block3: {
block2: {
if (!(level instanceof ServerLevel)) break block2;
ServerLevel serverLevel = (ServerLevel)level;
if (!itemStack.isEmpty() && serverLevel.getGameRules().get(GameRules.BLOCK_DROPS).booleanValue()) break block3;
}
return;
}
ItemEntity entity = entityFactory.get();
entity.setDefaultPickUpDelay();
level.addFreshEntity(entity);
}
protected void popExperience(ServerLevel level, BlockPos pos, int amount) {
if (level.getGameRules().get(GameRules.BLOCK_DROPS).booleanValue()) {
ExperienceOrb.award(level, Vec3.atCenterOf(pos), amount);
}
}
public float getExplosionResistance() {
return this.explosionResistance;
}
public void wasExploded(ServerLevel level, BlockPos pos, Explosion explosion) {
}
public void stepOn(Level level, BlockPos pos, BlockState onState, Entity entity) {
}
public @Nullable BlockState getStateForPlacement(BlockPlaceContext context) {
return this.defaultBlockState();
}
public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack destroyedWith) {
player.awardStat(Stats.BLOCK_MINED.get(this));
player.causeFoodExhaustion(0.005f);
Block.dropResources(state, level, pos, blockEntity, player, destroyedWith);
}
public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity by, ItemStack itemStack) {
}
public boolean isPossibleToRespawnInThis(BlockState state) {
return !state.isSolid() && !state.liquid();
}
public MutableComponent getName() {
return Component.translatable(this.getDescriptionId());
}
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, double fallDistance) {
entity.causeFallDamage(fallDistance, 1.0f, entity.damageSources().fall());
}
public void updateEntityMovementAfterFallOn(BlockGetter level, Entity entity) {
entity.setDeltaMovement(entity.getDeltaMovement().multiply(1.0, 0.0, 1.0));
}
public float getFriction() {
return this.friction;
}
public float getSpeedFactor() {
return this.speedFactor;
}
public float getJumpFactor() {
return this.jumpFactor;
}
protected void spawnDestroyParticles(Level level, Player player, BlockPos pos, BlockState state) {
level.levelEvent(player, 2001, pos, Block.getId(state));
}
public BlockState playerWillDestroy(Level level, BlockPos pos, BlockState state, Player player) {
this.spawnDestroyParticles(level, player, pos, state);
if (state.is(BlockTags.GUARDED_BY_PIGLINS) && level instanceof ServerLevel) {
ServerLevel serverLevel = (ServerLevel)level;
PiglinAi.angerNearbyPiglins(serverLevel, player, false);
}
level.gameEvent(GameEvent.BLOCK_DESTROY, pos, GameEvent.Context.of(player, state));
return state;
}
public void handlePrecipitation(BlockState state, Level level, BlockPos pos, Biome.Precipitation precipitation) {
}
public boolean dropFromExplosion(Explosion explosion) {
return true;
}
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
}
public StateDefinition<Block, BlockState> getStateDefinition() {
return this.stateDefinition;
}
protected final void registerDefaultState(BlockState state) {
this.defaultBlockState = state;
}
public final BlockState defaultBlockState() {
return this.defaultBlockState;
}
public final BlockState withPropertiesOf(BlockState source) {
BlockState result = this.defaultBlockState();
for (Property<?> property : source.getBlock().getStateDefinition().getProperties()) {
if (!result.hasProperty(property)) continue;
result = Block.copyProperty(source, result, property);
}
return result;
}
private static <T extends Comparable<T>> BlockState copyProperty(BlockState from, BlockState to, Property<T> property) {
return (BlockState)to.setValue(property, from.getValue(property));
}
@Override
public Item asItem() {
if (this.item == null) {
this.item = Item.byBlock(this);
}
return this.item;
}
public boolean hasDynamicShape() {
return this.dynamicShape;
}
public String toString() {
return "Block{" + BuiltInRegistries.BLOCK.wrapAsHolder(this).getRegisteredName() + "}";
}
@Override
protected Block asBlock() {
return this;
}
protected Function<BlockState, VoxelShape> getShapeForEachState(Function<BlockState, VoxelShape> shapeCalculator) {
return arg_0 -> ((ImmutableMap)((ImmutableMap)this.stateDefinition.getPossibleStates().stream().collect(ImmutableMap.toImmutableMap(Function.identity(), shapeCalculator)))).get(arg_0);
}
protected Function<BlockState, VoxelShape> getShapeForEachState(Function<BlockState, VoxelShape> shapeCalculator, Property<?> ... ignoredProperties) {
Map<Property, Object> defaults = Arrays.stream(ignoredProperties).collect(Collectors.toMap(k -> k, k -> k.getPossibleValues().getFirst()));
ImmutableMap map = (ImmutableMap)this.stateDefinition.getPossibleStates().stream().filter(state -> defaults.entrySet().stream().allMatch(entry -> state.getValue((Property)entry.getKey()) == entry.getValue())).collect(ImmutableMap.toImmutableMap(Function.identity(), shapeCalculator));
return blockState -> {
for (Map.Entry entry : defaults.entrySet()) {
blockState = Block.setValueHelper(blockState, (Property)entry.getKey(), entry.getValue());
}
return (VoxelShape)map.get(blockState);
};
}
private static <S extends StateHolder<?, S>, T extends Comparable<T>> S setValueHelper(S state, Property<T> property, Object value) {
return (S)((StateHolder)state.setValue(property, (Comparable)((Comparable)value)));
}
@Deprecated
public Holder.Reference<Block> builtInRegistryHolder() {
return this.builtInRegistryHolder;
}
protected void tryDropExperience(ServerLevel level, BlockPos pos, ItemStack tool, IntProvider xpRange) {
int experience = EnchantmentHelper.processBlockExperience(level, tool, xpRange.sample(level.getRandom()));
if (experience > 0) {
this.popExperience(level, pos, experience);
}
}
private record ShapePairKey(VoxelShape first, VoxelShape second) {
/*
* Enabled force condition propagation
* Lifted jumps to return sites
*/
@Override
public boolean equals(Object o) {
if (!(o instanceof ShapePairKey)) return false;
ShapePairKey that = (ShapePairKey)o;
if (this.first != that.first) return false;
if (this.second != that.second) return false;
return true;
}
@Override
public int hashCode() {
return System.identityHashCode(this.first) * 31 + System.identityHashCode(this.second);
}
}
@Retention(value=RetentionPolicy.CLASS)
@Target(value={ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.TYPE_USE})
public static @interface UpdateFlags {
}
}