347 lines
15 KiB
Java
347 lines
15 KiB
Java
package net.minecraft.world.level.block;
|
|
|
|
import net.minecraft.world.level.block.state.AbstractStateHolder;
|
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
|
import net.minecraft.world.level.block.state.pattern.BlockInWorld;
|
|
import com.google.common.cache.LoadingCache;
|
|
import net.minecraft.world.level.LevelReader;
|
|
import net.minecraft.world.level.block.state.pattern.BlockPattern;
|
|
import net.minecraft.world.level.block.state.StateDefinition;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.core.particles.ParticleOptions;
|
|
import net.minecraft.core.particles.ParticleTypes;
|
|
import net.minecraft.sounds.SoundSource;
|
|
import net.minecraft.sounds.SoundEvents;
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.world.level.LevelAccessor;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.entity.MobSpawnType;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.level.GameRules;
|
|
import java.util.Random;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.world.level.BlockGetter;
|
|
import net.minecraft.world.level.block.state.properties.Property;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
|
|
|
public class NetherPortalBlock extends Block {
|
|
public static final EnumProperty<Direction.Axis> AXIS;
|
|
protected static final VoxelShape X_AXIS_AABB;
|
|
protected static final VoxelShape Z_AXIS_AABB;
|
|
|
|
public NetherPortalBlock(final Properties c) {
|
|
super(c);
|
|
this.registerDefaultState(((AbstractStateHolder<O, BlockState>)this.stateDefinition.any()).<Direction.Axis, Direction.Axis>setValue(NetherPortalBlock.AXIS, Direction.Axis.X));
|
|
}
|
|
|
|
@Override
|
|
public VoxelShape getShape(final BlockState byg, final BlockGetter bjd, final BlockPos fk, final CollisionContext cvn) {
|
|
switch (byg.<Direction.Axis>getValue(NetherPortalBlock.AXIS)) {
|
|
case Z: {
|
|
return NetherPortalBlock.Z_AXIS_AABB;
|
|
}
|
|
default: {
|
|
return NetherPortalBlock.X_AXIS_AABB;
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void tick(final BlockState byg, final ServerLevel xd, BlockPos fk, final Random random) {
|
|
if (xd.dimension.isNaturalDimension() && xd.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && random.nextInt(2000) < xd.getDifficulty().getId()) {
|
|
while (xd.getBlockState(fk).getBlock() == this) {
|
|
fk = fk.below();
|
|
}
|
|
if (xd.getBlockState(fk).isValidSpawn(xd, fk, EntityType.ZOMBIE_PIGMAN)) {
|
|
final Entity akn6 = EntityType.ZOMBIE_PIGMAN.spawn(xd, null, null, null, fk.above(), MobSpawnType.STRUCTURE, false, false);
|
|
if (akn6 != null) {
|
|
akn6.changingDimensionDelay = akn6.getDimensionChangingDelay();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean trySpawnPortal(final LevelAccessor bju, final BlockPos fk) {
|
|
final PortalShape a4 = this.isPortal(bju, fk);
|
|
if (a4 != null) {
|
|
a4.createPortalBlocks();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Nullable
|
|
public PortalShape isPortal(final LevelAccessor bju, final BlockPos fk) {
|
|
final PortalShape a4 = new PortalShape(bju, fk, Direction.Axis.X);
|
|
if (a4.isValid() && a4.numPortalBlocks == 0) {
|
|
return a4;
|
|
}
|
|
final PortalShape a5 = new PortalShape(bju, fk, Direction.Axis.Z);
|
|
if (a5.isValid() && a5.numPortalBlocks == 0) {
|
|
return a5;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public BlockState updateShape(final BlockState byg1, final Direction fp, final BlockState byg3, final LevelAccessor bju, final BlockPos fk5, final BlockPos fk6) {
|
|
final Direction.Axis a8 = fp.getAxis();
|
|
final Direction.Axis a9 = byg1.<Direction.Axis>getValue(NetherPortalBlock.AXIS);
|
|
final boolean boolean10 = a9 != a8 && a8.isHorizontal();
|
|
if (boolean10 || byg3.getBlock() == this || new PortalShape(bju, fk5, a9).isComplete()) {
|
|
return super.updateShape(byg1, fp, byg3, bju, fk5, fk6);
|
|
}
|
|
return Blocks.AIR.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public void entityInside(final BlockState byg, final Level bjt, final BlockPos fk, final Entity akn) {
|
|
if (!akn.isPassenger() && !akn.isVehicle() && akn.canChangeDimensions()) {
|
|
akn.handleInsidePortal(fk);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void animateTick(final BlockState byg, final Level bjt, final BlockPos fk, final Random random) {
|
|
if (random.nextInt(100) == 0) {
|
|
bjt.playLocalSound(fk.getX() + 0.5, fk.getY() + 0.5, fk.getZ() + 0.5, SoundEvents.PORTAL_AMBIENT, SoundSource.BLOCKS, 0.5f, random.nextFloat() * 0.4f + 0.8f, false);
|
|
}
|
|
for (int integer6 = 0; integer6 < 4; ++integer6) {
|
|
double double7 = fk.getX() + (double)random.nextFloat();
|
|
final double double8 = fk.getY() + (double)random.nextFloat();
|
|
double double9 = fk.getZ() + (double)random.nextFloat();
|
|
double double10 = (random.nextFloat() - 0.5) * 0.5;
|
|
final double double11 = (random.nextFloat() - 0.5) * 0.5;
|
|
double double12 = (random.nextFloat() - 0.5) * 0.5;
|
|
final int integer7 = random.nextInt(2) * 2 - 1;
|
|
if (bjt.getBlockState(fk.west()).getBlock() == this || bjt.getBlockState(fk.east()).getBlock() == this) {
|
|
double9 = fk.getZ() + 0.5 + 0.25 * integer7;
|
|
double12 = random.nextFloat() * 2.0f * integer7;
|
|
}
|
|
else {
|
|
double7 = fk.getX() + 0.5 + 0.25 * integer7;
|
|
double10 = random.nextFloat() * 2.0f * integer7;
|
|
}
|
|
bjt.addParticle(ParticleTypes.PORTAL, double7, double8, double9, double10, double11, double12);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public ItemStack getCloneItemStack(final BlockGetter bjd, final BlockPos fk, final BlockState byg) {
|
|
return ItemStack.EMPTY;
|
|
}
|
|
|
|
@Override
|
|
public BlockState rotate(final BlockState byg, final Rotation btr) {
|
|
switch (btr) {
|
|
case COUNTERCLOCKWISE_90:
|
|
case CLOCKWISE_90: {
|
|
switch (byg.<Direction.Axis>getValue(NetherPortalBlock.AXIS)) {
|
|
case X: {
|
|
return ((AbstractStateHolder<O, BlockState>)byg).<Direction.Axis, Direction.Axis>setValue(NetherPortalBlock.AXIS, Direction.Axis.Z);
|
|
}
|
|
case Z: {
|
|
return ((AbstractStateHolder<O, BlockState>)byg).<Direction.Axis, Direction.Axis>setValue(NetherPortalBlock.AXIS, Direction.Axis.X);
|
|
}
|
|
default: {
|
|
return byg;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
return byg;
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void createBlockStateDefinition(final StateDefinition.Builder<Block, BlockState> a) {
|
|
a.add(NetherPortalBlock.AXIS);
|
|
}
|
|
|
|
public static BlockPattern.BlockPatternMatch getPortalShape(final LevelAccessor bju, final BlockPos fk) {
|
|
Direction.Axis a3 = Direction.Axis.Z;
|
|
PortalShape a4 = new PortalShape(bju, fk, Direction.Axis.X);
|
|
final LoadingCache<BlockPos, BlockInWorld> loadingCache5 = BlockPattern.createLevelCache(bju, true);
|
|
if (!a4.isValid()) {
|
|
a3 = Direction.Axis.X;
|
|
a4 = new PortalShape(bju, fk, Direction.Axis.Z);
|
|
}
|
|
if (!a4.isValid()) {
|
|
return new BlockPattern.BlockPatternMatch(fk, Direction.NORTH, Direction.UP, loadingCache5, 1, 1, 1);
|
|
}
|
|
final int[] arr6 = new int[Direction.AxisDirection.values().length];
|
|
final Direction fp7 = a4.rightDir.getCounterClockWise();
|
|
final BlockPos fk2 = a4.bottomLeft.above(a4.getHeight() - 1);
|
|
for (final Direction.AxisDirection b12 : Direction.AxisDirection.values()) {
|
|
final BlockPattern.BlockPatternMatch b13 = new BlockPattern.BlockPatternMatch((fp7.getAxisDirection() == b12) ? fk2 : fk2.relative(a4.rightDir, a4.getWidth() - 1), Direction.get(b12, a3), Direction.UP, loadingCache5, a4.getWidth(), a4.getHeight(), 1);
|
|
for (int integer14 = 0; integer14 < a4.getWidth(); ++integer14) {
|
|
for (int integer15 = 0; integer15 < a4.getHeight(); ++integer15) {
|
|
final BlockInWorld byk16 = b13.getBlock(integer14, integer15, 1);
|
|
if (!byk16.getState().isAir()) {
|
|
final int[] array = arr6;
|
|
final int ordinal = b12.ordinal();
|
|
++array[ordinal];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Direction.AxisDirection b14 = Direction.AxisDirection.POSITIVE;
|
|
for (final Direction.AxisDirection b15 : Direction.AxisDirection.values()) {
|
|
if (arr6[b15.ordinal()] < arr6[b14.ordinal()]) {
|
|
b14 = b15;
|
|
}
|
|
}
|
|
return new BlockPattern.BlockPatternMatch((fp7.getAxisDirection() == b14) ? fk2 : fk2.relative(a4.rightDir, a4.getWidth() - 1), Direction.get(b14, a3), Direction.UP, loadingCache5, a4.getWidth(), a4.getHeight(), 1);
|
|
}
|
|
|
|
static {
|
|
AXIS = BlockStateProperties.HORIZONTAL_AXIS;
|
|
X_AXIS_AABB = Block.box(0.0, 0.0, 6.0, 16.0, 16.0, 10.0);
|
|
Z_AXIS_AABB = Block.box(6.0, 0.0, 0.0, 10.0, 16.0, 16.0);
|
|
}
|
|
|
|
public static class PortalShape {
|
|
private final LevelAccessor level;
|
|
private final Direction.Axis axis;
|
|
private final Direction rightDir;
|
|
private final Direction leftDir;
|
|
private int numPortalBlocks;
|
|
@Nullable
|
|
private BlockPos bottomLeft;
|
|
private int height;
|
|
private int width;
|
|
|
|
public PortalShape(final LevelAccessor bju, BlockPos fk, final Direction.Axis a) {
|
|
this.level = bju;
|
|
this.axis = a;
|
|
if (a == Direction.Axis.X) {
|
|
this.leftDir = Direction.EAST;
|
|
this.rightDir = Direction.WEST;
|
|
}
|
|
else {
|
|
this.leftDir = Direction.NORTH;
|
|
this.rightDir = Direction.SOUTH;
|
|
}
|
|
for (BlockPos fk2 = fk; fk.getY() > fk2.getY() - 21 && fk.getY() > 0 && this.isEmpty(bju.getBlockState(fk.below())); fk = fk.below()) {}
|
|
final int integer6 = this.getDistanceUntilEdge(fk, this.leftDir) - 1;
|
|
if (integer6 >= 0) {
|
|
this.bottomLeft = fk.relative(this.leftDir, integer6);
|
|
this.width = this.getDistanceUntilEdge(this.bottomLeft, this.rightDir);
|
|
if (this.width < 2 || this.width > 21) {
|
|
this.bottomLeft = null;
|
|
this.width = 0;
|
|
}
|
|
}
|
|
if (this.bottomLeft != null) {
|
|
this.height = this.calculatePortalHeight();
|
|
}
|
|
}
|
|
|
|
protected int getDistanceUntilEdge(final BlockPos fk, final Direction fp) {
|
|
int integer4;
|
|
for (integer4 = 0; integer4 < 22; ++integer4) {
|
|
final BlockPos fk2 = fk.relative(fp, integer4);
|
|
if (!this.isEmpty(this.level.getBlockState(fk2))) {
|
|
break;
|
|
}
|
|
if (this.level.getBlockState(fk2.below()).getBlock() != Blocks.OBSIDIAN) {
|
|
break;
|
|
}
|
|
}
|
|
final Block bpe5 = this.level.getBlockState(fk.relative(fp, integer4)).getBlock();
|
|
if (bpe5 == Blocks.OBSIDIAN) {
|
|
return integer4;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public int getHeight() {
|
|
return this.height;
|
|
}
|
|
|
|
public int getWidth() {
|
|
return this.width;
|
|
}
|
|
|
|
protected int calculatePortalHeight() {
|
|
this.height = 0;
|
|
Label_0189:
|
|
while (this.height < 21) {
|
|
for (int integer2 = 0; integer2 < this.width; ++integer2) {
|
|
final BlockPos fk3 = this.bottomLeft.relative(this.rightDir, integer2).above(this.height);
|
|
final BlockState byg4 = this.level.getBlockState(fk3);
|
|
if (!this.isEmpty(byg4)) {
|
|
break Label_0189;
|
|
}
|
|
Block bpe5 = byg4.getBlock();
|
|
if (bpe5 == Blocks.NETHER_PORTAL) {
|
|
++this.numPortalBlocks;
|
|
}
|
|
if (integer2 == 0) {
|
|
bpe5 = this.level.getBlockState(fk3.relative(this.leftDir)).getBlock();
|
|
if (bpe5 != Blocks.OBSIDIAN) {
|
|
break Label_0189;
|
|
}
|
|
}
|
|
else if (integer2 == this.width - 1) {
|
|
bpe5 = this.level.getBlockState(fk3.relative(this.rightDir)).getBlock();
|
|
if (bpe5 != Blocks.OBSIDIAN) {
|
|
break Label_0189;
|
|
}
|
|
}
|
|
}
|
|
++this.height;
|
|
}
|
|
for (int integer2 = 0; integer2 < this.width; ++integer2) {
|
|
if (this.level.getBlockState(this.bottomLeft.relative(this.rightDir, integer2).above(this.height)).getBlock() != Blocks.OBSIDIAN) {
|
|
this.height = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (this.height > 21 || this.height < 3) {
|
|
this.bottomLeft = null;
|
|
this.width = 0;
|
|
return this.height = 0;
|
|
}
|
|
return this.height;
|
|
}
|
|
|
|
protected boolean isEmpty(final BlockState byg) {
|
|
final Block bpe3 = byg.getBlock();
|
|
return byg.isAir() || bpe3 == Blocks.FIRE || bpe3 == Blocks.NETHER_PORTAL;
|
|
}
|
|
|
|
public boolean isValid() {
|
|
return this.bottomLeft != null && this.width >= 2 && this.width <= 21 && this.height >= 3 && this.height <= 21;
|
|
}
|
|
|
|
public void createPortalBlocks() {
|
|
for (int integer2 = 0; integer2 < this.width; ++integer2) {
|
|
final BlockPos fk3 = this.bottomLeft.relative(this.rightDir, integer2);
|
|
for (int integer3 = 0; integer3 < this.height; ++integer3) {
|
|
this.level.setBlock(fk3.above(integer3), ((AbstractStateHolder<O, BlockState>)Blocks.NETHER_PORTAL.defaultBlockState()).<Direction.Axis, Direction.Axis>setValue(NetherPortalBlock.AXIS, this.axis), 18);
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean hasAllPortalBlocks() {
|
|
return this.numPortalBlocks >= this.width * this.height;
|
|
}
|
|
|
|
public boolean isComplete() {
|
|
return this.isValid() && this.hasAllPortalBlocks();
|
|
}
|
|
}
|
|
}
|