diff --git a/patches/minecraft/net/minecraft/server/level/ServerPlayer.java.patch b/patches/minecraft/net/minecraft/server/level/ServerPlayer.java.patch
index bb85e8aaf1..1b1781779e 100644
--- a/patches/minecraft/net/minecraft/server/level/ServerPlayer.java.patch
+++ b/patches/minecraft/net/minecraft/server/level/ServerPlayer.java.patch
@@ -54,7 +54,7 @@
if (!this.isSleeping() && this.isAlive()) {
BedRule bedrule = this.level().environmentAttributes().getValue(EnvironmentAttributes.BED_RULE, p_9115_);
- boolean flag = bedrule.canSleep(this.level());
-+ boolean flag = !net.minecraftforge.event.ForgeEventFactory.onSleepingTimeCheck(this, optAt, bedrule);
++ boolean flag = net.minecraftforge.event.ForgeEventFactory.onSleepingTimeCheck(this, optAt, bedrule);
boolean flag1 = bedrule.canSetSpawn(this.level());
if (!flag1 && !flag) {
return Either.left(bedrule.asProblem());
diff --git a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java
index 12a1374f79..297a26694d 100644
--- a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java
+++ b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java
@@ -593,7 +593,7 @@ public final class ForgeEventFactory {
var canContinueSleep = evt.getResult();
if (canContinueSleep == Result.DEFAULT)
- return !rule.canSleep(player.level());
+ return rule.canSleep(player.level());
else
return canContinueSleep == Result.ALLOW;
}
diff --git a/src/main/java/net/minecraftforge/event/entity/player/SleepingTimeCheckEvent.java b/src/main/java/net/minecraftforge/event/entity/player/SleepingTimeCheckEvent.java
index 94b7c520ec..bd990c7fda 100644
--- a/src/main/java/net/minecraftforge/event/entity/player/SleepingTimeCheckEvent.java
+++ b/src/main/java/net/minecraftforge/event/entity/player/SleepingTimeCheckEvent.java
@@ -22,7 +22,7 @@ import java.util.Optional;
* This event has a result. {@link HasResult}
*
* setResult(ALLOW) informs game that player can sleep at this time.
- * setResult(DEFAULT) causes game to check !{@link Level#isDay()} instead.
+ * setResult(DEFAULT) causes game to check {@link net.minecraft.world.attribute.BedRule#canSleep()} instead.
*/
public final class SleepingTimeCheckEvent extends MutableEvent implements PlayerEvent, HasResult {
public static final EventBus BUS = EventBus.create(SleepingTimeCheckEvent.class);
diff --git a/src/test/generated/try_sleep/data/forge/test_instance/try_sleep/sleep_daytime.json b/src/test/generated/try_sleep/data/forge/test_instance/try_sleep/sleep_daytime.json
new file mode 100644
index 0000000000..05ce627ab6
--- /dev/null
+++ b/src/test/generated/try_sleep/data/forge/test_instance/try_sleep/sleep_daytime.json
@@ -0,0 +1,7 @@
+{
+ "type": "minecraft:function",
+ "environment": "minecraft:default",
+ "function": "forge:try_sleep/sleep_daytime",
+ "max_ticks": 100,
+ "structure": "forge:empty3x3x3"
+}
\ No newline at end of file
diff --git a/src/test/generated/try_sleep/data/forge/test_instance/try_sleep/sleep_normally.json b/src/test/generated/try_sleep/data/forge/test_instance/try_sleep/sleep_normally.json
new file mode 100644
index 0000000000..5fbf79b1f9
--- /dev/null
+++ b/src/test/generated/try_sleep/data/forge/test_instance/try_sleep/sleep_normally.json
@@ -0,0 +1,7 @@
+{
+ "type": "minecraft:function",
+ "environment": "minecraft:default",
+ "function": "forge:try_sleep/sleep_normally",
+ "max_ticks": 100,
+ "structure": "forge:empty3x3x3"
+}
\ No newline at end of file
diff --git a/src/test/generated/try_sleep/data/forge/test_instance/try_sleep/sleep_obstructed.json b/src/test/generated/try_sleep/data/forge/test_instance/try_sleep/sleep_obstructed.json
new file mode 100644
index 0000000000..f9a5613d1c
--- /dev/null
+++ b/src/test/generated/try_sleep/data/forge/test_instance/try_sleep/sleep_obstructed.json
@@ -0,0 +1,7 @@
+{
+ "type": "minecraft:function",
+ "environment": "minecraft:default",
+ "function": "forge:try_sleep/sleep_obstructed",
+ "max_ticks": 100,
+ "structure": "forge:empty3x3x3"
+}
\ No newline at end of file
diff --git a/src/test/generated/try_sleep/data/forge/test_instance/try_sleep/sleep_unsafe.json b/src/test/generated/try_sleep/data/forge/test_instance/try_sleep/sleep_unsafe.json
new file mode 100644
index 0000000000..125be21460
--- /dev/null
+++ b/src/test/generated/try_sleep/data/forge/test_instance/try_sleep/sleep_unsafe.json
@@ -0,0 +1,7 @@
+{
+ "type": "minecraft:function",
+ "environment": "minecraft:default",
+ "function": "forge:try_sleep/sleep_unsafe",
+ "max_ticks": 100,
+ "structure": "forge:empty3x3x3"
+}
\ No newline at end of file
diff --git a/src/test/java/net/minecraftforge/debug/gameplay/level/TrySleepTest.java b/src/test/java/net/minecraftforge/debug/gameplay/level/TrySleepTest.java
new file mode 100644
index 0000000000..3df6ee9e01
--- /dev/null
+++ b/src/test/java/net/minecraftforge/debug/gameplay/level/TrySleepTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) Forge Development LLC and contributors
+ * SPDX-License-Identifier: LGPL-2.1-only
+ */
+
+package net.minecraftforge.debug.gameplay.level;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.gametest.framework.GameTestHelper;
+import net.minecraft.world.attribute.EnvironmentAttribute;
+import net.minecraft.world.attribute.EnvironmentAttributes;
+import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.entity.monster.Slime;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.level.GameType;
+import net.minecraft.world.level.block.BedBlock;
+import net.minecraft.world.level.block.Blocks;
+import net.minecraft.world.level.block.state.properties.BedPart;
+import net.minecraftforge.fml.common.Mod;
+import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
+import net.minecraftforge.gametest.GameTest;
+import net.minecraftforge.gametest.GameTestNamespace;
+import net.minecraftforge.test.BaseTestMod;
+
+@GameTestNamespace("forge")
+@Mod(TrySleepTest.MOD_ID)
+public class TrySleepTest extends BaseTestMod {
+ static final String MOD_ID = "try_sleep";
+ static final long NIGHT = 13000;
+ static final long DAY = 0;
+
+ public TrySleepTest(FMLJavaModLoadingContext context) {
+ super(context, false, false);
+ }
+
+ @GameTest
+ public static void sleep_obstructed(GameTestHelper helper) {
+ var player = helper.makeMockServerPlayer(GameType.SURVIVAL);
+
+ var bed = putBed(helper);
+ helper.setAndAssertBlock(bed.above(), Blocks.STONE);
+ setTimeAndTest(helper, NIGHT, bed, player, false, "Player was able to sleep in an obstructed bed.");
+ }
+
+ @GameTest
+ public static void sleep_daytime(GameTestHelper helper) {
+ var player = helper.makeMockServerPlayer(GameType.SURVIVAL);
+ var bed = putBed(helper);
+ setTimeAndTest(helper, DAY, bed, player, false, "Player was able to sleep during daytime.");
+ }
+
+ @GameTest
+ public static void sleep_unsafe(GameTestHelper helper) {
+ var player = helper.makeMockServerPlayer(GameType.SURVIVAL);
+ var bed = putBed(helper);
+ helper.spawn(EntityType.ZOMBIE, bed.east());
+ setTimeAndTest(helper, NIGHT, bed, player, false, "Player was able to sleep in an unsafe bed.");
+ }
+
+ @GameTest
+ public static void sleep_normally(GameTestHelper helper) {
+ var player = helper.makeMockServerPlayer(GameType.SURVIVAL);
+ var bed = putBed(helper);
+ setTimeAndTest(helper, NIGHT, bed, player, true, "Player was not able to sleep. There might be a slime or something causing this to fail.");
+ }
+
+ private static BlockPos putBed(GameTestHelper helper) {
+ var mid = new BlockPos(0,0,0);
+ var south = mid.south();
+ helper.setAndAssertBlock(south, Blocks.BLACK_BED.defaultBlockState());
+ helper.setAndAssertBlock(mid, Blocks.BLACK_BED.defaultBlockState().setValue(BedBlock.PART, BedPart.HEAD));
+ return mid;
+ }
+
+ private static void setTimeAndTest(GameTestHelper helper, long time, BlockPos bed, Player player, boolean shouldBeSleeping, String err) {
+ var origTime = helper.getLevel().getDayTime();
+ player.setPos(helper.absolutePos(bed).getCenter());
+ helper.getLevel().setDayTime(time);
+ helper.getLevel().tick(() -> true);
+ helper.useBlock(bed, player);
+ var sleep = player.isSleeping();
+ helper.getLevel().setDayTime(origTime);
+ helper.assertTrue(sleep == shouldBeSleeping, err);
+ helper.succeed();
+ }
+}