minecraft-source/src/net/minecraft/world/level/block/NetherPortalBlock.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();
}
}
}