diff --git a/pom.xml b/pom.xml
index a574b28..2c3e7bd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
Smooth sleeping experience for multiplayer Bukkit servers
me.offluffy
${project.name}
- 1.0.7
+ 1.0.8
jar
diff --git a/src/main/java/me/offluffy/SmoothSleep/SmoothSleep.java b/src/main/java/me/offluffy/SmoothSleep/SmoothSleep.java
index f2be79d..ad4a5a3 100644
--- a/src/main/java/me/offluffy/SmoothSleep/SmoothSleep.java
+++ b/src/main/java/me/offluffy/SmoothSleep/SmoothSleep.java
@@ -5,25 +5,29 @@
import me.offluffy.SmoothSleep.lib.MiscUtils;
import me.offluffy.SmoothSleep.lib.ReflectionUtils;
import me.offluffy.SmoothSleep.listeners.PlayerEventsListener;
+import org.apache.commons.lang.text.StrSubstitutor;
import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
+import java.util.Map;
+
+import static org.bukkit.ChatColor.*;
@SuppressWarnings("unused")
public class SmoothSleep extends JavaPlugin {
private final long SLEEP_TICKS_START = 12541L,
SLEEP_TICKS_END = 23458L,
SLEEP_TICKS_DURA = SLEEP_TICKS_END - SLEEP_TICKS_START;
+ private final long TICKS_PER_DAY = 1728000,
+ TICKS_PER_HOUR = 72000,
+ TICKS_PER_MIN = 1200;
private HashMap nightMults = new HashMap();
- private List sleepers = new ArrayList();
+ private Map sleepers = new HashMap();
public boolean enabled = true;
public void onEnable() {
@@ -46,22 +50,33 @@ public void run() {
int sc = getSleeperCount(w), wc = getWakerCount(w);
if (sc == 0) { continue; } // Do nothing if no one is sleeping
-
boolean useTitles = getConfig().getBoolean(cp + "use-titles", true);
- int minMult = nightMults.get(w).min, maxMult = nightMults.get(w).max;
- int timescale = Math.round((float) MiscUtils.remapValue(true, 0, sc+wc, minMult, maxMult, sc));
- long newTime = w.getTime() + timescale - 1;
- if (newTime > SLEEP_TICKS_END) newTime = SLEEP_TICKS_END;
+ long newTime;
+ int timescale;
+ if (wc == 0 && getConfig().getBoolean(cp + "instant-day-if-all-sleeping", false)) {
+ newTime = SLEEP_TICKS_END;
+ timescale = (int) SLEEP_TICKS_DURA;
+ } else {
+ int minMult = nightMults.get(w).min, maxMult = nightMults.get(w).max;
+ timescale = Math.round((float) MiscUtils.remapValue(true, 0, sc + wc, minMult, maxMult, sc));
+ newTime = w.getTime() + timescale - 1;
+ if (newTime > SLEEP_TICKS_END) newTime = SLEEP_TICKS_END;
+ }
+ for (Player p : sleepers.keySet()) {
+ long sleepTime = sleepers.get(p);
+ sleepTime += timescale;
+ sleepers.put(p, sleepTime);
+ }
w.setTime(newTime);
String title = "", subtitle = "";
Sound snd = null;
- List tempSleepers = new ArrayList(sleepers);
+ Map tempSleepers = new HashMap(sleepers);
if (w.getTime() >= SLEEP_TICKS_END) {
if (useTitles) {
- title = ChatColor.YELLOW + MiscUtils.ticksToTime(w.getTime());
- subtitle = trans(getConfig().getString(cp + "morning-subtitle", "Rise and shine, {PLAYER}!"));
+ title = trans(getConfig().getString(cp + "morning-title", "&e{12H}:{MIN} {MER_UPPER}"));
+ subtitle = trans(getConfig().getString(cp + "morning-subtitle", "&aRise and shine, {PLAYER}!"));
}
String sndName = getConfig().getString(cp + "morning-sound", "ENTITY_PLAYER_LEVELUP");
if (!sndName.isEmpty()) {
@@ -78,39 +93,49 @@ public void run() {
}
sleepers.clear();
} else if (useTitles) {
- title = ChatColor.AQUA + MiscUtils.ticksToTime(w.getTime());
- subtitle = ChatColor.GREEN + (sc + "/" + (sc+wc) + " Sleepers")
- + ChatColor.DARK_AQUA + " (" + timescale + "x speed)";
+ title = trans(getConfig().getString(cp + "sleeping-title", "&b{12H}:{MIN} {MER_UPPER}"));
+ subtitle = trans(getConfig().getString(cp + "sleeping-subtitle", "&a({SLEEPERS}/{PLAYERS} Sleeping &3({TIMESCALE}x speed)"));
}
- for (Player p : tempSleepers) {
+ for (Player p : tempSleepers.keySet()) {
if (useTitles) {
- long ticksPerDay = 1728000,
- ticksPerHour = 72000,
- ticksPerMin = 1200;
long worldTime = w.getTime();
long timeLived = p.getTicksLived();
- long daysLived = timeLived / ticksPerDay;
- long hrsLived = (timeLived - (daysLived * ticksPerDay)) / ticksPerHour;
- long minLived = (timeLived - (daysLived * ticksPerDay) - (hrsLived * ticksPerHour)) / ticksPerMin;
- String ps = subtitle
- .replace("{USERNAME}", p.getName())
- .replace("{DISPLAYNAME}", p.getDisplayName())
- .replace("{LEVEL}", p.getLevel()+"")
- .replace("{DAYS_LIVED}", daysLived+"")
- .replace("{REM_HOURS_LIVED}", hrsLived+"")
- .replace("{REM_MINS_LIVED}", minLived+"")
- .replace("{TOTAL_HOURS_LIVED}", (p.getTicksLived()/ticksPerHour)+"")
- .replace("{TOTAL_MINS_LIVED}", (p.getTicksLived()/ticksPerMin)+"")
- .replace("{TIME_LIVED}", daysLived + "d, " + hrsLived + "h, " + minLived + "m")
- .replace("{WORLD}", w.getName())
- .replace("{SERVER_IP}", Bukkit.getIp())
- .replace("{SERVER_MOTD}", Bukkit.getMotd())
- .replace("{SERVER_NAME}", Bukkit.getServerName())
- .replace("{SERVER_MOTD_STRIP}", ChatColor.stripColor(Bukkit.getMotd()))
- .replace("{SERVER_NAME_STRIP}", ChatColor.stripColor(Bukkit.getServerName()))
- ;
- p.sendTitle(title, ps, 0, 20, 20);
+ long daysLived = timeLived / TICKS_PER_DAY;
+ long hrsLived = (timeLived % TICKS_PER_DAY) / TICKS_PER_HOUR;
+ long minLived = (timeLived % TICKS_PER_DAY % TICKS_PER_HOUR) / TICKS_PER_MIN;
+ Map values = new HashMap();
+
+ values.put("12H", MiscUtils.ticksTo12Hours(worldTime) + "");
+ values.put("24H", MiscUtils.ticksTo24Hours(worldTime) + "");
+ values.put("MIN", String.format("%02d", MiscUtils.ticksToMinutes(worldTime)));
+ values.put("MER_UPPER", MiscUtils.ticksIsAM(worldTime) ? "AM" : "PM");
+ values.put("MER_LOWER", MiscUtils.ticksIsAM(worldTime) ? "am" : "pm");
+ values.put("SLEEPERS", sc + "");
+ values.put("WAKERS", wc + "");
+ values.put("TOTAL", (sc+wc) + "");
+ values.put("TIMESCALE", timescale + "");
+ values.put("USERNAME", p.getName());
+ values.put("DISPLAYNAME", p.getDisplayName());
+ values.put("DISPLAYNAME_STRIP", stripColor(p.getDisplayName()));
+ values.put("HOURS_SLEPT", (tempSleepers.get(p) / 1000L) + "");
+ values.put("LEVEL", p.getLevel() + "");
+ values.put("TIME_LIVED", "{DAYS_LIVED}d, {REM_HOURS_LIVED}h, {REM_MINS_LIVED}m");
+ values.put("DAYS_LIVED", (timeLived / TICKS_PER_DAY) + "");
+ values.put("REM_HOURS_LIVED", ((timeLived % TICKS_PER_DAY) / TICKS_PER_HOUR) + "");
+ values.put("REM_MINS_LIVED", ((timeLived % TICKS_PER_DAY % TICKS_PER_HOUR) / TICKS_PER_MIN) + "");
+ values.put("TOTAL_HOURS_LIVED", (p.getTicksLived() / TICKS_PER_HOUR) + "");
+ values.put("TOTAL_MINS_LIVED", (p.getTicksLived() / TICKS_PER_MIN) + "");
+ values.put("WORLD", w.getName());
+ values.put("SERVER_IP", Bukkit.getIp());
+ values.put("SERVER_MOTD", Bukkit.getMotd());
+ values.put("SERVER_NAME", Bukkit.getServerName());
+ values.put("SERVER_MOTD_STRIP", stripColor(Bukkit.getMotd()));
+ values.put("SERVER_NAME_STRIP", stripColor(Bukkit.getServerName()));
+ StrSubstitutor sub = new StrSubstitutor(values, "{", "}");
+ String ps = sub.replace(subtitle);
+ String pt = sub.replace(title);
+ p.sendTitle(pt, ps, 0, 20, 20);
}
if (snd != null) {
p.playSound(p.getLocation(), snd, 0.5f, 1.0f);
@@ -124,7 +149,7 @@ public void run() {
Bukkit.getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
public void run() {
if (!sleepers.isEmpty()) {
- for (Player p : sleepers) {
+ for (Player p : sleepers.keySet()) {
long wt = p.getWorld().getTime();
try {
Object nmsPlr = ReflectionUtils.invokeMethod(p, "getHandle");
@@ -149,16 +174,27 @@ public void reload() {
boolean changed = false;
// Will add config changes here if they'll need to be added from and older config.
+ if (!getConfig().contains(cp + "instant-day-if-all-sleeping", true)) {
+ getConfig().set(cp + "instant-day-if-all-sleeping", false);
+ changed = true;
+ }
+ if (!getConfig().contains(cp + "morning-title", true)) {
+ getConfig().set(cp + "morning-title", "&e{12H}:{MIN} {MER_UPPER}");
+ changed = true;
+ }
+
+ if (!getConfig().contains(cp + "sleeping-title", true)) {
+ getConfig().set(cp + "sleeping-title", "&b{12H}:{MIN} {MER_UPPER}");
+ changed = true;
+ }
+
if (!getConfig().contains(cp + "morning-subtitle", true)) {
- getConfig().set(cp + "morning-subtitle", "Rise and shine, {USERNAME}!");
+ getConfig().set(cp + "morning-subtitle", "&aRise and shine, {USERNAME}!");
changed = true;
}
- String mornSub = getConfig().getString(cp + "morning-subtitle", "Rise and shine, {USERNAME}!");
- if (mornSub.contains("{PLAYER}")) {
- getLogger().warning(cp + "morning-subtitle: " + mornSub);
- getLogger().warning("The {PLAYER} placeholder is no longer used! I'll replace it with {USERNAME}.");
- getConfig().set(cp + "morning-subtitle", mornSub.replace("{PLAYER}", "{USERNAME}"));
+ if (!getConfig().contains(cp + "sleeping-subtitle", true)) {
+ getConfig().set(cp + "sleeping-subtitle", "&a({SLEEPERS}/{TOTAL} Sleeping &3({TIMESCALE}x speed)");
changed = true;
}
@@ -187,6 +223,14 @@ public void reload() {
changed = true;
}
+ String mornSub = getConfig().getString(cp + "morning-subtitle", "&aRise and shine, {USERNAME}!");
+ if (mornSub.contains("{PLAYER}")) {
+ getLogger().warning(cp + "morning-subtitle: " + mornSub);
+ getLogger().warning("The {PLAYER} placeholder is no longer used! I'll replace it with {USERNAME}.");
+ getConfig().set(cp + "morning-subtitle", mornSub.replace("{PLAYER}", "{USERNAME}"));
+ changed = true;
+ }
+
// Some sanity checks to make sure that config values are valid
if (getConfig().getInt("worlds." + w.getName() + ".min-night-speed-mult", 10) < 1) {
getConfig().set(cp + "min-night-speed-mult", 1); // Must be >0
@@ -226,16 +270,16 @@ public void reload() {
}
}
- private String trans(String s) { return ChatColor.translateAlternateColorCodes('&', s); }
+ private String trans(String s) { return translateAlternateColorCodes('&', s); }
public boolean worldEnabled(World w) { return nightMults.containsKey(w); }
- public void addSleeper(Player p) { if (!sleepers.contains(p)) sleepers.add(p); }
+ public void addSleeper(Player p, long time) { if (!sleepers.containsKey(p)) sleepers.put(p, 0L); }
public void removeSleeper(Player p) { sleepers.remove(p); }
- private boolean isSleeping(Player p) { return p != null && sleepers.contains(p); }
+ private boolean isSleeping(Player p) { return p != null && sleepers.containsKey(p); }
public int getSleeperCount(World w) {
if (!worldEnabled(w)) return 0;
int s = 0;
- for (Player p : sleepers) { if (p.getWorld().equals(w)) { s++; } }
+ for (Player p : sleepers.keySet()) { if (p.getWorld().equals(w)) { s++; } }
return s;
}
public int getWakerCount(World w) {
diff --git a/src/main/java/me/offluffy/SmoothSleep/lib/MiscUtils.java b/src/main/java/me/offluffy/SmoothSleep/lib/MiscUtils.java
index 44719b2..41fde0f 100644
--- a/src/main/java/me/offluffy/SmoothSleep/lib/MiscUtils.java
+++ b/src/main/java/me/offluffy/SmoothSleep/lib/MiscUtils.java
@@ -10,11 +10,20 @@ public static double remapValue(boolean clamp, double oldMin, double oldMax, dou
return (((newMax - newMin) * (value - oldMin)) / (oldMax - oldMin)) + newMin;
}
- public static String ticksToTime(long ticks) {
- ticks += 6000; // Offset 0 ticks to = 6AM
- int hours = (int)(ticks / 1000), minutes = (int)((ticks % 1000) / 16.66);
- return (hours > 12 ? hours > 24 ? hours - 24 : hours-12 : hours) + ":"
- + (minutes < 10 ? "0" : "") + minutes + (hours >= 12 && hours < 24 ? " PM" : " AM");
+ public static int ticksTo24Hours(long ticks) {
+ ticks += 6000;
+ int hours = (int) ticks / 1000;
+ return (hours >= 24 ? hours - 24 : hours);
+ }
+ public static int ticksTo12Hours(long ticks) {
+ int hours = ticksTo24Hours(ticks);
+ return hours > 12 ? hours - 12: hours;
+ }
+ public static int ticksToMinutes(long ticks) {
+ return (int) ((ticks % 1000) / 16.66);
+ }
+ public static boolean ticksIsAM(long ticks) {
+ return ticksTo24Hours(ticks) < 12;
}
}
diff --git a/src/main/java/me/offluffy/SmoothSleep/listeners/PlayerEventsListener.java b/src/main/java/me/offluffy/SmoothSleep/listeners/PlayerEventsListener.java
index 959e80e..5618031 100644
--- a/src/main/java/me/offluffy/SmoothSleep/listeners/PlayerEventsListener.java
+++ b/src/main/java/me/offluffy/SmoothSleep/listeners/PlayerEventsListener.java
@@ -19,7 +19,7 @@ public void enterBed(PlayerBedEnterEvent e) {
Player p = e.getPlayer();
World w = e.getBed().getWorld();
// Location l = e.getBed().getLocation();
- if (plugin.worldEnabled(w)) { plugin.addSleeper(p); }
+ if (plugin.worldEnabled(w)) { plugin.addSleeper(p, w.getTime()); }
}
@EventHandler(ignoreCancelled = true)
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index ddac644..d33f0b6 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -28,14 +28,24 @@
# morning-subtitle: The message shown under the clock upon waking up if 'use-titles' is enabled.
# -- Any short message with ampersand {&} color codes. Good idea to wrap this value in 'quotes' or it may break
# -- If you want to keep the clock, but not the subtitle, then just leave this blank (empty quotes '')
-# -- Supports some variables:
+# -- Supports variables:
+# -- -- {12H} - The 12-hour portion of the server time
+# -- -- {24H} - The 24-hour portion of the server time
+# -- -- {MIN} - The minutes portion of the server time
+# -- -- {MER_UPPER} - The uppercase meridiem counterpart of 12-hour time, AM or PM
+# -- -- {MER_LOWER} - The lowercase meridiem counterpart of 12-hour time, am or pm
+# -- -- {SLEEPERS} - The number of players currently sleeping
+# -- -- {WAKERS} - The number of non-ignored non-sleeping players
+# -- -- {TOTAL} - The number of players sleeping + non-sleeping, non-ignored players
+# -- -- {TIMESCALE} - How many times faster than normal time is passing
# -- -- {USERNAME} - The player's username (not always the one that is displayed in game)
# -- -- {DISPLAYNAME} - The player's name as it is shown in game. May contain prefixes, color codes, etc.
+# -- -- {HOURS_SLEPT} - How many in-game hours the player has slept, regardless of timescale
# -- -- {LEVEL} - The player's current level
# -- -- {DAYS_LIVED} - The number of days that the player has lived
# -- -- {REM_HOURS_LIVED} - The number of hours the player has lived after subtracting days
# -- -- {REM_MINS_LIVED} - The number of minutes the player has lived after subtracting days and hours
-# -- -- {TOTAL_HOURS_LIVED} - The number of hours that the player has lived (total hours, doesn't sutract days)
+# -- -- {TOTAL_HOURS_LIVED} - The number of hours that the player has lived (total hours, doesn't subtract days)
# -- -- {TOTAL_MINS_LIVED} - The number of minutes that the player has lived (total minutes, doesn't subtract hours or days)
# -- -- {TIME_LIVED} - The time the player has lived in days, minutes, and seconds; formatted as '0d, 0h, 0m'
# -- -- {WORLD} - The name of the world that the player is sleeping in
@@ -51,12 +61,18 @@
#
# use-titles: If true, displays a large clock and sleeper stats when sleeping, and 'morning-subtitle' in the morning
#
+# instant-day-if-all-sleeping: If true, this will instantly skip night if all non-sleep-ignored players are sleeping.
+#
# =============================
worlds:
world:
min-night-speed-mult: 10
max-night-speed-mult: 50
+ sleeping-title: '&b{12H}:{MIN} {MER_UPPER}'
+ morning-title: '&e{12H}:{MIN} {MER_UPPER}'
+ sleeping-subtitle: '&a{SLEEPERS}/{TOTAL} Sleeping &3({TIMESCALE}x speed)'
morning-subtitle: '&aRise and shine, {USERNAME}!'
morning-sound: 'ENTITY_PLAYER_LEVELUP'
clear-weather-when-morning: true
- use-titles: true
\ No newline at end of file
+ use-titles: true
+ instant-day-if-all-sleeping: false
\ No newline at end of file