Code/net/minecraft/world/level/block/piston/PistonBaseBlock.java

389 lines
18 KiB
Java
Raw Normal View History

2025-07-01 06:20:03 +00:00
package net.minecraft.world.level.block.piston;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import com.mojang.serialization.codecs.RecordCodecBuilder.Instance;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.SignalGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.DirectionalBlock;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
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.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.PistonType;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.material.PushReaction;
import net.minecraft.world.level.pathfinder.PathComputationType;
import net.minecraft.world.level.redstone.ExperimentalRedstoneUtils;
import net.minecraft.world.level.redstone.Orientation;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public class PistonBaseBlock extends DirectionalBlock {
public static final MapCodec<PistonBaseBlock> CODEC = RecordCodecBuilder.mapCodec(
p_360537_ -> p_360537_.group(Codec.BOOL.fieldOf("sticky").forGetter(p_309381_ -> p_309381_.isSticky), propertiesCodec())
.apply(p_360537_, PistonBaseBlock::new)
);
public static final BooleanProperty EXTENDED = BlockStateProperties.EXTENDED;
public static final int TRIGGER_EXTEND = 0;
public static final int TRIGGER_CONTRACT = 1;
public static final int TRIGGER_DROP = 2;
public static final int PLATFORM_THICKNESS = 4;
private static final Map<Direction, VoxelShape> SHAPES = Shapes.rotateAll(Block.boxZ(16.0, 4.0, 16.0));
private final boolean isSticky;
@Override
public MapCodec<PistonBaseBlock> codec() {
return CODEC;
}
public PistonBaseBlock(boolean p_60163_, BlockBehaviour.Properties p_60164_) {
super(p_60164_);
this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(EXTENDED, false));
this.isSticky = p_60163_;
}
@Override
protected VoxelShape getShape(BlockState p_60220_, BlockGetter p_60221_, BlockPos p_60222_, CollisionContext p_60223_) {
return p_60220_.getValue(EXTENDED) ? SHAPES.get(p_60220_.getValue(FACING)) : Shapes.block();
}
@Override
public void setPlacedBy(Level p_60172_, BlockPos p_60173_, BlockState p_60174_, LivingEntity p_60175_, ItemStack p_60176_) {
if (!p_60172_.isClientSide) {
this.checkIfExtend(p_60172_, p_60173_, p_60174_);
}
}
@Override
protected void neighborChanged(BlockState p_60198_, Level p_60199_, BlockPos p_60200_, Block p_60201_, @Nullable Orientation p_366407_, boolean p_60203_) {
if (!p_60199_.isClientSide) {
this.checkIfExtend(p_60199_, p_60200_, p_60198_);
}
}
@Override
protected void onPlace(BlockState p_60225_, Level p_60226_, BlockPos p_60227_, BlockState p_60228_, boolean p_60229_) {
if (!p_60228_.is(p_60225_.getBlock())) {
if (!p_60226_.isClientSide && p_60226_.getBlockEntity(p_60227_) == null) {
this.checkIfExtend(p_60226_, p_60227_, p_60225_);
}
}
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext p_60166_) {
return this.defaultBlockState().setValue(FACING, p_60166_.getNearestLookingDirection().getOpposite()).setValue(EXTENDED, false);
}
private void checkIfExtend(Level p_60168_, BlockPos p_60169_, BlockState p_60170_) {
Direction direction = p_60170_.getValue(FACING);
boolean flag = this.getNeighborSignal(p_60168_, p_60169_, direction);
if (flag && !p_60170_.getValue(EXTENDED)) {
if (new PistonStructureResolver(p_60168_, p_60169_, direction, true).resolve()) {
p_60168_.blockEvent(p_60169_, this, 0, direction.get3DDataValue());
}
} else if (!flag && p_60170_.getValue(EXTENDED)) {
BlockPos blockpos = p_60169_.relative(direction, 2);
BlockState blockstate = p_60168_.getBlockState(blockpos);
int i = 1;
if (blockstate.is(Blocks.MOVING_PISTON)
&& blockstate.getValue(FACING) == direction
&& p_60168_.getBlockEntity(blockpos) instanceof PistonMovingBlockEntity pistonmovingblockentity
&& pistonmovingblockentity.isExtending()
&& (
pistonmovingblockentity.getProgress(0.0F) < 0.5F
|| p_60168_.getGameTime() == pistonmovingblockentity.getLastTicked()
|| ((ServerLevel)p_60168_).isHandlingTick()
)) {
i = 2;
}
p_60168_.blockEvent(p_60169_, this, i, direction.get3DDataValue());
}
}
private boolean getNeighborSignal(SignalGetter p_277378_, BlockPos p_60179_, Direction p_60180_) {
for (Direction direction : Direction.values()) {
if (direction != p_60180_ && p_277378_.hasSignal(p_60179_.relative(direction), direction)) {
return true;
}
}
if (p_277378_.hasSignal(p_60179_, Direction.DOWN)) {
return true;
} else {
BlockPos blockpos = p_60179_.above();
for (Direction direction1 : Direction.values()) {
if (direction1 != Direction.DOWN && p_277378_.hasSignal(blockpos.relative(direction1), direction1)) {
return true;
}
}
return false;
}
}
@Override
protected boolean triggerEvent(BlockState p_60192_, Level p_60193_, BlockPos p_60194_, int p_60195_, int p_60196_) {
Direction direction = p_60192_.getValue(FACING);
BlockState blockstate = p_60192_.setValue(EXTENDED, true);
if (!p_60193_.isClientSide) {
boolean flag = this.getNeighborSignal(p_60193_, p_60194_, direction);
if (flag && (p_60195_ == 1 || p_60195_ == 2)) {
p_60193_.setBlock(p_60194_, blockstate, 2);
return false;
}
if (!flag && p_60195_ == 0) {
return false;
}
}
if (p_60195_ == 0) {
if (!this.moveBlocks(p_60193_, p_60194_, direction, true)) {
return false;
}
p_60193_.setBlock(p_60194_, blockstate, 67);
p_60193_.playSound(null, p_60194_, SoundEvents.PISTON_EXTEND, SoundSource.BLOCKS, 0.5F, p_60193_.random.nextFloat() * 0.25F + 0.6F);
p_60193_.gameEvent(GameEvent.BLOCK_ACTIVATE, p_60194_, GameEvent.Context.of(blockstate));
} else if (p_60195_ == 1 || p_60195_ == 2) {
BlockEntity blockentity = p_60193_.getBlockEntity(p_60194_.relative(direction));
if (blockentity instanceof PistonMovingBlockEntity) {
((PistonMovingBlockEntity)blockentity).finalTick();
}
BlockState blockstate1 = Blocks.MOVING_PISTON
.defaultBlockState()
.setValue(MovingPistonBlock.FACING, direction)
.setValue(MovingPistonBlock.TYPE, this.isSticky ? PistonType.STICKY : PistonType.DEFAULT);
p_60193_.setBlock(p_60194_, blockstate1, 276);
p_60193_.setBlockEntity(
MovingPistonBlock.newMovingBlockEntity(
p_60194_, blockstate1, this.defaultBlockState().setValue(FACING, Direction.from3DDataValue(p_60196_ & 7)), direction, false, true
)
);
p_60193_.updateNeighborsAt(p_60194_, blockstate1.getBlock());
blockstate1.updateNeighbourShapes(p_60193_, p_60194_, 2);
if (this.isSticky) {
BlockPos blockpos = p_60194_.offset(direction.getStepX() * 2, direction.getStepY() * 2, direction.getStepZ() * 2);
BlockState blockstate2 = p_60193_.getBlockState(blockpos);
boolean flag1 = false;
if (blockstate2.is(Blocks.MOVING_PISTON)
&& p_60193_.getBlockEntity(blockpos) instanceof PistonMovingBlockEntity pistonmovingblockentity
&& pistonmovingblockentity.getDirection() == direction
&& pistonmovingblockentity.isExtending()) {
pistonmovingblockentity.finalTick();
flag1 = true;
}
if (!flag1) {
if (p_60195_ != 1
|| blockstate2.isAir()
|| !isPushable(blockstate2, p_60193_, blockpos, direction.getOpposite(), false, direction)
|| blockstate2.getPistonPushReaction() != PushReaction.NORMAL && !blockstate2.is(Blocks.PISTON) && !blockstate2.is(Blocks.STICKY_PISTON)) {
p_60193_.removeBlock(p_60194_.relative(direction), false);
} else {
this.moveBlocks(p_60193_, p_60194_, direction, false);
}
}
} else {
p_60193_.removeBlock(p_60194_.relative(direction), false);
}
p_60193_.playSound(null, p_60194_, SoundEvents.PISTON_CONTRACT, SoundSource.BLOCKS, 0.5F, p_60193_.random.nextFloat() * 0.15F + 0.6F);
p_60193_.gameEvent(GameEvent.BLOCK_DEACTIVATE, p_60194_, GameEvent.Context.of(blockstate1));
}
return true;
}
public static boolean isPushable(BlockState p_60205_, Level p_60206_, BlockPos p_60207_, Direction p_60208_, boolean p_60209_, Direction p_60210_) {
if (p_60207_.getY() < p_60206_.getMinY() || p_60207_.getY() > p_60206_.getMaxY() || !p_60206_.getWorldBorder().isWithinBounds(p_60207_)) {
return false;
} else if (p_60205_.isAir()) {
return true;
} else if (p_60205_.is(Blocks.OBSIDIAN)
|| p_60205_.is(Blocks.CRYING_OBSIDIAN)
|| p_60205_.is(Blocks.RESPAWN_ANCHOR)
|| p_60205_.is(Blocks.REINFORCED_DEEPSLATE)) {
return false;
} else if (p_60208_ == Direction.DOWN && p_60207_.getY() == p_60206_.getMinY()) {
return false;
} else if (p_60208_ == Direction.UP && p_60207_.getY() == p_60206_.getMaxY()) {
return false;
} else {
if (!p_60205_.is(Blocks.PISTON) && !p_60205_.is(Blocks.STICKY_PISTON)) {
if (p_60205_.getDestroySpeed(p_60206_, p_60207_) == -1.0F) {
return false;
}
switch (p_60205_.getPistonPushReaction()) {
case BLOCK:
return false;
case DESTROY:
return p_60209_;
case PUSH_ONLY:
return p_60208_ == p_60210_;
}
} else if (p_60205_.getValue(EXTENDED)) {
return false;
}
return !p_60205_.hasBlockEntity();
}
}
private boolean moveBlocks(Level p_60182_, BlockPos p_60183_, Direction p_60184_, boolean p_60185_) {
BlockPos blockpos = p_60183_.relative(p_60184_);
if (!p_60185_ && p_60182_.getBlockState(blockpos).is(Blocks.PISTON_HEAD)) {
p_60182_.setBlock(blockpos, Blocks.AIR.defaultBlockState(), 276);
}
PistonStructureResolver pistonstructureresolver = new PistonStructureResolver(p_60182_, p_60183_, p_60184_, p_60185_);
if (!pistonstructureresolver.resolve()) {
return false;
} else {
Map<BlockPos, BlockState> map = Maps.newHashMap();
List<BlockPos> list = pistonstructureresolver.getToPush();
List<BlockState> list1 = Lists.newArrayList();
for (BlockPos blockpos1 : list) {
BlockState blockstate = p_60182_.getBlockState(blockpos1);
list1.add(blockstate);
map.put(blockpos1, blockstate);
}
List<BlockPos> list2 = pistonstructureresolver.getToDestroy();
BlockState[] ablockstate = new BlockState[list.size() + list2.size()];
Direction direction = p_60185_ ? p_60184_ : p_60184_.getOpposite();
int i = 0;
for (int j = list2.size() - 1; j >= 0; j--) {
BlockPos blockpos2 = list2.get(j);
BlockState blockstate1 = p_60182_.getBlockState(blockpos2);
BlockEntity blockentity = blockstate1.hasBlockEntity() ? p_60182_.getBlockEntity(blockpos2) : null;
dropResources(blockstate1, p_60182_, blockpos2, blockentity);
if (!blockstate1.is(BlockTags.FIRE) && p_60182_.isClientSide()) {
p_60182_.levelEvent(2001, blockpos2, getId(blockstate1));
}
p_60182_.setBlock(blockpos2, Blocks.AIR.defaultBlockState(), 18);
p_60182_.gameEvent(GameEvent.BLOCK_DESTROY, blockpos2, GameEvent.Context.of(blockstate1));
ablockstate[i++] = blockstate1;
}
for (int k = list.size() - 1; k >= 0; k--) {
BlockPos blockpos3 = list.get(k);
BlockState blockstate5 = p_60182_.getBlockState(blockpos3);
blockpos3 = blockpos3.relative(direction);
map.remove(blockpos3);
BlockState blockstate7 = Blocks.MOVING_PISTON.defaultBlockState().setValue(FACING, p_60184_);
p_60182_.setBlock(blockpos3, blockstate7, 324);
p_60182_.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(blockpos3, blockstate7, list1.get(k), p_60184_, p_60185_, false));
ablockstate[i++] = blockstate5;
}
if (p_60185_) {
PistonType pistontype = this.isSticky ? PistonType.STICKY : PistonType.DEFAULT;
BlockState blockstate4 = Blocks.PISTON_HEAD.defaultBlockState().setValue(PistonHeadBlock.FACING, p_60184_).setValue(PistonHeadBlock.TYPE, pistontype);
BlockState blockstate6 = Blocks.MOVING_PISTON
.defaultBlockState()
.setValue(MovingPistonBlock.FACING, p_60184_)
.setValue(MovingPistonBlock.TYPE, this.isSticky ? PistonType.STICKY : PistonType.DEFAULT);
map.remove(blockpos);
p_60182_.setBlock(blockpos, blockstate6, 324);
p_60182_.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(blockpos, blockstate6, blockstate4, p_60184_, true, true));
}
BlockState blockstate3 = Blocks.AIR.defaultBlockState();
for (BlockPos blockpos4 : map.keySet()) {
p_60182_.setBlock(blockpos4, blockstate3, 82);
}
for (Entry<BlockPos, BlockState> entry : map.entrySet()) {
BlockPos blockpos5 = entry.getKey();
BlockState blockstate2 = entry.getValue();
blockstate2.updateIndirectNeighbourShapes(p_60182_, blockpos5, 2);
blockstate3.updateNeighbourShapes(p_60182_, blockpos5, 2);
blockstate3.updateIndirectNeighbourShapes(p_60182_, blockpos5, 2);
}
Orientation orientation = ExperimentalRedstoneUtils.initialOrientation(p_60182_, pistonstructureresolver.getPushDirection(), null);
i = 0;
for (int l = list2.size() - 1; l >= 0; l--) {
BlockState blockstate8 = ablockstate[i++];
BlockPos blockpos6 = list2.get(l);
if (p_60182_ instanceof ServerLevel serverlevel) {
blockstate8.affectNeighborsAfterRemoval(serverlevel, blockpos6, false);
}
blockstate8.updateIndirectNeighbourShapes(p_60182_, blockpos6, 2);
p_60182_.updateNeighborsAt(blockpos6, blockstate8.getBlock(), orientation);
}
for (int i1 = list.size() - 1; i1 >= 0; i1--) {
p_60182_.updateNeighborsAt(list.get(i1), ablockstate[i++].getBlock(), orientation);
}
if (p_60185_) {
p_60182_.updateNeighborsAt(blockpos, Blocks.PISTON_HEAD, orientation);
}
return true;
}
}
@Override
protected BlockState rotate(BlockState p_60215_, Rotation p_60216_) {
return p_60215_.setValue(FACING, p_60216_.rotate(p_60215_.getValue(FACING)));
}
@Override
protected BlockState mirror(BlockState p_60212_, Mirror p_60213_) {
return p_60212_.rotate(p_60213_.getRotation(p_60212_.getValue(FACING)));
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> p_60218_) {
p_60218_.add(FACING, EXTENDED);
}
@Override
protected boolean useShapeForLightOcclusion(BlockState p_60231_) {
return p_60231_.getValue(EXTENDED);
}
@Override
protected boolean isPathfindable(BlockState p_60187_, PathComputationType p_60190_) {
return false;
}
}