From 3e77c95a45377e1ff88908774439f59bc8447a9c Mon Sep 17 00:00:00 2001 From: Superkat32 Date: Thu, 5 Oct 2023 21:14:50 -0400 Subject: [PATCH] Day time sleeping FEAT: Added a new config option to enable/disable sleeping through the day! (fixes #21) FEAT: Config options to enable/disable time until dusk message REFACTOR: Some changes on how nighttime is detected, now always using a boolean form SleepMath instead of calculating it each time it is needed REFACTOR: Some additional changes to en_us.json --- .../realisticsleep/RealisticSleep.java | 12 ++++++++++ .../realisticsleep/SleepMath.java | 11 ++++++--- .../config/RealisticSleepConfig.java | 13 ++++++++++ .../mixin/ServerPlayerEntityMixin.java | 15 +++++++++--- .../mixin/ServerWorldMixin.java | 24 ++++++++++++++++--- .../assets/realisticsleep/lang/en_us.json | 12 +++++++++- 6 files changed, 77 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/github/steveplays28/realisticsleep/RealisticSleep.java b/src/main/java/com/github/steveplays28/realisticsleep/RealisticSleep.java index 29101b8..b21a6ff 100644 --- a/src/main/java/com/github/steveplays28/realisticsleep/RealisticSleep.java +++ b/src/main/java/com/github/steveplays28/realisticsleep/RealisticSleep.java @@ -4,7 +4,9 @@ import me.shedaniel.autoconfig.AutoConfig; import me.shedaniel.autoconfig.serializer.GsonConfigSerializer; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.entity.event.v1.EntitySleepEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.minecraft.util.ActionResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,5 +27,15 @@ public void onInitialize() { AutoConfig.getConfigHolder(RealisticSleepConfig.class).load(); config = AutoConfig.getConfigHolder(RealisticSleepConfig.class).getConfig(); }); + + //Registers a sleeping event using Fabric API + EntitySleepEvents.ALLOW_SLEEP_TIME.register(((player, sleepingPos, vanillaResult) -> { + //If day sleeping is disabled, then the vanilla Minecraft action will be returned instead + if(config.allowDaySleeping) { + return ActionResult.SUCCESS; + } + + return ActionResult.PASS; + })); } } diff --git a/src/main/java/com/github/steveplays28/realisticsleep/SleepMath.java b/src/main/java/com/github/steveplays28/realisticsleep/SleepMath.java index 47c5acc..6c993c1 100644 --- a/src/main/java/com/github/steveplays28/realisticsleep/SleepMath.java +++ b/src/main/java/com/github/steveplays28/realisticsleep/SleepMath.java @@ -4,7 +4,8 @@ public class SleepMath { public static final int DAY_LENGTH = 24000; - public static final int WAKE_UP_TIME = 23449; + public static final int SUNRISE_WAKE_UP = 23449; + public static final int SUNSET_WAKE_UP = 12449; public static double calculateNightTimeStepPerTick(double sleepingRatio, double multiplier, double lastTimeStepPerTick) { return switch (config.sleepSpeedCurve) { @@ -17,14 +18,18 @@ public static int calculateTicksToTimeOfDay(int timeOfDay, int targetTimeOfDay) } public static int calculateTicksUntilAwake(int currentTimeOfDay) { - return calculateTicksToTimeOfDay(currentTimeOfDay, DAY_LENGTH); + return calculateTicksToTimeOfDay(currentTimeOfDay, isNightTime(currentTimeOfDay) ? DAY_LENGTH : SUNSET_WAKE_UP); } public static int calculateSecondsUntilAwake(int currentTimeOfDay, double timeStepPerTick, double tps) { - return (int) Math.round(calculateTicksUntilAwake(currentTimeOfDay) / timeStepPerTick / tps); + return (int) Math.round(calculateTicksUntilAwake(currentTimeOfDay % DAY_LENGTH) / timeStepPerTick / tps); } public static double getRandomNumberInRange(double min, double max) { return (Math.random() * (max - min)) + min; } + + public static boolean isNightTime(long currentTimeOfDay) { + return currentTimeOfDay % DAY_LENGTH >= SUNSET_WAKE_UP; + } } diff --git a/src/main/java/com/github/steveplays28/realisticsleep/config/RealisticSleepConfig.java b/src/main/java/com/github/steveplays28/realisticsleep/config/RealisticSleepConfig.java index d3defcf..9dad219 100644 --- a/src/main/java/com/github/steveplays28/realisticsleep/config/RealisticSleepConfig.java +++ b/src/main/java/com/github/steveplays28/realisticsleep/config/RealisticSleepConfig.java @@ -8,16 +8,29 @@ public class RealisticSleepConfig implements ConfigData { @ConfigEntry.Gui.Tooltip public boolean sendDawnMessage = true; + + @ConfigEntry.Gui.Tooltip + public boolean sendDuskMessage = true; + @ConfigEntry.Gui.Tooltip public String dawnMessage = "The sun rises."; + @ConfigEntry.Gui.Tooltip + public String duskMessage = "The night begins."; + @ConfigEntry.Gui.Tooltip public boolean sendSleepingMessage = true; @ConfigEntry.Gui.Tooltip public boolean showTimeUntilDawn = true; + + @ConfigEntry.Gui.Tooltip + public boolean showTimeUntilDusk = true; @ConfigEntry.Gui.Tooltip public boolean sendNotEnoughPlayersSleepingMessage = true; + @ConfigEntry.Gui.Tooltip + public boolean allowDaySleeping = true; + @ConfigEntry.Gui.Tooltip public SleepSpeedCurve sleepSpeedCurve = SleepSpeedCurve.LINEAR; @ConfigEntry.Gui.Tooltip diff --git a/src/main/java/com/github/steveplays28/realisticsleep/mixin/ServerPlayerEntityMixin.java b/src/main/java/com/github/steveplays28/realisticsleep/mixin/ServerPlayerEntityMixin.java index 8345da4..69c7048 100644 --- a/src/main/java/com/github/steveplays28/realisticsleep/mixin/ServerPlayerEntityMixin.java +++ b/src/main/java/com/github/steveplays28/realisticsleep/mixin/ServerPlayerEntityMixin.java @@ -1,8 +1,10 @@ package com.github.steveplays28.realisticsleep.mixin; +import com.github.steveplays28.realisticsleep.SleepMath; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; import net.minecraft.text.Text; import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; @@ -12,7 +14,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import static com.github.steveplays28.realisticsleep.RealisticSleep.config; -import static com.github.steveplays28.realisticsleep.SleepMath.WAKE_UP_TIME; @Mixin(ServerPlayerEntity.class) public abstract class ServerPlayerEntityMixin extends Entity { @@ -23,14 +24,22 @@ public ServerPlayerEntityMixin(EntityType type, World world) { @Shadow public abstract void sendMessage(Text message, boolean overlay); + @Shadow public abstract ServerWorld getWorld(); + @Inject(method = "wakeUp(ZZ)V", at = @At(value = "HEAD")) public void wakeUpInject(boolean skipSleepTimer, boolean updateSleepingPlayers, CallbackInfo ci) { - if (getWorld().getTimeOfDay() >= WAKE_UP_TIME) { + if (!SleepMath.isNightTime(getWorld().getTimeOfDay())) { // Return if we shouldn't send the dawn message - if (!config.sendDawnMessage || config.dawnMessage.equals("")) return; + if (!config.sendDawnMessage || config.dawnMessage.isEmpty()) return; // Send dawn HUD message to player sendMessage(Text.of(config.dawnMessage), true); + } else if (config.allowDaySleeping && SleepMath.isNightTime(getWorld().getTimeOfDay())) { //Only shows this message if day sleeping is allowed + // Return if we shouldn't send the dawn or dusk message + if (!config.sendDuskMessage || config.duskMessage.isEmpty()) return; + + // Send dawn or dusk HUD message to player + sendMessage(Text.of(config.duskMessage), true); } } } diff --git a/src/main/java/com/github/steveplays28/realisticsleep/mixin/ServerWorldMixin.java b/src/main/java/com/github/steveplays28/realisticsleep/mixin/ServerWorldMixin.java index 391f310..8141af8 100644 --- a/src/main/java/com/github/steveplays28/realisticsleep/mixin/ServerWorldMixin.java +++ b/src/main/java/com/github/steveplays28/realisticsleep/mixin/ServerWorldMixin.java @@ -72,6 +72,8 @@ public abstract class ServerWorldMixin extends World { @Shadow public abstract List getPlayers(); + @Shadow protected abstract void wakeSleepingPlayers(); + protected ServerWorldMixin(MutableWorldProperties properties, RegistryKey registryRef, RegistryEntry registryEntry, Supplier profiler, boolean isClient, boolean debugWorld, long seed, int maxChainedNeighborUpdates) { super(properties, registryRef, registryEntry, profiler, isClient, debugWorld, seed, maxChainedNeighborUpdates); } @@ -83,6 +85,9 @@ public void tickInject(BooleanSupplier shouldKeepTicking, CallbackInfo ci) { int secondsUntilAwake = Math.abs( SleepMath.calculateSecondsUntilAwake((int) worldProperties.getTimeOfDay() % DAY_LENGTH, nightTimeStepPerTick, 20)); + //Gets the remainder of the current time of day, as this number never actually resets each day(from my own testing) + int ticksUntilAwake = SleepMath.calculateTicksUntilAwake((int) worldProperties.getTimeOfDay() % DAY_LENGTH); + // Check if the night has (almost) ended and the weather should be skipped if (secondsUntilAwake <= 2 && shouldSkipWeather) { clearWeather(); @@ -101,7 +106,7 @@ public void tickInject(BooleanSupplier shouldKeepTicking, CallbackInfo ci) { nightTimeStepPerTick = SleepMath.calculateNightTimeStepPerTick(sleepingRatio, config.sleepSpeedMultiplier, nightTimeStepPerTick); nightTimeStepPerTickRounded = (int) Math.round(nightTimeStepPerTick); - var isNight = worldProperties.getTimeOfDay() > DAY_LENGTH / 2; + var isNight = SleepMath.isNightTime(worldProperties.getTimeOfDay()); var nightDayOrThunderstormText = Text.translatable( String.format("%s.text.%s", MOD_ID, worldProperties.isThundering() ? "thunderstorm" : isNight ? "night" : "day")); @@ -162,8 +167,14 @@ public void tickInject(BooleanSupplier shouldKeepTicking, CallbackInfo ci) { sleepMessage = Text.translatable(String.format("%s.text.sleep_message", MOD_ID), sleepingPlayerCount, playerCount).append( nightDayOrThunderstormText); - if (config.showTimeUntilDawn) { - sleepMessage.append(Text.translatable(String.format("%s.text.time_until_dawn", MOD_ID), secondsUntilAwake)); + if(isNight) { + if (config.showTimeUntilDawn) { + sleepMessage.append(Text.translatable(String.format("%s.text.time_until_dawn", MOD_ID), secondsUntilAwake)); + } + } else { + if(config.showTimeUntilDusk) { + sleepMessage.append(Text.translatable(String.format("%s.text.time_until_dusk", MOD_ID), secondsUntilAwake)); + } } for (ServerPlayerEntity player : players) { @@ -171,6 +182,13 @@ public void tickInject(BooleanSupplier shouldKeepTicking, CallbackInfo ci) { } } } + + int tickGrace = 30; //The amount of extra ticks for waking up - maybe useful in cases where TPS is low? + //In my own testing, using just secondsUntilAwake <= 0 seemed to have a few seconds where + //trying to sleep back in the bed would kick the player right out + if (secondsUntilAwake <= 0 && ticksUntilAwake <= tickGrace) { + this.wakeSleepingPlayers(); + } } @Inject(method = "tickTime", at = @At(value = "HEAD"), cancellable = true) diff --git a/src/main/resources/assets/realisticsleep/lang/en_us.json b/src/main/resources/assets/realisticsleep/lang/en_us.json index f58263f..69b23e2 100644 --- a/src/main/resources/assets/realisticsleep/lang/en_us.json +++ b/src/main/resources/assets/realisticsleep/lang/en_us.json @@ -2,13 +2,22 @@ "text.autoconfig.realisticsleep.title": "Realistic Sleep Config", "text.autoconfig.realisticsleep.option.sendDawnMessage": "Send dawn message?", "text.autoconfig.realisticsleep.option.sendDawnMessage.@Tooltip": "Send a message to all players at dawn.", + "text.autoconfig.realisticsleep.option.sendDuskMessage": "Send dusk message?", + "text.autoconfig.realisticsleep.option.sendDuskMessage.@Tooltip": "Send a message to all players at dusk.", + "text.autoconfig.realisticsleep.option.dawnMessage": "Dawn message", "text.autoconfig.realisticsleep.option.dawnMessage.@Tooltip": "The message displayed to all players at dawn.", + "text.autoconfig.realisticsleep.option.duskMessage": "Dusk message", + "text.autoconfig.realisticsleep.option.duskMessage.@Tooltip": "The message displayed to all players at dawn.", "text.autoconfig.realisticsleep.option.sendSleepingMessage": "Send sleeping message?", "text.autoconfig.realisticsleep.option.sendSleepingMessage.@Tooltip": "Toggles the \"players are sleeping through this night...\" message.", "text.autoconfig.realisticsleep.option.showTimeUntilDawn": "Show time until dawn?", "text.autoconfig.realisticsleep.option.showTimeUntilDawn.@Tooltip": "Displays the seconds until dawn.", + "text.autoconfig.realisticsleep.option.showTimeUntilDusk": "Show time until dusk?", + "text.autoconfig.realisticsleep.option.showTimeUntilDusk.@Tooltip": "Displays the seconds until dusk.", "text.autoconfig.realisticsleep.option.sendNotEnoughPlayersSleepingMessage": "Send not enough players sleeping message?", "text.autoconfig.realisticsleep.option.sendNotEnoughPlayersSleepingMessage.@Tooltip": "Toggles the amount of players who need to sleep to skip to dawn message.", + "text.autoconfig.realisticsleep.option.allowDaySleeping": "Allow sleeping through the day?", + "text.autoconfig.realisticsleep.option.allowDaySleeping.@Tooltip": "Toggles daytime sleeping.", "text.autoconfig.realisticsleep.option.sleepSpeedCurve": "Sleep speed curve", "text.autoconfig.realisticsleep.option.sleepSpeedCurve.@Tooltip": "The curve used to determine the speed multiplier of the night as time progresses.", "text.autoconfig.realisticsleep.option.sleepSpeedMultiplier": "Sleep speed multiplier", @@ -28,5 +37,6 @@ "realisticsleep.text.night": "night", "realisticsleep.text.day": "day", "realisticsleep.text.thunderstorm": "thunderstorm", - "realisticsleep.text.time_until_dawn": " (time until dawn: %ds)" + "realisticsleep.text.time_until_dawn": " (time until dawn: %ds)", + "realisticsleep.text.time_until_dusk": " (time until dusk: %ds)" }