Code/net/minecraft/world/level/block/MultifaceBlock.java

300 lines
11 KiB
Java
Raw Normal View History

2025-07-01 06:20:03 +00:00
package net.minecraft.world.level.block;
import com.mojang.serialization.MapCodec;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.ScheduledTickAccess;
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.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public class MultifaceBlock extends Block implements SimpleWaterloggedBlock {
public static final MapCodec<MultifaceBlock> CODEC = simpleCodec(MultifaceBlock::new);
public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
private static final Map<Direction, BooleanProperty> PROPERTY_BY_DIRECTION = PipeBlock.PROPERTY_BY_DIRECTION;
protected static final Direction[] DIRECTIONS = Direction.values();
private final Function<BlockState, VoxelShape> shapes;
private final boolean canRotate;
private final boolean canMirrorX;
private final boolean canMirrorZ;
@Override
protected MapCodec<? extends MultifaceBlock> codec() {
return CODEC;
}
public MultifaceBlock(BlockBehaviour.Properties p_153822_) {
super(p_153822_);
this.registerDefaultState(getDefaultMultifaceState(this.stateDefinition));
this.shapes = this.makeShapes();
this.canRotate = Direction.Plane.HORIZONTAL.stream().allMatch(this::isFaceSupported);
this.canMirrorX = Direction.Plane.HORIZONTAL.stream().filter(Direction.Axis.X).filter(this::isFaceSupported).count() % 2L == 0L;
this.canMirrorZ = Direction.Plane.HORIZONTAL.stream().filter(Direction.Axis.Z).filter(this::isFaceSupported).count() % 2L == 0L;
}
private Function<BlockState, VoxelShape> makeShapes() {
Map<Direction, VoxelShape> map = Shapes.rotateAll(Block.boxZ(16.0, 0.0, 1.0));
return this.getShapeForEachState(p_390946_ -> {
VoxelShape voxelshape = Shapes.empty();
for (Direction direction : DIRECTIONS) {
if (hasFace(p_390946_, direction)) {
voxelshape = Shapes.or(voxelshape, map.get(direction));
}
}
return voxelshape.isEmpty() ? Shapes.block() : voxelshape;
}, new Property[]{WATERLOGGED});
}
public static Set<Direction> availableFaces(BlockState p_221585_) {
if (!(p_221585_.getBlock() instanceof MultifaceBlock)) {
return Set.of();
} else {
Set<Direction> set = EnumSet.noneOf(Direction.class);
for (Direction direction : Direction.values()) {
if (hasFace(p_221585_, direction)) {
set.add(direction);
}
}
return set;
}
}
public static Set<Direction> unpack(byte p_221570_) {
Set<Direction> set = EnumSet.noneOf(Direction.class);
for (Direction direction : Direction.values()) {
if ((p_221570_ & (byte)(1 << direction.ordinal())) > 0) {
set.add(direction);
}
}
return set;
}
public static byte pack(Collection<Direction> p_221577_) {
byte b0 = 0;
for (Direction direction : p_221577_) {
b0 = (byte)(b0 | 1 << direction.ordinal());
}
return b0;
}
protected boolean isFaceSupported(Direction p_153921_) {
return true;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> p_153917_) {
for (Direction direction : DIRECTIONS) {
if (this.isFaceSupported(direction)) {
p_153917_.add(getFaceProperty(direction));
}
}
p_153917_.add(WATERLOGGED);
}
@Override
protected BlockState updateShape(
BlockState p_153904_,
LevelReader p_367619_,
ScheduledTickAccess p_360930_,
BlockPos p_153908_,
Direction p_153905_,
BlockPos p_153909_,
BlockState p_153906_,
RandomSource p_369670_
) {
if (p_153904_.getValue(WATERLOGGED)) {
p_360930_.scheduleTick(p_153908_, Fluids.WATER, Fluids.WATER.getTickDelay(p_367619_));
}
if (!hasAnyFace(p_153904_)) {
return Blocks.AIR.defaultBlockState();
} else {
return hasFace(p_153904_, p_153905_) && !canAttachTo(p_367619_, p_153905_, p_153909_, p_153906_)
? removeFace(p_153904_, getFaceProperty(p_153905_))
: p_153904_;
}
}
@Override
protected FluidState getFluidState(BlockState p_378072_) {
return p_378072_.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(p_378072_);
}
@Override
protected VoxelShape getShape(BlockState p_153851_, BlockGetter p_153852_, BlockPos p_153853_, CollisionContext p_153854_) {
return this.shapes.apply(p_153851_);
}
@Override
protected boolean canSurvive(BlockState p_153888_, LevelReader p_153889_, BlockPos p_153890_) {
boolean flag = false;
for (Direction direction : DIRECTIONS) {
if (hasFace(p_153888_, direction)) {
if (!canAttachTo(p_153889_, p_153890_, direction)) {
return false;
}
flag = true;
}
}
return flag;
}
@Override
protected boolean canBeReplaced(BlockState p_153848_, BlockPlaceContext p_153849_) {
return !p_153849_.getItemInHand().is(this.asItem()) || hasAnyVacantFace(p_153848_);
}
@Nullable
@Override
public BlockState getStateForPlacement(BlockPlaceContext p_153824_) {
Level level = p_153824_.getLevel();
BlockPos blockpos = p_153824_.getClickedPos();
BlockState blockstate = level.getBlockState(blockpos);
return Arrays.stream(p_153824_.getNearestLookingDirections())
.map(p_153865_ -> this.getStateForPlacement(blockstate, level, blockpos, p_153865_))
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
public boolean isValidStateForPlacement(BlockGetter p_221572_, BlockState p_221573_, BlockPos p_221574_, Direction p_221575_) {
if (this.isFaceSupported(p_221575_) && (!p_221573_.is(this) || !hasFace(p_221573_, p_221575_))) {
BlockPos blockpos = p_221574_.relative(p_221575_);
return canAttachTo(p_221572_, p_221575_, blockpos, p_221572_.getBlockState(blockpos));
} else {
return false;
}
}
@Nullable
public BlockState getStateForPlacement(BlockState p_153941_, BlockGetter p_153942_, BlockPos p_153943_, Direction p_153944_) {
if (!this.isValidStateForPlacement(p_153942_, p_153941_, p_153943_, p_153944_)) {
return null;
} else {
BlockState blockstate;
if (p_153941_.is(this)) {
blockstate = p_153941_;
} else if (p_153941_.getFluidState().isSourceOfType(Fluids.WATER)) {
blockstate = this.defaultBlockState().setValue(BlockStateProperties.WATERLOGGED, true);
} else {
blockstate = this.defaultBlockState();
}
return blockstate.setValue(getFaceProperty(p_153944_), true);
}
}
@Override
protected BlockState rotate(BlockState p_153895_, Rotation p_153896_) {
return !this.canRotate ? p_153895_ : this.mapDirections(p_153895_, p_153896_::rotate);
}
@Override
protected BlockState mirror(BlockState p_153892_, Mirror p_153893_) {
if (p_153893_ == Mirror.FRONT_BACK && !this.canMirrorX) {
return p_153892_;
} else {
return p_153893_ == Mirror.LEFT_RIGHT && !this.canMirrorZ ? p_153892_ : this.mapDirections(p_153892_, p_153893_::mirror);
}
}
private BlockState mapDirections(BlockState p_153911_, Function<Direction, Direction> p_153912_) {
BlockState blockstate = p_153911_;
for (Direction direction : DIRECTIONS) {
if (this.isFaceSupported(direction)) {
blockstate = blockstate.setValue(getFaceProperty(p_153912_.apply(direction)), p_153911_.getValue(getFaceProperty(direction)));
}
}
return blockstate;
}
public static boolean hasFace(BlockState p_153901_, Direction p_153902_) {
BooleanProperty booleanproperty = getFaceProperty(p_153902_);
return p_153901_.getValueOrElse(booleanproperty, false);
}
public static boolean canAttachTo(BlockGetter p_376779_, BlockPos p_375819_, Direction p_378815_) {
BlockPos blockpos = p_375819_.relative(p_378815_);
BlockState blockstate = p_376779_.getBlockState(blockpos);
return canAttachTo(p_376779_, p_378815_, blockpos, blockstate);
}
public static boolean canAttachTo(BlockGetter p_153830_, Direction p_153831_, BlockPos p_153832_, BlockState p_153833_) {
return Block.isFaceFull(p_153833_.getBlockSupportShape(p_153830_, p_153832_), p_153831_.getOpposite())
|| Block.isFaceFull(p_153833_.getCollisionShape(p_153830_, p_153832_), p_153831_.getOpposite());
}
private static BlockState removeFace(BlockState p_153898_, BooleanProperty p_153899_) {
BlockState blockstate = p_153898_.setValue(p_153899_, false);
return hasAnyFace(blockstate) ? blockstate : Blocks.AIR.defaultBlockState();
}
public static BooleanProperty getFaceProperty(Direction p_153934_) {
return PROPERTY_BY_DIRECTION.get(p_153934_);
}
private static BlockState getDefaultMultifaceState(StateDefinition<Block, BlockState> p_153919_) {
BlockState blockstate = p_153919_.any().setValue(WATERLOGGED, false);
for (BooleanProperty booleanproperty : PROPERTY_BY_DIRECTION.values()) {
blockstate = blockstate.trySetValue(booleanproperty, false);
}
return blockstate;
}
protected static boolean hasAnyFace(BlockState p_153961_) {
for (Direction direction : DIRECTIONS) {
if (hasFace(p_153961_, direction)) {
return true;
}
}
return false;
}
private static boolean hasAnyVacantFace(BlockState p_153963_) {
for (Direction direction : DIRECTIONS) {
if (!hasFace(p_153963_, direction)) {
return true;
}
}
return false;
}
}