Skip to content

Commit

Permalink
feat: make night skipping behave like in vanilla
Browse files Browse the repository at this point in the history
  • Loading branch information
Pupskuchen committed Mar 25, 2023
1 parent 9880a59 commit 6b6e1d0
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 80 deletions.
8 changes: 4 additions & 4 deletions src/main/java/net/pupskuchen/timecontrol/TimeControl.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import net.pupskuchen.timecontrol.config.ConfigManager;
import net.pupskuchen.timecontrol.event.player.PlayerBed;
import net.pupskuchen.timecontrol.runnable.Runnable;
import net.pupskuchen.timecontrol.util.TimeControlUtil;
import net.pupskuchen.timecontrol.util.LogUtil;

public class TimeControl extends JavaPlugin {

Expand Down Expand Up @@ -39,7 +39,7 @@ private void registerConfig() {
}

private void registerEvents() {
this.getServer().getPluginManager().registerEvents(new PlayerBed(getConfigManager()), this);
this.getServer().getPluginManager().registerEvents(new PlayerBed(this, getConfigManager()), this);
}

private void registerRunnables() {
Expand All @@ -56,8 +56,8 @@ private void setDaylightCycle(final boolean value) {
.filter(world -> this.cm.getWorlds().contains(world.getName()))
.forEach(world -> {
world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, value);
TimeControlUtil.console(
"Setting GameRule.DO_DAYLIGHT_CYCLE to " + value + " for world '" + world.getName() + "'");
LogUtil.console(String.format("Setting game rule \"%s\" to \"%b\" for world \"%s\"",
GameRule.DO_DAYLIGHT_CYCLE.getName(), value, world.getName()));
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import org.bukkit.configuration.file.FileConfiguration;

import net.pupskuchen.timecontrol.util.TimeControlUtil;
import net.pupskuchen.timecontrol.util.LogUtil;

import java.util.Collections;
import java.util.HashSet;
Expand All @@ -18,7 +18,7 @@ public class ConfigManager {

private boolean nightSkippingEnabled;
private boolean percentageEnabled;
private int percentage;
private int configPercentage;

public ConfigManager(final FileConfiguration config) {
this.config = config;
Expand All @@ -30,22 +30,22 @@ public void validate() {
final int day = this.config.getInt("day", 30);
if (day <= 0) {
this.day = 30;
TimeControlUtil.consoleWarning("Set day cycle to " + day + " minutes is not safe, reverting to default...");
LogUtil.consoleWarning("Set day cycle to " + day + " minutes is not safe, reverting to default...");
} else {
this.day = day;
}
TimeControlUtil.console("Set day cycle to " + this.day + " minutes");
LogUtil.console("Set day cycle to " + this.day + " minutes");

// night
final int night = this.config.getInt("night", 5);
if (night <= 0) {
this.night = 5;
TimeControlUtil
LogUtil
.consoleWarning("Set night cycle to " + night + " minutes is not safe, reverting to default...");
} else {
this.night = night;
}
TimeControlUtil.console("Set night cycle to " + this.night + " minutes");
LogUtil.console("Set night cycle to " + this.night + " minutes");

// worlds
final List<String> worlds = this.config.getStringList("worlds");
Expand All @@ -54,7 +54,7 @@ public void validate() {
this.worlds = Collections.unmodifiableSet(this.worlds);

percentageEnabled = this.config.getBoolean("players-sleeping-percentage.enabled");
percentage = this.config.getInt("players-sleeping-percentage.percentage");
configPercentage = this.config.getInt("players-sleeping-percentage.percentage");
nightSkippingEnabled = this.config.getBoolean("night-skipping.enabled");
}

Expand All @@ -74,8 +74,8 @@ public boolean isPercentageEnabled() {
return percentageEnabled;
}

public int getPercentage() {
return percentage;
public int getConfigPercentage() {
return configPercentage;
}

public boolean isNightSkippingEnabled() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
package net.pupskuchen.timecontrol.event.player;

import org.bukkit.GameRule;
import java.util.HashMap;
import java.util.Map;

import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerBedEnterEvent;
import org.bukkit.event.player.PlayerBedLeaveEvent;
import org.bukkit.plugin.java.JavaPlugin;

import net.pupskuchen.timecontrol.config.ConfigManager;
import net.pupskuchen.timecontrol.util.TimeControlUtil;
import net.pupskuchen.timecontrol.util.NightSkipper;

public class PlayerBed implements Listener {

private final JavaPlugin plugin;
private final ConfigManager configManager;
private final Map<String, NightSkipper> worldSkippers;

public PlayerBed(ConfigManager configManager) {
public PlayerBed(final JavaPlugin plugin, final ConfigManager configManager) {
this.plugin = plugin;
this.configManager = configManager;
this.worldSkippers = new HashMap<>();
}

@EventHandler
Expand All @@ -28,27 +36,30 @@ public void onPlayerBedEnter(final PlayerBedEnterEvent event) {
}

final World world = event.getPlayer().getWorld();
final int sleeping = (int) world.getPlayers().stream().filter((player) -> player.isSleeping()).count() + 1;

int percentage;

if (!configManager.isPercentageEnabled()) {
try {
percentage = world.getGameRuleValue(GameRule.PLAYERS_SLEEPING_PERCENTAGE);
} catch (Exception e) {
TimeControlUtil.consoleWarning("Could not fetch game-rule value 'playersSleepingPercentage!" +
" Please go to the config.yml and enable players-sleeping-percentage");
return;
}
final String worldName = world.getName();
NightSkipper skipper = worldSkippers.get(worldName);

if (skipper == null) {
skipper = new NightSkipper(plugin, configManager, world);
this.worldSkippers.put(worldName, skipper);
}

skipper.restartGuard();
}

@EventHandler
public void onPlayerBedLeave(final PlayerBedLeaveEvent event) {
if (!configManager.isNightSkippingEnabled()) {
return;
}

percentage = configManager.getPercentage();
final String worldName = event.getPlayer().getWorld().getName();
final NightSkipper skipper = worldSkippers.get(worldName);

if ((sleeping / world.getPlayers().size()) * 100 >= percentage) {
world.setTime(1000);
event.setCancelled(true);
TimeControlUtil.console("The night has been skipped by sleeping");
if (skipper == null) {
return;
}
}

skipper.skipNight();
}
}
64 changes: 30 additions & 34 deletions src/main/java/net/pupskuchen/timecontrol/runnable/Runnable.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package net.pupskuchen.timecontrol.runnable;

import java.util.HashMap;
import java.util.Map;

import org.bukkit.World;
import org.bukkit.scheduler.BukkitRunnable;

import net.pupskuchen.timecontrol.TimeControl;
import net.pupskuchen.timecontrol.config.ConfigManager;
import net.pupskuchen.timecontrol.util.TimeControlUtil;

import java.util.HashMap;
import java.util.Map;
import net.pupskuchen.timecontrol.util.TickUtil;
import net.pupskuchen.timecontrol.util.LogUtil;
import net.pupskuchen.timecontrol.util.TimeUtil;

public class Runnable {

Expand All @@ -23,52 +25,46 @@ public Runnable(final TimeControl plugin) {
}

public void runCycles(final World world) {
final double dayRatio = TickUtil.cycleMinsToTickRatio(cm.getDay());
final double nightRatio = TickUtil.cycleMinsToTickRatio(cm.getNight());
final String worldName = world.getName();

new BukkitRunnable() {
@Override
public void run() {
final long time = world.getTime();
if (TimeControlUtil.isDay(world)) {
setTime(world, convertMinsToTicks(cm.getDay()));
} else if (TimeControlUtil.isNight(world)) {
setTime(world, convertMinsToTicks(cm.getNight()));
if (TimeUtil.isDay(world)) {
setTime(world, worldName, dayRatio);
} else {
TimeControlUtil.consoleWarning(world.getName() + " world time " + time + " is impossible");
setTime(world, worldName, nightRatio);
}
}
}.runTaskTimer(this.plugin, 0, 1);
TimeControlUtil.console("Running day and night cycles for world '" + world.getName() + "'");

LogUtil.console("Running day and night cycles for world '" + world.getName() + "'");
}

private void setTime(final World world, final long val) {
final String w = world.getName();
this.counts.putIfAbsent(w, 0L);
final double ratio = (1.0 / (val / 12000.0));
long time = world.getTime();
// Speedup
private void setTime(final World world, final String worldName, final double ratio) {
this.counts.putIfAbsent(worldName, 0L);
final long time = world.getTime();

if (ratio > 1.0) {
time += Math.round(ratio);
world.setTime(time);
this.counts.put(w, 0L);
// Slowdown
// speed up
world.setTime(time + Math.round(ratio));
this.counts.put(worldName, 0L);
} else if (ratio < 1.0) {
final long count = this.counts.get(w);
// slow down
final long count = this.counts.get(worldName);

if (count <= 0) {
// Slow
time += 1;
world.setTime(time);
this.counts.put(w, Math.round(1.0 / ratio) - 1);
world.setTime(time + 1);
this.counts.put(worldName, Math.round(1.0 / ratio) - 1);
} else {
// Wait
this.counts.put(w, count - 1);
this.counts.put(worldName, count - 1);
}
// Normal
} else {
world.setTime(++time);
// Normal
world.setTime(time + 1);
}
}

private long convertMinsToTicks(final long min) {
return min * 60 * 20;
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package net.pupskuchen.timecontrol.util;

import org.bukkit.Bukkit;
import org.bukkit.World;

public class TimeControlUtil {

public class LogUtil {
public static final String LOG_PREFIX = "[TimeControl] ";

public static void console(final String message) {
Expand All @@ -15,13 +13,4 @@ public static void consoleWarning(final String message) {
Bukkit.getLogger().warning(LOG_PREFIX + message);
}

public static boolean isDay(final World world) {
final long time = world.getTime();
return time >= 0 && time < 12000;
}

public static boolean isNight(final World world) {
return !isDay(world);
}

}
43 changes: 43 additions & 0 deletions src/main/java/net/pupskuchen/timecontrol/util/NightSkipGuard.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package net.pupskuchen.timecontrol.util;

import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;

public class NightSkipGuard {
private static final int DEFAULT_SLEEP_TICKS = 101;

private final long skippableTickThreshold = DEFAULT_SLEEP_TICKS;
private final JavaPlugin plugin;

private boolean canSkip = false;
private BukkitTask waitForSkippable;

public NightSkipGuard(final JavaPlugin plugin) {
this.plugin = plugin;
}

public void makeSkippable() {
this.cancel();

waitForSkippable = new BukkitRunnable() {
@Override
public void run() {
canSkip = true;
}
}.runTaskLater(plugin, skippableTickThreshold);
}

public void cancel() {
if (waitForSkippable == null) {
return;
}

waitForSkippable.cancel();
canSkip = false;
}

public boolean isSkippable() {
return canSkip;
}
}
Loading

0 comments on commit 6b6e1d0

Please sign in to comment.