minecraft-src/net/minecraft/world/level/block/piston/PistonStructureResolver.java
2025-07-04 01:41:11 +03:00

208 lines
6.2 KiB
Java

package net.minecraft.world.level.block.piston;
import com.google.common.collect.Lists;
import java.util.List;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.PushReaction;
public class PistonStructureResolver {
public static final int MAX_PUSH_DEPTH = 12;
private final Level level;
private final BlockPos pistonPos;
private final boolean extending;
private final BlockPos startPos;
private final Direction pushDirection;
/**
* All block positions to be moved by the piston
*/
private final List<BlockPos> toPush = Lists.<BlockPos>newArrayList();
/**
* All blocks to be destroyed by the piston
*/
private final List<BlockPos> toDestroy = Lists.<BlockPos>newArrayList();
private final Direction pistonDirection;
public PistonStructureResolver(Level level, BlockPos pistonPos, Direction pistonDirection, boolean extending) {
this.level = level;
this.pistonPos = pistonPos;
this.pistonDirection = pistonDirection;
this.extending = extending;
if (extending) {
this.pushDirection = pistonDirection;
this.startPos = pistonPos.relative(pistonDirection);
} else {
this.pushDirection = pistonDirection.getOpposite();
this.startPos = pistonPos.relative(pistonDirection, 2);
}
}
public boolean resolve() {
this.toPush.clear();
this.toDestroy.clear();
BlockState blockState = this.level.getBlockState(this.startPos);
if (!PistonBaseBlock.isPushable(blockState, this.level, this.startPos, this.pushDirection, false, this.pistonDirection)) {
if (this.extending && blockState.getPistonPushReaction() == PushReaction.DESTROY) {
this.toDestroy.add(this.startPos);
return true;
} else {
return false;
}
} else if (!this.addBlockLine(this.startPos, this.pushDirection)) {
return false;
} else {
for (int i = 0; i < this.toPush.size(); i++) {
BlockPos blockPos = (BlockPos)this.toPush.get(i);
if (isSticky(this.level.getBlockState(blockPos)) && !this.addBranchingBlocks(blockPos)) {
return false;
}
}
return true;
}
}
private static boolean isSticky(BlockState state) {
return state.is(Blocks.SLIME_BLOCK) || state.is(Blocks.HONEY_BLOCK);
}
private static boolean canStickToEachOther(BlockState state1, BlockState state2) {
if (state1.is(Blocks.HONEY_BLOCK) && state2.is(Blocks.SLIME_BLOCK)) {
return false;
} else {
return state1.is(Blocks.SLIME_BLOCK) && state2.is(Blocks.HONEY_BLOCK) ? false : isSticky(state1) || isSticky(state2);
}
}
private boolean addBlockLine(BlockPos originPos, Direction direction) {
BlockState blockState = this.level.getBlockState(originPos);
if (blockState.isAir()) {
return true;
} else if (!PistonBaseBlock.isPushable(blockState, this.level, originPos, this.pushDirection, false, direction)) {
return true;
} else if (originPos.equals(this.pistonPos)) {
return true;
} else if (this.toPush.contains(originPos)) {
return true;
} else {
int i = 1;
if (i + this.toPush.size() > 12) {
return false;
} else {
while (isSticky(blockState)) {
BlockPos blockPos = originPos.relative(this.pushDirection.getOpposite(), i);
BlockState blockState2 = blockState;
blockState = this.level.getBlockState(blockPos);
if (blockState.isAir()
|| !canStickToEachOther(blockState2, blockState)
|| !PistonBaseBlock.isPushable(blockState, this.level, blockPos, this.pushDirection, false, this.pushDirection.getOpposite())
|| blockPos.equals(this.pistonPos)) {
break;
}
if (++i + this.toPush.size() > 12) {
return false;
}
}
int j = 0;
for (int k = i - 1; k >= 0; k--) {
this.toPush.add(originPos.relative(this.pushDirection.getOpposite(), k));
j++;
}
int k = 1;
while (true) {
BlockPos blockPos2 = originPos.relative(this.pushDirection, k);
int l = this.toPush.indexOf(blockPos2);
if (l > -1) {
this.reorderListAtCollision(j, l);
for (int m = 0; m <= l + j; m++) {
BlockPos blockPos3 = (BlockPos)this.toPush.get(m);
if (isSticky(this.level.getBlockState(blockPos3)) && !this.addBranchingBlocks(blockPos3)) {
return false;
}
}
return true;
}
blockState = this.level.getBlockState(blockPos2);
if (blockState.isAir()) {
return true;
}
if (!PistonBaseBlock.isPushable(blockState, this.level, blockPos2, this.pushDirection, true, this.pushDirection) || blockPos2.equals(this.pistonPos)) {
return false;
}
if (blockState.getPistonPushReaction() == PushReaction.DESTROY) {
this.toDestroy.add(blockPos2);
return true;
}
if (this.toPush.size() >= 12) {
return false;
}
this.toPush.add(blockPos2);
j++;
k++;
}
}
}
}
private void reorderListAtCollision(int offsets, int index) {
List<BlockPos> list = Lists.<BlockPos>newArrayList();
List<BlockPos> list2 = Lists.<BlockPos>newArrayList();
List<BlockPos> list3 = Lists.<BlockPos>newArrayList();
list.addAll(this.toPush.subList(0, index));
list2.addAll(this.toPush.subList(this.toPush.size() - offsets, this.toPush.size()));
list3.addAll(this.toPush.subList(index, this.toPush.size() - offsets));
this.toPush.clear();
this.toPush.addAll(list);
this.toPush.addAll(list2);
this.toPush.addAll(list3);
}
private boolean addBranchingBlocks(BlockPos fromPos) {
BlockState blockState = this.level.getBlockState(fromPos);
for (Direction direction : Direction.values()) {
if (direction.getAxis() != this.pushDirection.getAxis()) {
BlockPos blockPos = fromPos.relative(direction);
BlockState blockState2 = this.level.getBlockState(blockPos);
if (canStickToEachOther(blockState2, blockState) && !this.addBlockLine(blockPos, direction)) {
return false;
}
}
}
return true;
}
public Direction getPushDirection() {
return this.pushDirection;
}
/**
* @return all block positions to be moved by the piston
*/
public List<BlockPos> getToPush() {
return this.toPush;
}
/**
* @return all block positions to be destroyed by the piston
*/
public List<BlockPos> getToDestroy() {
return this.toDestroy;
}
}