--- a/net/minecraft/world/level/block/BedBlock.java
+++ b/net/minecraft/world/level/block/BedBlock.java
@@ -45,6 +45,7 @@
 import org.apache.commons.lang3.ArrayUtils;
 
 public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock {
+
     public static final EnumProperty<BedPart> PART = BlockStateProperties.BED_PART;
     public static final BooleanProperty OCCUPIED = BlockStateProperties.OCCUPIED;
     protected static final int HEIGHT = 9;
@@ -54,22 +55,23 @@
     protected static final VoxelShape LEG_SOUTH_WEST = Block.box(0.0D, 0.0D, 13.0D, 3.0D, 3.0D, 16.0D);
     protected static final VoxelShape LEG_NORTH_EAST = Block.box(13.0D, 0.0D, 0.0D, 16.0D, 3.0D, 3.0D);
     protected static final VoxelShape LEG_SOUTH_EAST = Block.box(13.0D, 0.0D, 13.0D, 16.0D, 3.0D, 16.0D);
-    protected static final VoxelShape NORTH_SHAPE = Shapes.or(BASE, LEG_NORTH_WEST, LEG_NORTH_EAST);
-    protected static final VoxelShape SOUTH_SHAPE = Shapes.or(BASE, LEG_SOUTH_WEST, LEG_SOUTH_EAST);
-    protected static final VoxelShape WEST_SHAPE = Shapes.or(BASE, LEG_NORTH_WEST, LEG_SOUTH_WEST);
-    protected static final VoxelShape EAST_SHAPE = Shapes.or(BASE, LEG_NORTH_EAST, LEG_SOUTH_EAST);
+    protected static final VoxelShape NORTH_SHAPE = Shapes.or(BedBlock.BASE, BedBlock.LEG_NORTH_WEST, BedBlock.LEG_NORTH_EAST);
+    protected static final VoxelShape SOUTH_SHAPE = Shapes.or(BedBlock.BASE, BedBlock.LEG_SOUTH_WEST, BedBlock.LEG_SOUTH_EAST);
+    protected static final VoxelShape WEST_SHAPE = Shapes.or(BedBlock.BASE, BedBlock.LEG_NORTH_WEST, BedBlock.LEG_SOUTH_WEST);
+    protected static final VoxelShape EAST_SHAPE = Shapes.or(BedBlock.BASE, BedBlock.LEG_NORTH_EAST, BedBlock.LEG_SOUTH_EAST);
     private final DyeColor color;
 
     public BedBlock(DyeColor color, BlockBehaviour.Properties settings) {
         super(settings);
         this.color = color;
-        this.registerDefaultState(this.stateDefinition.any().setValue(PART, BedPart.FOOT).setValue(OCCUPIED, Boolean.valueOf(false)));
+        this.registerDefaultState((BlockState) ((BlockState) ((BlockState) this.stateDefinition.any()).setValue(BedBlock.PART, BedPart.FOOT)).setValue(BedBlock.OCCUPIED, false));
     }
 
     @Nullable
     public static Direction getBedOrientation(BlockGetter world, BlockPos pos) {
-        BlockState blockState = world.getBlockState(pos);
-        return blockState.getBlock() instanceof BedBlock ? blockState.getValue(FACING) : null;
+        BlockState iblockdata = world.getBlockState(pos);
+
+        return iblockdata.getBlock() instanceof BedBlock ? (Direction) iblockdata.getValue(BedBlock.FACING) : null;
     }
 
     @Override
@@ -77,34 +79,54 @@
         if (world.isClientSide) {
             return InteractionResult.CONSUME;
         } else {
-            if (state.getValue(PART) != BedPart.HEAD) {
-                pos = pos.relative(state.getValue(FACING));
+            if (state.getValue(BedBlock.PART) != BedPart.HEAD) {
+                pos = pos.relative((Direction) state.getValue(BedBlock.FACING));
                 state = world.getBlockState(pos);
-                if (!state.is(this)) {
+                if (!state.is((Block) this)) {
                     return InteractionResult.CONSUME;
                 }
             }
 
-            if (!canSetSpawn(world)) {
+            // CraftBukkit - moved world and biome check into EntityHuman
+            if (false && !BedBlock.canSetSpawn(world)) {
                 world.removeBlock(pos, false);
-                BlockPos blockPos = pos.relative(state.getValue(FACING).getOpposite());
-                if (world.getBlockState(blockPos).is(this)) {
-                    world.removeBlock(blockPos, false);
+                BlockPos blockposition1 = pos.relative(((Direction) state.getValue(BedBlock.FACING)).getOpposite());
+
+                if (world.getBlockState(blockposition1).is((Block) this)) {
+                    world.removeBlock(blockposition1, false);
                 }
 
-                world.explode((Entity)null, DamageSource.badRespawnPointExplosion(), (ExplosionDamageCalculator)null, (double)pos.getX() + 0.5D, (double)pos.getY() + 0.5D, (double)pos.getZ() + 0.5D, 5.0F, true, Explosion.BlockInteraction.DESTROY);
+                world.explode((Entity) null, DamageSource.badRespawnPointExplosion(), (ExplosionDamageCalculator) null, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, 5.0F, true, Explosion.BlockInteraction.DESTROY);
                 return InteractionResult.SUCCESS;
-            } else if (state.getValue(OCCUPIED)) {
+            } else if ((Boolean) state.getValue(BedBlock.OCCUPIED)) {
                 if (!this.kickVillagerOutOfBed(world, pos)) {
                     player.displayClientMessage(Component.translatable("block.minecraft.bed.occupied"), true);
                 }
 
                 return InteractionResult.SUCCESS;
             } else {
-                player.startSleepInBed(pos).ifLeft((reason) -> {
-                    if (reason.getMessage() != null) {
-                        player.displayClientMessage(reason.getMessage(), true);
+                // CraftBukkit start
+                BlockState finaliblockdata = state;
+                BlockPos finalblockposition = pos;
+                // CraftBukkit end
+                player.startSleepInBed(pos).ifLeft((entityhuman_enumbedresult) -> {
+                    // Paper start - PlayerBedFailEnterEvent
+                    if (entityhuman_enumbedresult != null) {
+                        io.papermc.paper.event.player.PlayerBedFailEnterEvent event = new io.papermc.paper.event.player.PlayerBedFailEnterEvent((org.bukkit.entity.Player) player.getBukkitEntity(), io.papermc.paper.event.player.PlayerBedFailEnterEvent.FailReason.VALUES[entityhuman_enumbedresult.ordinal()], org.bukkit.craftbukkit.v1_19_R1.block.CraftBlock.at(world, finalblockposition), !world.dimensionType().bedWorks(), io.papermc.paper.adventure.PaperAdventure.asAdventure(entityhuman_enumbedresult.getMessage()));
+                        if (!event.callEvent()) {
+                            return;
+                        }
+                        // Paper end
+                    // CraftBukkit start - handling bed explosion from below here
+                    if (event.getWillExplode()) { // Paper
+                        this.explodeBed(finaliblockdata, world, finalblockposition);
+                    } else
+                    // CraftBukkit end
+                    if (entityhuman_enumbedresult.getMessage() != null) {
+                        final net.kyori.adventure.text.Component message = event.getMessage(); // Paper
+                        if (message != null) player.displayClientMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message), true); // Paper
                     }
+                    } // Paper
 
                 });
                 return InteractionResult.SUCCESS;
@@ -112,16 +134,36 @@
         }
     }
 
+    // CraftBukkit start
+    private InteractionResult explodeBed(BlockState iblockdata, Level world, BlockPos blockposition) {
+        {
+            {
+                world.removeBlock(blockposition, false);
+                BlockPos blockposition1 = blockposition.relative(((Direction) iblockdata.getValue(BedBlock.FACING)).getOpposite());
+
+                if (world.getBlockState(blockposition1).getBlock() == this) {
+                    world.removeBlock(blockposition1, false);
+                }
+
+                world.explode((Entity) null, DamageSource.badRespawnPointExplosion(), (ExplosionDamageCalculator) null, (double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, 5.0F, true, Explosion.BlockInteraction.DESTROY);
+                return InteractionResult.SUCCESS;
+            }
+        }
+    }
+    // CraftBukkit end
+
     public static boolean canSetSpawn(Level world) {
-        return world.dimensionType().bedWorks();
+        // CraftBukkit - moved world and biome check into EntityHuman
+        return true || world.dimensionType().bedWorks();
     }
 
     private boolean kickVillagerOutOfBed(Level world, BlockPos pos) {
         List<Villager> list = world.getEntitiesOfClass(Villager.class, new AABB(pos), LivingEntity::isSleeping);
+
         if (list.isEmpty()) {
             return false;
         } else {
-            list.get(0).stopSleeping();
+            ((Villager) list.get(0)).stopSleeping();
             return true;
         }
     }
@@ -142,21 +184,19 @@
     }
 
     private void bounceUp(Entity entity) {
-        Vec3 vec3 = entity.getDeltaMovement();
-        if (vec3.y < 0.0D) {
-            double d = entity instanceof LivingEntity ? 1.0D : 0.8D;
-            entity.setDeltaMovement(vec3.x, -vec3.y * (double)0.66F * d, vec3.z);
+        Vec3 vec3d = entity.getDeltaMovement();
+
+        if (vec3d.y < 0.0D) {
+            double d0 = entity instanceof LivingEntity ? 1.0D : 0.8D;
+
+            entity.setDeltaMovement(vec3d.x, -vec3d.y * 0.6600000262260437D * d0, vec3d.z);
         }
 
     }
 
     @Override
     public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
-        if (direction == getNeighbourDirection(state.getValue(PART), state.getValue(FACING))) {
-            return neighborState.is(this) && neighborState.getValue(PART) != state.getValue(PART) ? state.setValue(OCCUPIED, neighborState.getValue(OCCUPIED)) : Blocks.AIR.defaultBlockState();
-        } else {
-            return super.updateShape(state, direction, neighborState, world, pos, neighborPos);
-        }
+        return direction == BedBlock.getNeighbourDirection((BedPart) state.getValue(BedBlock.PART), (Direction) state.getValue(BedBlock.FACING)) ? (neighborState.is((Block) this) && neighborState.getValue(BedBlock.PART) != state.getValue(BedBlock.PART) ? (BlockState) state.setValue(BedBlock.OCCUPIED, (Boolean) neighborState.getValue(BedBlock.OCCUPIED)) : Blocks.AIR.defaultBlockState()) : super.updateShape(state, direction, neighborState, world, pos, neighborPos);
     }
 
     private static Direction getNeighbourDirection(BedPart part, Direction direction) {
@@ -166,13 +206,15 @@
     @Override
     public void playerWillDestroy(Level world, BlockPos pos, BlockState state, Player player) {
         if (!world.isClientSide && player.isCreative()) {
-            BedPart bedPart = state.getValue(PART);
-            if (bedPart == BedPart.FOOT) {
-                BlockPos blockPos = pos.relative(getNeighbourDirection(bedPart, state.getValue(FACING)));
-                BlockState blockState = world.getBlockState(blockPos);
-                if (blockState.is(this) && blockState.getValue(PART) == BedPart.HEAD) {
-                    world.setBlock(blockPos, Blocks.AIR.defaultBlockState(), 35);
-                    world.levelEvent(player, 2001, blockPos, Block.getId(blockState));
+            BedPart blockpropertybedpart = (BedPart) state.getValue(BedBlock.PART);
+
+            if (blockpropertybedpart == BedPart.FOOT) {
+                BlockPos blockposition1 = pos.relative(BedBlock.getNeighbourDirection(blockpropertybedpart, (Direction) state.getValue(BedBlock.FACING)));
+                BlockState iblockdata1 = world.getBlockState(blockposition1);
+
+                if (iblockdata1.is((Block) this) && iblockdata1.getValue(BedBlock.PART) == BedPart.HEAD) {
+                    world.setBlock(blockposition1, Blocks.AIR.defaultBlockState(), 35);
+                    world.levelEvent(player, 2001, blockposition1, Block.getId(iblockdata1));
                 }
             }
         }
@@ -183,36 +225,40 @@
     @Nullable
     @Override
     public BlockState getStateForPlacement(BlockPlaceContext ctx) {
-        Direction direction = ctx.getHorizontalDirection();
-        BlockPos blockPos = ctx.getClickedPos();
-        BlockPos blockPos2 = blockPos.relative(direction);
-        Level level = ctx.getLevel();
-        return level.getBlockState(blockPos2).canBeReplaced(ctx) && level.getWorldBorder().isWithinBounds(blockPos2) ? this.defaultBlockState().setValue(FACING, direction) : null;
+        Direction enumdirection = ctx.getHorizontalDirection();
+        BlockPos blockposition = ctx.getClickedPos();
+        BlockPos blockposition1 = blockposition.relative(enumdirection);
+        Level world = ctx.getLevel();
+
+        return world.getBlockState(blockposition1).canBeReplaced(ctx) && world.getWorldBorder().isWithinBounds(blockposition1) ? (BlockState) this.defaultBlockState().setValue(BedBlock.FACING, enumdirection) : null;
     }
 
     @Override
     public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) {
-        Direction direction = getConnectedDirection(state).getOpposite();
-        switch (direction) {
+        Direction enumdirection = BedBlock.getConnectedDirection(state).getOpposite();
+
+        switch (enumdirection) {
             case NORTH:
-                return NORTH_SHAPE;
+                return BedBlock.NORTH_SHAPE;
             case SOUTH:
-                return SOUTH_SHAPE;
+                return BedBlock.SOUTH_SHAPE;
             case WEST:
-                return WEST_SHAPE;
+                return BedBlock.WEST_SHAPE;
             default:
-                return EAST_SHAPE;
+                return BedBlock.EAST_SHAPE;
         }
     }
 
     public static Direction getConnectedDirection(BlockState state) {
-        Direction direction = state.getValue(FACING);
-        return state.getValue(PART) == BedPart.HEAD ? direction.getOpposite() : direction;
+        Direction enumdirection = (Direction) state.getValue(BedBlock.FACING);
+
+        return state.getValue(BedBlock.PART) == BedPart.HEAD ? enumdirection.getOpposite() : enumdirection;
     }
 
     public static DoubleBlockCombiner.BlockType getBlockType(BlockState state) {
-        BedPart bedPart = state.getValue(PART);
-        return bedPart == BedPart.HEAD ? DoubleBlockCombiner.BlockType.FIRST : DoubleBlockCombiner.BlockType.SECOND;
+        BedPart blockpropertybedpart = (BedPart) state.getValue(BedBlock.PART);
+
+        return blockpropertybedpart == BedPart.HEAD ? DoubleBlockCombiner.BlockType.FIRST : DoubleBlockCombiner.BlockType.SECOND;
     }
 
     private static boolean isBunkBed(BlockGetter world, BlockPos pos) {
@@ -220,40 +266,47 @@
     }
 
     public static Optional<Vec3> findStandUpPosition(EntityType<?> type, CollisionGetter world, BlockPos pos, float spawnAngle) {
-        Direction direction = world.getBlockState(pos).getValue(FACING);
-        Direction direction2 = direction.getClockWise();
-        Direction direction3 = direction2.isFacingAngle(spawnAngle) ? direction2.getOpposite() : direction2;
-        if (isBunkBed(world, pos)) {
-            return findBunkBedStandUpPosition(type, world, pos, direction, direction3);
+        Direction enumdirection = (Direction) world.getBlockState(pos).getValue(BedBlock.FACING);
+        Direction enumdirection1 = enumdirection.getClockWise();
+        Direction enumdirection2 = enumdirection1.isFacingAngle(spawnAngle) ? enumdirection1.getOpposite() : enumdirection1;
+
+        if (BedBlock.isBunkBed(world, pos)) {
+            return BedBlock.findBunkBedStandUpPosition(type, world, pos, enumdirection, enumdirection2);
         } else {
-            int[][] is = bedStandUpOffsets(direction, direction3);
-            Optional<Vec3> optional = findStandUpPositionAtOffset(type, world, pos, is, true);
-            return optional.isPresent() ? optional : findStandUpPositionAtOffset(type, world, pos, is, false);
+            int[][] aint = BedBlock.bedStandUpOffsets(enumdirection, enumdirection2);
+            Optional<Vec3> optional = BedBlock.findStandUpPositionAtOffset(type, world, pos, aint, true);
+
+            return optional.isPresent() ? optional : BedBlock.findStandUpPositionAtOffset(type, world, pos, aint, false);
         }
     }
 
     private static Optional<Vec3> findBunkBedStandUpPosition(EntityType<?> type, CollisionGetter world, BlockPos pos, Direction bedDirection, Direction respawnDirection) {
-        int[][] is = bedSurroundStandUpOffsets(bedDirection, respawnDirection);
-        Optional<Vec3> optional = findStandUpPositionAtOffset(type, world, pos, is, true);
+        int[][] aint = BedBlock.bedSurroundStandUpOffsets(bedDirection, respawnDirection);
+        Optional<Vec3> optional = BedBlock.findStandUpPositionAtOffset(type, world, pos, aint, true);
+
         if (optional.isPresent()) {
             return optional;
         } else {
-            BlockPos blockPos = pos.below();
-            Optional<Vec3> optional2 = findStandUpPositionAtOffset(type, world, blockPos, is, true);
-            if (optional2.isPresent()) {
-                return optional2;
+            BlockPos blockposition1 = pos.below();
+            Optional<Vec3> optional1 = BedBlock.findStandUpPositionAtOffset(type, world, blockposition1, aint, true);
+
+            if (optional1.isPresent()) {
+                return optional1;
             } else {
-                int[][] js = bedAboveStandUpOffsets(bedDirection);
-                Optional<Vec3> optional3 = findStandUpPositionAtOffset(type, world, pos, js, true);
-                if (optional3.isPresent()) {
-                    return optional3;
+                int[][] aint1 = BedBlock.bedAboveStandUpOffsets(bedDirection);
+                Optional<Vec3> optional2 = BedBlock.findStandUpPositionAtOffset(type, world, pos, aint1, true);
+
+                if (optional2.isPresent()) {
+                    return optional2;
                 } else {
-                    Optional<Vec3> optional4 = findStandUpPositionAtOffset(type, world, pos, is, false);
-                    if (optional4.isPresent()) {
-                        return optional4;
+                    Optional<Vec3> optional3 = BedBlock.findStandUpPositionAtOffset(type, world, pos, aint, false);
+
+                    if (optional3.isPresent()) {
+                        return optional3;
                     } else {
-                        Optional<Vec3> optional5 = findStandUpPositionAtOffset(type, world, blockPos, is, false);
-                        return optional5.isPresent() ? optional5 : findStandUpPositionAtOffset(type, world, pos, js, false);
+                        Optional<Vec3> optional4 = BedBlock.findStandUpPositionAtOffset(type, world, blockposition1, aint, false);
+
+                        return optional4.isPresent() ? optional4 : BedBlock.findStandUpPositionAtOffset(type, world, pos, aint1, false);
                     }
                 }
             }
@@ -261,13 +314,18 @@
     }
 
     private static Optional<Vec3> findStandUpPositionAtOffset(EntityType<?> type, CollisionGetter world, BlockPos pos, int[][] possibleOffsets, boolean ignoreInvalidPos) {
-        BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
+        BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
+        int[][] aint1 = possibleOffsets;
+        int i = possibleOffsets.length;
 
-        for(int[] is : possibleOffsets) {
-            mutableBlockPos.set(pos.getX() + is[0], pos.getY(), pos.getZ() + is[1]);
-            Vec3 vec3 = DismountHelper.findSafeDismountLocation(type, world, mutableBlockPos, ignoreInvalidPos);
-            if (vec3 != null) {
-                return Optional.of(vec3);
+        for (int j = 0; j < i; ++j) {
+            int[] aint2 = aint1[j];
+
+            blockposition_mutableblockposition.set(pos.getX() + aint2[0], pos.getY(), pos.getZ() + aint2[1]);
+            Vec3 vec3d = DismountHelper.findSafeDismountLocation(type, world, blockposition_mutableblockposition, ignoreInvalidPos);
+
+            if (vec3d != null) {
+                return Optional.of(vec3d);
             }
         }
 
@@ -286,7 +344,7 @@
 
     @Override
     protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
-        builder.add(FACING, PART, OCCUPIED);
+        builder.add(BedBlock.FACING, BedBlock.PART, BedBlock.OCCUPIED);
     }
 
     @Override
@@ -298,8 +356,9 @@
     public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack itemStack) {
         super.setPlacedBy(world, pos, state, placer, itemStack);
         if (!world.isClientSide) {
-            BlockPos blockPos = pos.relative(state.getValue(FACING));
-            world.setBlock(blockPos, state.setValue(PART, BedPart.HEAD), 3);
+            BlockPos blockposition1 = pos.relative((Direction) state.getValue(BedBlock.FACING));
+
+            world.setBlock(blockposition1, (BlockState) state.setValue(BedBlock.PART, BedPart.HEAD), 3);
             world.blockUpdated(pos, Blocks.AIR);
             state.updateNeighbourShapes(world, pos, 3);
         }
@@ -312,8 +371,9 @@
 
     @Override
     public long getSeed(BlockState state, BlockPos pos) {
-        BlockPos blockPos = pos.relative(state.getValue(FACING), state.getValue(PART) == BedPart.HEAD ? 0 : 1);
-        return Mth.getSeed(blockPos.getX(), pos.getY(), blockPos.getZ());
+        BlockPos blockposition1 = pos.relative((Direction) state.getValue(BedBlock.FACING), state.getValue(BedBlock.PART) == BedPart.HEAD ? 0 : 1);
+
+        return Mth.getSeed(blockposition1.getX(), pos.getY(), blockposition1.getZ());
     }
 
     @Override
@@ -322,7 +382,7 @@
     }
 
     private static int[][] bedStandUpOffsets(Direction bedDirection, Direction respawnDirection) {
-        return ArrayUtils.addAll((int[][])bedSurroundStandUpOffsets(bedDirection, respawnDirection), (int[][])bedAboveStandUpOffsets(bedDirection));
+        return (int[][]) ArrayUtils.addAll(BedBlock.bedSurroundStandUpOffsets(bedDirection, respawnDirection), BedBlock.bedAboveStandUpOffsets(bedDirection));
     }
 
     private static int[][] bedSurroundStandUpOffsets(Direction bedDirection, Direction respawnDirection) {
