From f3723eb6f2d6abb87b1dc213081837ebbd779c7d Mon Sep 17 00:00:00 2001 From: OffLuffy Date: Fri, 13 Jul 2018 13:29:01 -0400 Subject: [PATCH] 1.0.8 - Added several placeholders - Made morning and sleeping subtitles and titles configurable with the ability to parse placeholders - Used apache.commons.lang StrSubstitutor instead of manually using String replace. - Added the option to instantly set time to day if everyone is sleeping. (More instant than vanilla) --- pom.xml | 2 +- .../me/offluffy/SmoothSleep/SmoothSleep.java | 146 ++++++++++++------ .../offluffy/SmoothSleep/lib/MiscUtils.java | 19 ++- .../listeners/PlayerEventsListener.java | 2 +- src/main/resources/config.yml | 22 ++- 5 files changed, 130 insertions(+), 61 deletions(-) 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