345 lines
16 KiB
Java
345 lines
16 KiB
Java
package net.minecraft.world.level.block;
|
|
|
|
import net.minecraft.world.level.block.state.AbstractStateHolder;
|
|
import net.minecraft.world.phys.shapes.Shapes;
|
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
|
import net.minecraft.world.level.pathfinder.PathComputationType;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.level.block.entity.BedBlockEntity;
|
|
import net.minecraft.world.level.block.state.StateDefinition;
|
|
import net.minecraft.world.level.material.PushReaction;
|
|
import java.util.Optional;
|
|
import net.minecraft.world.level.LevelReader;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
|
import net.minecraft.world.item.BlockPlaceContext;
|
|
import net.minecraft.stats.Stat;
|
|
import net.minecraft.stats.Stats;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
|
import net.minecraft.world.level.LevelAccessor;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import java.util.List;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.phys.AABB;
|
|
import net.minecraft.world.entity.npc.Villager;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.network.chat.TranslatableComponent;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.level.Explosion;
|
|
import net.minecraft.world.damagesource.DamageSource;
|
|
import net.minecraft.world.level.biome.Biomes;
|
|
import net.minecraft.world.InteractionResult;
|
|
import net.minecraft.world.phys.BlockHitResult;
|
|
import net.minecraft.world.InteractionHand;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.level.Level;
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.world.level.material.MaterialColor;
|
|
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.item.DyeColor;
|
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
|
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
|
import net.minecraft.world.level.block.state.properties.BedPart;
|
|
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
|
|
|
public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock {
|
|
public static final EnumProperty<BedPart> PART;
|
|
public static final BooleanProperty OCCUPIED;
|
|
protected static final VoxelShape BASE;
|
|
protected static final VoxelShape LEG_NORTH_WEST;
|
|
protected static final VoxelShape LEG_SOUTH_WEST;
|
|
protected static final VoxelShape LEG_NORTH_EAST;
|
|
protected static final VoxelShape LEG_SOUTH_EAST;
|
|
protected static final VoxelShape NORTH_SHAPE;
|
|
protected static final VoxelShape SOUTH_SHAPE;
|
|
protected static final VoxelShape WEST_SHAPE;
|
|
protected static final VoxelShape EAST_SHAPE;
|
|
private final DyeColor color;
|
|
|
|
public BedBlock(final DyeColor bdg, final Properties c) {
|
|
super(c);
|
|
this.color = bdg;
|
|
this.registerDefaultState((((AbstractStateHolder<O, BlockState>)this.stateDefinition.any()).setValue(BedBlock.PART, BedPart.FOOT)).<Comparable, Boolean>setValue((Property<Comparable>)BedBlock.OCCUPIED, false));
|
|
}
|
|
|
|
@Override
|
|
public MaterialColor getMapColor(final BlockState byg, final BlockGetter bjd, final BlockPos fk) {
|
|
if (byg.<BedPart>getValue(BedBlock.PART) == BedPart.FOOT) {
|
|
return this.color.getMaterialColor();
|
|
}
|
|
return MaterialColor.WOOL;
|
|
}
|
|
|
|
@Nullable
|
|
public static Direction getBedOrientation(final BlockGetter bjd, final BlockPos fk) {
|
|
final BlockState byg3 = bjd.getBlockState(fk);
|
|
return (byg3.getBlock() instanceof BedBlock) ? byg3.<Direction>getValue((Property<Direction>)BedBlock.FACING) : null;
|
|
}
|
|
|
|
@Override
|
|
public InteractionResult use(BlockState byg, final Level bjt, BlockPos fk, final Player ayg, final InteractionHand ajh, final BlockHitResult cvd) {
|
|
if (bjt.isClientSide) {
|
|
return InteractionResult.CONSUME;
|
|
}
|
|
if (byg.<BedPart>getValue(BedBlock.PART) != BedPart.HEAD) {
|
|
fk = fk.relative(byg.<Direction>getValue((Property<Direction>)BedBlock.FACING));
|
|
byg = bjt.getBlockState(fk);
|
|
if (byg.getBlock() != this) {
|
|
return InteractionResult.CONSUME;
|
|
}
|
|
}
|
|
if (!bjt.dimension.mayRespawn() || bjt.getBiome(fk) == Biomes.NETHER) {
|
|
bjt.removeBlock(fk, false);
|
|
final BlockPos fk2 = fk.relative(byg.<Direction>getValue((Property<Direction>)BedBlock.FACING).getOpposite());
|
|
if (bjt.getBlockState(fk2).getBlock() == this) {
|
|
bjt.removeBlock(fk2, false);
|
|
}
|
|
bjt.explode(null, DamageSource.netherBedExplosion(), fk.getX() + 0.5, fk.getY() + 0.5, fk.getZ() + 0.5, 5.0f, true, Explosion.BlockInteraction.DESTROY);
|
|
return InteractionResult.SUCCESS;
|
|
}
|
|
if (byg.<Boolean>getValue((Property<Boolean>)BedBlock.OCCUPIED)) {
|
|
if (!this.kickVillagerOutOfBed(bjt, fk)) {
|
|
ayg.displayClientMessage(new TranslatableComponent("block.minecraft.bed.occupied", new Object[0]), true);
|
|
}
|
|
return InteractionResult.SUCCESS;
|
|
}
|
|
ayg.startSleepInBed(fk).ifLeft(a -> {
|
|
if (a != null) {
|
|
ayg.displayClientMessage(a.getMessage(), true);
|
|
}
|
|
return;
|
|
});
|
|
return InteractionResult.SUCCESS;
|
|
}
|
|
|
|
private boolean kickVillagerOutOfBed(final Level bjt, final BlockPos fk) {
|
|
final List<Villager> list4 = bjt.<Villager>getEntitiesOfClass(Villager.class, new AABB(fk), LivingEntity::isSleeping);
|
|
if (list4.isEmpty()) {
|
|
return false;
|
|
}
|
|
list4.get(0).stopSleeping();
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void fallOn(final Level bjt, final BlockPos fk, final Entity akn, final float float4) {
|
|
super.fallOn(bjt, fk, akn, float4 * 0.5f);
|
|
}
|
|
|
|
@Override
|
|
public void updateEntityAfterFallOn(final BlockGetter bjd, final Entity akn) {
|
|
if (akn.isSuppressingBounce()) {
|
|
super.updateEntityAfterFallOn(bjd, akn);
|
|
}
|
|
else {
|
|
this.bounceUp(akn);
|
|
}
|
|
}
|
|
|
|
private void bounceUp(final Entity akn) {
|
|
final Vec3 cvi3 = akn.getDeltaMovement();
|
|
if (cvi3.y < 0.0) {
|
|
final double double4 = (akn instanceof LivingEntity) ? 1.0 : 0.8;
|
|
akn.setDeltaMovement(cvi3.x, -cvi3.y * 0.6600000262260437 * double4, cvi3.z);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public BlockState updateShape(final BlockState byg1, final Direction fp, final BlockState byg3, final LevelAccessor bju, final BlockPos fk5, final BlockPos fk6) {
|
|
if (fp != getNeighbourDirection(byg1.<BedPart>getValue(BedBlock.PART), byg1.<Direction>getValue((Property<Direction>)BedBlock.FACING))) {
|
|
return super.updateShape(byg1, fp, byg3, bju, fk5, fk6);
|
|
}
|
|
if (byg3.getBlock() == this && byg3.<BedPart>getValue(BedBlock.PART) != byg1.<BedPart>getValue(BedBlock.PART)) {
|
|
return ((AbstractStateHolder<O, BlockState>)byg1).<Comparable, Comparable>setValue((Property<Comparable>)BedBlock.OCCUPIED, (Comparable)byg3.<V>getValue((Property<V>)BedBlock.OCCUPIED));
|
|
}
|
|
return Blocks.AIR.defaultBlockState();
|
|
}
|
|
|
|
private static Direction getNeighbourDirection(final BedPart byv, final Direction fp) {
|
|
return (byv == BedPart.FOOT) ? fp : fp.getOpposite();
|
|
}
|
|
|
|
@Override
|
|
public void playerDestroy(final Level bjt, final Player ayg, final BlockPos fk, final BlockState byg, @Nullable final BlockEntity bwi, final ItemStack bek) {
|
|
super.playerDestroy(bjt, ayg, fk, Blocks.AIR.defaultBlockState(), bwi, bek);
|
|
}
|
|
|
|
@Override
|
|
public void playerWillDestroy(final Level bjt, final BlockPos fk, final BlockState byg, final Player ayg) {
|
|
final BedPart byv6 = byg.<BedPart>getValue(BedBlock.PART);
|
|
final BlockPos fk2 = fk.relative(getNeighbourDirection(byv6, byg.<Direction>getValue((Property<Direction>)BedBlock.FACING)));
|
|
final BlockState byg2 = bjt.getBlockState(fk2);
|
|
if (byg2.getBlock() == this && byg2.<BedPart>getValue(BedBlock.PART) != byv6) {
|
|
bjt.setBlock(fk2, Blocks.AIR.defaultBlockState(), 35);
|
|
bjt.levelEvent(ayg, 2001, fk2, Block.getId(byg2));
|
|
if (!bjt.isClientSide && !ayg.isCreative()) {
|
|
final ItemStack bek9 = ayg.getMainHandItem();
|
|
Block.dropResources(byg, bjt, fk, null, ayg, bek9);
|
|
Block.dropResources(byg2, bjt, fk2, null, ayg, bek9);
|
|
}
|
|
ayg.awardStat(Stats.BLOCK_MINED.get(this));
|
|
}
|
|
super.playerWillDestroy(bjt, fk, byg, ayg);
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public BlockState getStateForPlacement(final BlockPlaceContext bcn) {
|
|
final Direction fp3 = bcn.getHorizontalDirection();
|
|
final BlockPos fk4 = bcn.getClickedPos();
|
|
final BlockPos fk5 = fk4.relative(fp3);
|
|
if (bcn.getLevel().getBlockState(fk5).canBeReplaced(bcn)) {
|
|
return ((AbstractStateHolder<O, BlockState>)this.defaultBlockState()).<Comparable, Direction>setValue((Property<Comparable>)BedBlock.FACING, fp3);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public VoxelShape getShape(final BlockState byg, final BlockGetter bjd, final BlockPos fk, final CollisionContext cvn) {
|
|
final Direction fp6 = getConnectedDirection(byg).getOpposite();
|
|
switch (fp6) {
|
|
case NORTH: {
|
|
return BedBlock.NORTH_SHAPE;
|
|
}
|
|
case SOUTH: {
|
|
return BedBlock.SOUTH_SHAPE;
|
|
}
|
|
case WEST: {
|
|
return BedBlock.WEST_SHAPE;
|
|
}
|
|
default: {
|
|
return BedBlock.EAST_SHAPE;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static Direction getConnectedDirection(final BlockState byg) {
|
|
final Direction fp2 = byg.<Direction>getValue((Property<Direction>)BedBlock.FACING);
|
|
return (byg.<BedPart>getValue(BedBlock.PART) == BedPart.HEAD) ? fp2.getOpposite() : fp2;
|
|
}
|
|
|
|
public static DoubleBlockCombiner.BlockType getBlockType(final BlockState byg) {
|
|
final BedPart byv2 = byg.<BedPart>getValue(BedBlock.PART);
|
|
if (byv2 == BedPart.HEAD) {
|
|
return DoubleBlockCombiner.BlockType.FIRST;
|
|
}
|
|
return DoubleBlockCombiner.BlockType.SECOND;
|
|
}
|
|
|
|
public static Optional<Vec3> findStandUpPosition(final EntityType<?> akr, final LevelReader bjw, final BlockPos fk, int integer) {
|
|
final Direction fp5 = bjw.getBlockState(fk).<Direction>getValue((Property<Direction>)BedBlock.FACING);
|
|
final int integer2 = fk.getX();
|
|
final int integer3 = fk.getY();
|
|
final int integer4 = fk.getZ();
|
|
for (int integer5 = 0; integer5 <= 1; ++integer5) {
|
|
final int integer6 = integer2 - fp5.getStepX() * integer5 - 1;
|
|
final int integer7 = integer4 - fp5.getStepZ() * integer5 - 1;
|
|
final int integer8 = integer6 + 2;
|
|
final int integer9 = integer7 + 2;
|
|
for (int integer10 = integer6; integer10 <= integer8; ++integer10) {
|
|
for (int integer11 = integer7; integer11 <= integer9; ++integer11) {
|
|
final BlockPos fk2 = new BlockPos(integer10, integer3, integer11);
|
|
final Optional<Vec3> optional17 = getStandingLocationAtOrBelow(akr, bjw, fk2);
|
|
if (optional17.isPresent()) {
|
|
if (integer <= 0) {
|
|
return optional17;
|
|
}
|
|
--integer;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Optional.<Vec3>empty();
|
|
}
|
|
|
|
protected static Optional<Vec3> getStandingLocationAtOrBelow(final EntityType<?> akr, final LevelReader bjw, final BlockPos fk) {
|
|
final VoxelShape cwc4 = bjw.getBlockState(fk).getCollisionShape(bjw, fk);
|
|
if (cwc4.max(Direction.Axis.Y) > 0.4375) {
|
|
return Optional.<Vec3>empty();
|
|
}
|
|
final BlockPos.MutableBlockPos a5 = new BlockPos.MutableBlockPos(fk);
|
|
while (a5.getY() >= 0 && fk.getY() - a5.getY() <= 2 && bjw.getBlockState(a5).getCollisionShape(bjw, a5).isEmpty()) {
|
|
a5.move(Direction.DOWN);
|
|
}
|
|
final VoxelShape cwc5 = bjw.getBlockState(a5).getCollisionShape(bjw, a5);
|
|
if (cwc5.isEmpty()) {
|
|
return Optional.<Vec3>empty();
|
|
}
|
|
final double double7 = a5.getY() + cwc5.max(Direction.Axis.Y) + 2.0E-7;
|
|
if (fk.getY() - double7 > 2.0) {
|
|
return Optional.<Vec3>empty();
|
|
}
|
|
final float float9 = akr.getWidth() / 2.0f;
|
|
final Vec3 cvi10 = new Vec3(a5.getX() + 0.5, double7, a5.getZ() + 0.5);
|
|
if (bjw.noCollision(new AABB(cvi10.x - float9, cvi10.y, cvi10.z - float9, cvi10.x + float9, cvi10.y + akr.getHeight(), cvi10.z + float9))) {
|
|
return Optional.<Vec3>of(cvi10);
|
|
}
|
|
return Optional.<Vec3>empty();
|
|
}
|
|
|
|
@Override
|
|
public PushReaction getPistonPushReaction(final BlockState byg) {
|
|
return PushReaction.DESTROY;
|
|
}
|
|
|
|
@Override
|
|
public RenderShape getRenderShape(final BlockState byg) {
|
|
return RenderShape.ENTITYBLOCK_ANIMATED;
|
|
}
|
|
|
|
@Override
|
|
protected void createBlockStateDefinition(final StateDefinition.Builder<Block, BlockState> a) {
|
|
a.add(BedBlock.FACING, BedBlock.PART, BedBlock.OCCUPIED);
|
|
}
|
|
|
|
@Override
|
|
public BlockEntity newBlockEntity(final BlockGetter bjd) {
|
|
return new BedBlockEntity(this.color);
|
|
}
|
|
|
|
@Override
|
|
public void setPlacedBy(final Level bjt, final BlockPos fk, final BlockState byg, @Nullable final LivingEntity akw, final ItemStack bek) {
|
|
super.setPlacedBy(bjt, fk, byg, akw, bek);
|
|
if (!bjt.isClientSide) {
|
|
final BlockPos fk2 = fk.relative(byg.<Direction>getValue((Property<Direction>)BedBlock.FACING));
|
|
bjt.setBlock(fk2, ((AbstractStateHolder<O, BlockState>)byg).<BedPart, BedPart>setValue(BedBlock.PART, BedPart.HEAD), 3);
|
|
bjt.blockUpdated(fk, Blocks.AIR);
|
|
byg.updateNeighbourShapes(bjt, fk, 3);
|
|
}
|
|
}
|
|
|
|
public DyeColor getColor() {
|
|
return this.color;
|
|
}
|
|
|
|
@Override
|
|
public long getSeed(final BlockState byg, final BlockPos fk) {
|
|
final BlockPos fk2 = fk.relative((Direction)byg.<Direction>getValue((Property<Direction>)BedBlock.FACING), (int)((byg.<BedPart>getValue(BedBlock.PART) != BedPart.HEAD) ? 1 : 0));
|
|
return Mth.getSeed(fk2.getX(), fk.getY(), fk2.getZ());
|
|
}
|
|
|
|
@Override
|
|
public boolean isPathfindable(final BlockState byg, final BlockGetter bjd, final BlockPos fk, final PathComputationType cqo) {
|
|
return false;
|
|
}
|
|
|
|
static {
|
|
PART = BlockStateProperties.BED_PART;
|
|
OCCUPIED = BlockStateProperties.OCCUPIED;
|
|
BASE = Block.box(0.0, 3.0, 0.0, 16.0, 9.0, 16.0);
|
|
LEG_NORTH_WEST = Block.box(0.0, 0.0, 0.0, 3.0, 3.0, 3.0);
|
|
LEG_SOUTH_WEST = Block.box(0.0, 0.0, 13.0, 3.0, 3.0, 16.0);
|
|
LEG_NORTH_EAST = Block.box(13.0, 0.0, 0.0, 16.0, 3.0, 3.0);
|
|
LEG_SOUTH_EAST = Block.box(13.0, 0.0, 13.0, 16.0, 3.0, 16.0);
|
|
NORTH_SHAPE = Shapes.or(BedBlock.BASE, BedBlock.LEG_NORTH_WEST, BedBlock.LEG_NORTH_EAST);
|
|
SOUTH_SHAPE = Shapes.or(BedBlock.BASE, BedBlock.LEG_SOUTH_WEST, BedBlock.LEG_SOUTH_EAST);
|
|
WEST_SHAPE = Shapes.or(BedBlock.BASE, BedBlock.LEG_NORTH_WEST, BedBlock.LEG_SOUTH_WEST);
|
|
EAST_SHAPE = Shapes.or(BedBlock.BASE, BedBlock.LEG_NORTH_EAST, BedBlock.LEG_SOUTH_EAST);
|
|
}
|
|
}
|