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(); + } +}