diff --git a/paper-api/src/main/java/org/bukkit/entity/LivingEntity.java b/paper-api/src/main/java/org/bukkit/entity/LivingEntity.java index 19a48dce7c2f..265968dcb27b 100644 --- a/paper-api/src/main/java/org/bukkit/entity/LivingEntity.java +++ b/paper-api/src/main/java/org/bukkit/entity/LivingEntity.java @@ -841,6 +841,24 @@ default boolean addPotionEffect(@NotNull PotionEffect effect) { */ public boolean isSleeping(); + /** + * Attempts to make the entity sleep at the given location. + *
+ * The location must be in the current world and have a bed placed at the + * location. + * + * @param location the location of the bed + * @return whether the sleep was successful + */ + public boolean sleep(@NotNull Location location); + + /** + * Causes this entity to wake up if it is currently sleeping. + * + * @throws IllegalStateException if not sleeping + */ + public void wakeup(); + /** * Gets if the entity is climbing. * diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java index 5a4e98531031..9db67e3acd4d 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java @@ -210,6 +210,11 @@ public boolean sleep(Location location, boolean force) { return true; } + @Override + public boolean sleep(Location location) { + return this.sleep(location, false); + } + @Override public void wakeup(boolean setSpawnLocation) { Preconditions.checkState(this.isSleeping(), "Cannot wakeup if not sleeping"); @@ -217,6 +222,11 @@ public void wakeup(boolean setSpawnLocation) { this.getHandle().stopSleepInBed(true, setSpawnLocation); } + @Override + public void wakeup() { + this.wakeup(false); + } + @Override public void startRiptideAttack(int duration, float damage, ItemStack attackItem) { Preconditions.checkArgument(duration > 0, "Duration must be greater than 0"); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java index b0987314d263..89451bca56f0 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java @@ -13,6 +13,7 @@ import io.papermc.paper.adventure.PaperAdventure; import net.kyori.adventure.key.Key; import net.minecraft.Optionull; +import net.minecraft.core.BlockPos; import io.papermc.paper.world.damagesource.CombatTracker; import net.minecraft.core.component.DataComponents; import net.minecraft.network.protocol.game.ClientboundHurtAnimationPacket; @@ -40,6 +41,8 @@ import net.minecraft.world.entity.projectile.arrow.ThrownTrident; import net.minecraft.world.item.Items; import net.minecraft.world.item.component.Consumable; +import net.minecraft.world.level.block.BedBlock; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; import net.minecraft.world.waypoints.WaypointStyleAsset; import net.minecraft.world.waypoints.WaypointStyleAssets; @@ -61,6 +64,7 @@ import org.bukkit.craftbukkit.inventory.CraftEntityEquipment; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.potion.CraftPotionEffectType; +import org.bukkit.craftbukkit.util.CraftLocation; import org.bukkit.entity.AbstractArrow; import org.bukkit.entity.AbstractWindCharge; import org.bukkit.entity.Arrow; @@ -769,6 +773,31 @@ public boolean isSleeping() { return this.getHandle().isSleeping(); } + @Override + public boolean sleep(Location location) { + Preconditions.checkArgument(location != null, "Location cannot be null"); + Preconditions.checkArgument(location.getWorld() != null, "Location needs to be in a world"); + Preconditions.checkArgument(location.getWorld().equals(this.getWorld()), "Cannot sleep across worlds"); + Preconditions.checkState(!this.getHandle().generation, "Cannot sleep during world generation"); + + BlockPos position = CraftLocation.toBlockPosition(location); + BlockState state = this.getHandle().level().getBlockState(position); + if (!(state.getBlock() instanceof BedBlock)) { + return false; + } + + this.getHandle().startSleeping(position); + return true; + } + + @Override + public void wakeup() { + Preconditions.checkState(this.isSleeping(), "Cannot wakeup if not sleeping"); + Preconditions.checkState(!this.getHandle().generation, "Cannot wakeup during world generation"); + + this.getHandle().stopSleeping(); + } + @Override public boolean isClimbing() { Preconditions.checkState(!this.getHandle().generation, "Cannot check if climbing during world generation");