403 lines
18 KiB
Java
403 lines
18 KiB
Java
|
package net.minecraft.world.level.block.piston;
|
||
|
|
||
|
import java.util.Iterator;
|
||
|
import java.util.List;
|
||
|
import net.minecraft.core.BlockPos;
|
||
|
import net.minecraft.core.Direction;
|
||
|
import net.minecraft.core.HolderLookup;
|
||
|
import net.minecraft.core.registries.Registries;
|
||
|
import net.minecraft.nbt.CompoundTag;
|
||
|
import net.minecraft.nbt.NbtOps;
|
||
|
import net.minecraft.nbt.Tag;
|
||
|
import net.minecraft.resources.RegistryOps;
|
||
|
import net.minecraft.server.level.ServerPlayer;
|
||
|
import net.minecraft.util.Mth;
|
||
|
import net.minecraft.world.entity.Entity;
|
||
|
import net.minecraft.world.entity.MoverType;
|
||
|
import net.minecraft.world.level.BlockGetter;
|
||
|
import net.minecraft.world.level.Level;
|
||
|
import net.minecraft.world.level.block.Block;
|
||
|
import net.minecraft.world.level.block.Blocks;
|
||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||
|
import net.minecraft.world.level.block.state.BlockState;
|
||
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||
|
import net.minecraft.world.level.block.state.properties.PistonType;
|
||
|
import net.minecraft.world.level.material.PushReaction;
|
||
|
import net.minecraft.world.level.redstone.ExperimentalRedstoneUtils;
|
||
|
import net.minecraft.world.phys.AABB;
|
||
|
import net.minecraft.world.phys.Vec3;
|
||
|
import net.minecraft.world.phys.shapes.Shapes;
|
||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||
|
|
||
|
public class PistonMovingBlockEntity extends BlockEntity {
|
||
|
private static final int TICKS_TO_EXTEND = 2;
|
||
|
private static final double PUSH_OFFSET = 0.01;
|
||
|
public static final double TICK_MOVEMENT = 0.51;
|
||
|
private static final BlockState DEFAULT_BLOCK_STATE = Blocks.AIR.defaultBlockState();
|
||
|
private static final float DEFAULT_PROGRESS = 0.0F;
|
||
|
private static final boolean DEFAULT_EXTENDING = false;
|
||
|
private static final boolean DEFAULT_SOURCE = false;
|
||
|
private BlockState movedState = DEFAULT_BLOCK_STATE;
|
||
|
private Direction direction;
|
||
|
private boolean extending = false;
|
||
|
private boolean isSourcePiston = false;
|
||
|
private static final ThreadLocal<Direction> NOCLIP = ThreadLocal.withInitial(() -> null);
|
||
|
private float progress = 0.0F;
|
||
|
private float progressO = 0.0F;
|
||
|
private long lastTicked;
|
||
|
private int deathTicks;
|
||
|
|
||
|
public PistonMovingBlockEntity(BlockPos p_155901_, BlockState p_155902_) {
|
||
|
super(BlockEntityType.PISTON, p_155901_, p_155902_);
|
||
|
}
|
||
|
|
||
|
public PistonMovingBlockEntity(BlockPos p_155904_, BlockState p_155905_, BlockState p_155906_, Direction p_155907_, boolean p_155908_, boolean p_155909_) {
|
||
|
this(p_155904_, p_155905_);
|
||
|
this.movedState = p_155906_;
|
||
|
this.direction = p_155907_;
|
||
|
this.extending = p_155908_;
|
||
|
this.isSourcePiston = p_155909_;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public CompoundTag getUpdateTag(HolderLookup.Provider p_335610_) {
|
||
|
return this.saveCustomOnly(p_335610_);
|
||
|
}
|
||
|
|
||
|
public boolean isExtending() {
|
||
|
return this.extending;
|
||
|
}
|
||
|
|
||
|
public Direction getDirection() {
|
||
|
return this.direction;
|
||
|
}
|
||
|
|
||
|
public boolean isSourcePiston() {
|
||
|
return this.isSourcePiston;
|
||
|
}
|
||
|
|
||
|
public float getProgress(float p_60351_) {
|
||
|
if (p_60351_ > 1.0F) {
|
||
|
p_60351_ = 1.0F;
|
||
|
}
|
||
|
|
||
|
return Mth.lerp(p_60351_, this.progressO, this.progress);
|
||
|
}
|
||
|
|
||
|
public float getXOff(float p_60381_) {
|
||
|
return this.direction.getStepX() * this.getExtendedProgress(this.getProgress(p_60381_));
|
||
|
}
|
||
|
|
||
|
public float getYOff(float p_60386_) {
|
||
|
return this.direction.getStepY() * this.getExtendedProgress(this.getProgress(p_60386_));
|
||
|
}
|
||
|
|
||
|
public float getZOff(float p_60389_) {
|
||
|
return this.direction.getStepZ() * this.getExtendedProgress(this.getProgress(p_60389_));
|
||
|
}
|
||
|
|
||
|
private float getExtendedProgress(float p_60391_) {
|
||
|
return this.extending ? p_60391_ - 1.0F : 1.0F - p_60391_;
|
||
|
}
|
||
|
|
||
|
private BlockState getCollisionRelatedBlockState() {
|
||
|
return !this.isExtending() && this.isSourcePiston() && this.movedState.getBlock() instanceof PistonBaseBlock
|
||
|
? Blocks.PISTON_HEAD
|
||
|
.defaultBlockState()
|
||
|
.setValue(PistonHeadBlock.SHORT, this.progress > 0.25F)
|
||
|
.setValue(PistonHeadBlock.TYPE, this.movedState.is(Blocks.STICKY_PISTON) ? PistonType.STICKY : PistonType.DEFAULT)
|
||
|
.setValue(PistonHeadBlock.FACING, this.movedState.getValue(PistonBaseBlock.FACING))
|
||
|
: this.movedState;
|
||
|
}
|
||
|
|
||
|
private static void moveCollidedEntities(Level p_155911_, BlockPos p_155912_, float p_155913_, PistonMovingBlockEntity p_155914_) {
|
||
|
Direction direction = p_155914_.getMovementDirection();
|
||
|
double d0 = p_155913_ - p_155914_.progress;
|
||
|
VoxelShape voxelshape = p_155914_.getCollisionRelatedBlockState().getCollisionShape(p_155911_, p_155912_);
|
||
|
if (!voxelshape.isEmpty()) {
|
||
|
AABB aabb = moveByPositionAndProgress(p_155912_, voxelshape.bounds(), p_155914_);
|
||
|
List<Entity> list = p_155911_.getEntities(null, PistonMath.getMovementArea(aabb, direction, d0).minmax(aabb));
|
||
|
if (!list.isEmpty()) {
|
||
|
List<AABB> list1 = voxelshape.toAabbs();
|
||
|
boolean flag = p_155914_.movedState.is(Blocks.SLIME_BLOCK);
|
||
|
Iterator iterator = list.iterator();
|
||
|
|
||
|
while (true) {
|
||
|
Entity entity;
|
||
|
while (true) {
|
||
|
if (!iterator.hasNext()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
entity = (Entity)iterator.next();
|
||
|
if (entity.getPistonPushReaction() != PushReaction.IGNORE) {
|
||
|
if (!flag) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!(entity instanceof ServerPlayer)) {
|
||
|
Vec3 vec3 = entity.getDeltaMovement();
|
||
|
double d1 = vec3.x;
|
||
|
double d2 = vec3.y;
|
||
|
double d3 = vec3.z;
|
||
|
switch (direction.getAxis()) {
|
||
|
case X:
|
||
|
d1 = direction.getStepX();
|
||
|
break;
|
||
|
case Y:
|
||
|
d2 = direction.getStepY();
|
||
|
break;
|
||
|
case Z:
|
||
|
d3 = direction.getStepZ();
|
||
|
}
|
||
|
|
||
|
entity.setDeltaMovement(d1, d2, d3);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
double d4 = 0.0;
|
||
|
|
||
|
for (AABB aabb2 : list1) {
|
||
|
AABB aabb1 = PistonMath.getMovementArea(moveByPositionAndProgress(p_155912_, aabb2, p_155914_), direction, d0);
|
||
|
AABB aabb3 = entity.getBoundingBox();
|
||
|
if (aabb1.intersects(aabb3)) {
|
||
|
d4 = Math.max(d4, getMovement(aabb1, direction, aabb3));
|
||
|
if (d4 >= d0) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!(d4 <= 0.0)) {
|
||
|
d4 = Math.min(d4, d0) + 0.01;
|
||
|
moveEntityByPiston(direction, entity, d4, direction);
|
||
|
if (!p_155914_.extending && p_155914_.isSourcePiston) {
|
||
|
fixEntityWithinPistonBase(p_155912_, entity, direction, d0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void moveEntityByPiston(Direction p_60372_, Entity p_60373_, double p_60374_, Direction p_60375_) {
|
||
|
NOCLIP.set(p_60372_);
|
||
|
Vec3 vec3 = p_60373_.position();
|
||
|
p_60373_.move(MoverType.PISTON, new Vec3(p_60374_ * p_60375_.getStepX(), p_60374_ * p_60375_.getStepY(), p_60374_ * p_60375_.getStepZ()));
|
||
|
p_60373_.applyEffectsFromBlocks(vec3, p_60373_.position());
|
||
|
p_60373_.removeLatestMovementRecordingBatch();
|
||
|
NOCLIP.set(null);
|
||
|
}
|
||
|
|
||
|
private static void moveStuckEntities(Level p_155932_, BlockPos p_155933_, float p_155934_, PistonMovingBlockEntity p_155935_) {
|
||
|
if (p_155935_.isStickyForEntities()) {
|
||
|
Direction direction = p_155935_.getMovementDirection();
|
||
|
if (direction.getAxis().isHorizontal()) {
|
||
|
double d0 = p_155935_.movedState.getCollisionShape(p_155932_, p_155933_).max(Direction.Axis.Y);
|
||
|
AABB aabb = moveByPositionAndProgress(p_155933_, new AABB(0.0, d0, 0.0, 1.0, 1.5000010000000001, 1.0), p_155935_);
|
||
|
double d1 = p_155934_ - p_155935_.progress;
|
||
|
|
||
|
for (Entity entity : p_155932_.getEntities((Entity)null, aabb, p_287552_ -> matchesStickyCritera(aabb, p_287552_, p_155933_))) {
|
||
|
moveEntityByPiston(direction, entity, d1, direction);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static boolean matchesStickyCritera(AABB p_287782_, Entity p_287720_, BlockPos p_287775_) {
|
||
|
return p_287720_.getPistonPushReaction() == PushReaction.NORMAL
|
||
|
&& p_287720_.onGround()
|
||
|
&& (
|
||
|
p_287720_.isSupportedBy(p_287775_)
|
||
|
|| p_287720_.getX() >= p_287782_.minX
|
||
|
&& p_287720_.getX() <= p_287782_.maxX
|
||
|
&& p_287720_.getZ() >= p_287782_.minZ
|
||
|
&& p_287720_.getZ() <= p_287782_.maxZ
|
||
|
);
|
||
|
}
|
||
|
|
||
|
private boolean isStickyForEntities() {
|
||
|
return this.movedState.is(Blocks.HONEY_BLOCK);
|
||
|
}
|
||
|
|
||
|
public Direction getMovementDirection() {
|
||
|
return this.extending ? this.direction : this.direction.getOpposite();
|
||
|
}
|
||
|
|
||
|
private static double getMovement(AABB p_60368_, Direction p_60369_, AABB p_60370_) {
|
||
|
switch (p_60369_) {
|
||
|
case EAST:
|
||
|
return p_60368_.maxX - p_60370_.minX;
|
||
|
case WEST:
|
||
|
return p_60370_.maxX - p_60368_.minX;
|
||
|
case UP:
|
||
|
default:
|
||
|
return p_60368_.maxY - p_60370_.minY;
|
||
|
case DOWN:
|
||
|
return p_60370_.maxY - p_60368_.minY;
|
||
|
case SOUTH:
|
||
|
return p_60368_.maxZ - p_60370_.minZ;
|
||
|
case NORTH:
|
||
|
return p_60370_.maxZ - p_60368_.minZ;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static AABB moveByPositionAndProgress(BlockPos p_155926_, AABB p_155927_, PistonMovingBlockEntity p_155928_) {
|
||
|
double d0 = p_155928_.getExtendedProgress(p_155928_.progress);
|
||
|
return p_155927_.move(
|
||
|
p_155926_.getX() + d0 * p_155928_.direction.getStepX(),
|
||
|
p_155926_.getY() + d0 * p_155928_.direction.getStepY(),
|
||
|
p_155926_.getZ() + d0 * p_155928_.direction.getStepZ()
|
||
|
);
|
||
|
}
|
||
|
|
||
|
private static void fixEntityWithinPistonBase(BlockPos p_155921_, Entity p_155922_, Direction p_155923_, double p_155924_) {
|
||
|
AABB aabb = p_155922_.getBoundingBox();
|
||
|
AABB aabb1 = Shapes.block().bounds().move(p_155921_);
|
||
|
if (aabb.intersects(aabb1)) {
|
||
|
Direction direction = p_155923_.getOpposite();
|
||
|
double d0 = getMovement(aabb1, direction, aabb) + 0.01;
|
||
|
double d1 = getMovement(aabb1, direction, aabb.intersect(aabb1)) + 0.01;
|
||
|
if (Math.abs(d0 - d1) < 0.01) {
|
||
|
d0 = Math.min(d0, p_155924_) + 0.01;
|
||
|
moveEntityByPiston(p_155923_, p_155922_, d0, direction);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public BlockState getMovedState() {
|
||
|
return this.movedState;
|
||
|
}
|
||
|
|
||
|
public void finalTick() {
|
||
|
if (this.level != null && (this.progressO < 1.0F || this.level.isClientSide)) {
|
||
|
this.progress = 1.0F;
|
||
|
this.progressO = this.progress;
|
||
|
this.level.removeBlockEntity(this.worldPosition);
|
||
|
this.setRemoved();
|
||
|
if (this.level.getBlockState(this.worldPosition).is(Blocks.MOVING_PISTON)) {
|
||
|
BlockState blockstate;
|
||
|
if (this.isSourcePiston) {
|
||
|
blockstate = Blocks.AIR.defaultBlockState();
|
||
|
} else {
|
||
|
blockstate = Block.updateFromNeighbourShapes(this.movedState, this.level, this.worldPosition);
|
||
|
}
|
||
|
|
||
|
this.level.setBlock(this.worldPosition, blockstate, 3);
|
||
|
this.level.neighborChanged(this.worldPosition, blockstate.getBlock(), ExperimentalRedstoneUtils.initialOrientation(this.level, this.getPushDirection(), null));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void preRemoveSideEffects(BlockPos p_397541_, BlockState p_393563_) {
|
||
|
this.finalTick();
|
||
|
}
|
||
|
|
||
|
public Direction getPushDirection() {
|
||
|
return this.extending ? this.direction : this.direction.getOpposite();
|
||
|
}
|
||
|
|
||
|
public static void tick(Level p_155916_, BlockPos p_155917_, BlockState p_155918_, PistonMovingBlockEntity p_155919_) {
|
||
|
p_155919_.lastTicked = p_155916_.getGameTime();
|
||
|
p_155919_.progressO = p_155919_.progress;
|
||
|
if (p_155919_.progressO >= 1.0F) {
|
||
|
if (p_155916_.isClientSide && p_155919_.deathTicks < 5) {
|
||
|
p_155919_.deathTicks++;
|
||
|
} else {
|
||
|
p_155916_.removeBlockEntity(p_155917_);
|
||
|
p_155919_.setRemoved();
|
||
|
if (p_155916_.getBlockState(p_155917_).is(Blocks.MOVING_PISTON)) {
|
||
|
BlockState blockstate = Block.updateFromNeighbourShapes(p_155919_.movedState, p_155916_, p_155917_);
|
||
|
if (blockstate.isAir()) {
|
||
|
p_155916_.setBlock(p_155917_, p_155919_.movedState, 340);
|
||
|
Block.updateOrDestroy(p_155919_.movedState, blockstate, p_155916_, p_155917_, 3);
|
||
|
} else {
|
||
|
if (blockstate.hasProperty(BlockStateProperties.WATERLOGGED) && blockstate.getValue(BlockStateProperties.WATERLOGGED)) {
|
||
|
blockstate = blockstate.setValue(BlockStateProperties.WATERLOGGED, false);
|
||
|
}
|
||
|
|
||
|
p_155916_.setBlock(p_155917_, blockstate, 67);
|
||
|
p_155916_.neighborChanged(p_155917_, blockstate.getBlock(), ExperimentalRedstoneUtils.initialOrientation(p_155916_, p_155919_.getPushDirection(), null));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
float f = p_155919_.progress + 0.5F;
|
||
|
moveCollidedEntities(p_155916_, p_155917_, f, p_155919_);
|
||
|
moveStuckEntities(p_155916_, p_155917_, f, p_155919_);
|
||
|
p_155919_.progress = f;
|
||
|
if (p_155919_.progress >= 1.0F) {
|
||
|
p_155919_.progress = 1.0F;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected void loadAdditional(CompoundTag p_333735_, HolderLookup.Provider p_332716_) {
|
||
|
super.loadAdditional(p_333735_, p_332716_);
|
||
|
RegistryOps<Tag> registryops = p_332716_.createSerializationContext(NbtOps.INSTANCE);
|
||
|
this.movedState = p_333735_.read("blockState", BlockState.CODEC, registryops).orElse(DEFAULT_BLOCK_STATE);
|
||
|
this.direction = p_333735_.read("facing", Direction.LEGACY_ID_CODEC).orElse(Direction.DOWN);
|
||
|
this.progress = p_333735_.getFloatOr("progress", 0.0F);
|
||
|
this.progressO = this.progress;
|
||
|
this.extending = p_333735_.getBooleanOr("extending", false);
|
||
|
this.isSourcePiston = p_333735_.getBooleanOr("source", false);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected void saveAdditional(CompoundTag p_187530_, HolderLookup.Provider p_331280_) {
|
||
|
super.saveAdditional(p_187530_, p_331280_);
|
||
|
RegistryOps<Tag> registryops = p_331280_.createSerializationContext(NbtOps.INSTANCE);
|
||
|
p_187530_.store("blockState", BlockState.CODEC, registryops, this.movedState);
|
||
|
p_187530_.store("facing", Direction.LEGACY_ID_CODEC, this.direction);
|
||
|
p_187530_.putFloat("progress", this.progressO);
|
||
|
p_187530_.putBoolean("extending", this.extending);
|
||
|
p_187530_.putBoolean("source", this.isSourcePiston);
|
||
|
}
|
||
|
|
||
|
public VoxelShape getCollisionShape(BlockGetter p_60357_, BlockPos p_60358_) {
|
||
|
VoxelShape voxelshape;
|
||
|
if (!this.extending && this.isSourcePiston && this.movedState.getBlock() instanceof PistonBaseBlock) {
|
||
|
voxelshape = this.movedState.setValue(PistonBaseBlock.EXTENDED, true).getCollisionShape(p_60357_, p_60358_);
|
||
|
} else {
|
||
|
voxelshape = Shapes.empty();
|
||
|
}
|
||
|
|
||
|
Direction direction = NOCLIP.get();
|
||
|
if (this.progress < 1.0 && direction == this.getMovementDirection()) {
|
||
|
return voxelshape;
|
||
|
} else {
|
||
|
BlockState blockstate;
|
||
|
if (this.isSourcePiston()) {
|
||
|
blockstate = Blocks.PISTON_HEAD
|
||
|
.defaultBlockState()
|
||
|
.setValue(PistonHeadBlock.FACING, this.direction)
|
||
|
.setValue(PistonHeadBlock.SHORT, this.extending != 1.0F - this.progress < 0.25F);
|
||
|
} else {
|
||
|
blockstate = this.movedState;
|
||
|
}
|
||
|
|
||
|
float f = this.getExtendedProgress(this.progress);
|
||
|
double d0 = this.direction.getStepX() * f;
|
||
|
double d1 = this.direction.getStepY() * f;
|
||
|
double d2 = this.direction.getStepZ() * f;
|
||
|
return Shapes.or(voxelshape, blockstate.getCollisionShape(p_60357_, p_60358_).move(d0, d1, d2));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public long getLastTicked() {
|
||
|
return this.lastTicked;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setLevel(Level p_250671_) {
|
||
|
super.setLevel(p_250671_);
|
||
|
if (p_250671_.holderLookup(Registries.BLOCK).get(this.movedState.getBlock().builtInRegistryHolder().key()).isEmpty()) {
|
||
|
this.movedState = Blocks.AIR.defaultBlockState();
|
||
|
}
|
||
|
}
|
||
|
}
|