diff --git a/src/main/java/xyz/nkomarn/Harbor/Harbor.java b/src/main/java/xyz/nkomarn/Harbor/Harbor.java index b790df0..e642985 100644 --- a/src/main/java/xyz/nkomarn/Harbor/Harbor.java +++ b/src/main/java/xyz/nkomarn/Harbor/Harbor.java @@ -1,8 +1,6 @@ package xyz.nkomarn.Harbor; import com.earth2me.essentials.Essentials; -import org.bukkit.Bukkit; -import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; import xyz.nkomarn.Harbor.command.HarborCommand; import xyz.nkomarn.Harbor.listener.AfkListener; @@ -12,35 +10,32 @@ import xyz.nkomarn.Harbor.util.Config; import xyz.nkomarn.Harbor.util.Metrics; public class Harbor extends JavaPlugin { - public static Harbor instance; - public static String version = "1.6.2"; - public static Essentials essentials; + private static Harbor harbor; + private static Essentials essentials; + public static final String version = "1.6.2"; public void onEnable() { - instance = this; + harbor = this; saveDefaultConfig(); - Bukkit.getServer().getScheduler().runTaskTimerAsynchronously(this, - new Checker(), 0L, Config.getInteger("values.timer") * 20); - - final PluginManager pluginManager = getServer().getPluginManager(); - getCommand("harbor").setExecutor(new HarborCommand()); - pluginManager.registerEvents(new BedListener(), this); - - if (!Config.getString("version").equals(version)) { - getLogger().warning(String.format("The configuration version is '%s' but you're running Harbor " + - "version '%s'. Please update your configuration.", Config.getString("version"), version)); - } - - // bStats new Metrics(this); - // Essentials hook - essentials = (Essentials) getServer().getPluginManager().getPlugin("Essentials"); + getCommand("harbor").setExecutor(new HarborCommand()); + getServer().getPluginManager().registerEvents(new BedListener(), this); + getServer().getScheduler().runTaskTimerAsynchronously(this, + new Checker(), 0L, Config.getInteger("interval") * 20); - // If Essentials isn't present, enable fallback AFK system - if (essentials == null) { + essentials = (Essentials) getServer().getPluginManager().getPlugin("Essentials"); + if (essentials == null) { // If Essentials isn't present, enable fallback AFK system getLogger().info("Essentials not present- registering fallback AFK detection system."); getServer().getPluginManager().registerEvents(new AfkListener(), this); } } + + public static Harbor getHarbor() { + return harbor; + } + + public static Essentials getEssentials() { + return essentials; + } } diff --git a/src/main/java/xyz/nkomarn/Harbor/command/HarborCommand.java b/src/main/java/xyz/nkomarn/Harbor/command/HarborCommand.java index fa00e19..2ba7522 100644 --- a/src/main/java/xyz/nkomarn/Harbor/command/HarborCommand.java +++ b/src/main/java/xyz/nkomarn/Harbor/command/HarborCommand.java @@ -32,7 +32,7 @@ public class HarborCommand implements TabExecutor { } if (args[0].equalsIgnoreCase("reload")) { - Harbor.instance.reloadConfig(); + Harbor.getHarbor().reloadConfig(); sender.sendMessage(ChatColor.translateAlternateColorCodes('&', prefix + "&7Reloaded configuration.")); return true; @@ -54,7 +54,7 @@ public class HarborCommand implements TabExecutor { } Checker.skippingWorlds.add(world); - new AccelerateNightTask(world).runTaskTimer(Harbor.instance, 0L, 1); + new AccelerateNightTask(world).runTaskTimer(Harbor.getHarbor(), 0L, 1); sender.sendMessage(ChatColor.translateAlternateColorCodes('&', prefix + "&7Forcing night skip in your world.")); return true; diff --git a/src/main/java/xyz/nkomarn/Harbor/listener/BedListener.java b/src/main/java/xyz/nkomarn/Harbor/listener/BedListener.java index ec5d3b4..43835a0 100644 --- a/src/main/java/xyz/nkomarn/Harbor/listener/BedListener.java +++ b/src/main/java/xyz/nkomarn/Harbor/listener/BedListener.java @@ -15,7 +15,7 @@ public class BedListener implements Listener { public void onBedEnter(final PlayerBedEnterEvent event) { if (event.getBedEnterResult() != PlayerBedEnterEvent.BedEnterResult.OK) return; if (Checker.skippingWorlds.contains(event.getPlayer().getWorld())) return; - Bukkit.getScheduler().runTaskLater(Harbor.instance, () -> Messages.sendWorldChatMessage(event.getBed().getWorld(), + Bukkit.getScheduler().runTaskLater(Harbor.getHarbor(), () -> Messages.sendWorldChatMessage(event.getBed().getWorld(), Config.getString("messages.chat.sleeping") .replace("[player]", event.getPlayer().getName()) .replace("[displayname]", event.getPlayer().getDisplayName())), 1); diff --git a/src/main/java/xyz/nkomarn/Harbor/task/AccelerateNightTask.java b/src/main/java/xyz/nkomarn/Harbor/task/AccelerateNightTask.java index b8ec30f..b789dbb 100644 --- a/src/main/java/xyz/nkomarn/Harbor/task/AccelerateNightTask.java +++ b/src/main/java/xyz/nkomarn/Harbor/task/AccelerateNightTask.java @@ -1,10 +1,8 @@ package xyz.nkomarn.Harbor.task; -import org.bukkit.Bukkit; import org.bukkit.Statistic; import org.bukkit.World; import org.bukkit.scheduler.BukkitRunnable; -import xyz.nkomarn.Harbor.Harbor; import xyz.nkomarn.Harbor.util.Config; import xyz.nkomarn.Harbor.util.Messages; @@ -13,23 +11,16 @@ public class AccelerateNightTask extends BukkitRunnable { public AccelerateNightTask(final World world) { this.world = world; + Messages.sendRandomChatMessage(world, "messages.chat.night-skipping"); } @Override public void run() { final long time = world.getTime(); - final int interval = Config.getInteger("values.interval"); - - // Variable interval based on player count - - if (!(time >= 450 && time <= 1000)) { - world.setTime(time + interval); - } else { - if (!Config.getBoolean("features.phantoms")) { - world.getPlayers().forEach(player -> - player.setStatistic(Statistic.TIME_SINCE_REST, 0)); - } + final int dayTime = Config.getInteger("night-skip.daytime-ticks"); + final int timeRate = Config.getInteger("night-skip.time-rate"); + if (time >= (dayTime - timeRate * 2) && time <= dayTime) { if (Config.getBoolean("features.clear-rain")) { world.setStorm(false); } @@ -38,9 +29,15 @@ public class AccelerateNightTask extends BukkitRunnable { world.setThundering(false); } + if (Config.getBoolean("night-skip.reset-phantom-statistic")) { + world.getPlayers().forEach(player -> player.setStatistic(Statistic.TIME_SINCE_REST, 0)); + } + Checker.skippingWorlds.remove(world); - Messages.sendRandomChatMessage(world, "messages.chat.skipped"); + Messages.sendRandomChatMessage(world, "messages.chat.night-skipped"); this.cancel(); + } else { + world.setTime(time + timeRate); } } } diff --git a/src/main/java/xyz/nkomarn/Harbor/task/Checker.java b/src/main/java/xyz/nkomarn/Harbor/task/Checker.java index 2927858..ab328bf 100644 --- a/src/main/java/xyz/nkomarn/Harbor/task/Checker.java +++ b/src/main/java/xyz/nkomarn/Harbor/task/Checker.java @@ -22,36 +22,35 @@ public class Checker implements Runnable { @Override public void run() { - Bukkit.getOnlinePlayers() - .stream() - .map(Player::getWorld).distinct() - .filter(this::validateWorld) - .forEach(this::checkWorld); + Bukkit.getWorlds().stream().filter(this::validateWorld).forEach(this::checkWorld); } private void checkWorld(final World world) { final int sleeping = getSleeping(world).size(); final int needed = getNeeded(world); - // Send actionbar sleeping notification if (sleeping > 0 && needed > 0) { - double percentage = Math.min(1, (double) sleeping / getSkipAmount(world)); + // TODO redo bossbars + final double sleepingPercentage = Math.min(1, (double) sleeping / getSkipAmount(world)); Messages.sendBossBarMessage(world, Config.getString("messages.bossbar.sleeping.message"), - BarColor.valueOf(Config.getString("messages.bossbar.sleeping.color")), percentage); - Messages.sendActionBarMessage(world, Config.getString("messages.actionbar.sleeping")); + BarColor.valueOf(Config.getString("messages.bossbar.sleeping.color")), sleepingPercentage); + + + Messages.sendActionBarMessage(world, Config.getString("messages.actionbar.players-sleeping")); } else if (needed == 0 && sleeping > 0) { Messages.sendBossBarMessage(world, Config.getString("messages.bossbar.everyone.message"), BarColor.valueOf(Config.getString("messages.bossbar.everyone.color")), 1); - Messages.sendActionBarMessage(world, Config.getString("messages.actionbar.everyone")); - if (!Config.getBoolean("features.skip")) return; - if (Config.getBoolean("features.instant-skip")) { - world.setTime(1000); + Messages.sendActionBarMessage(world, Config.getString("messages.actionbar.night-skipping")); + + if (!Config.getBoolean("night-skip.enabled")) return; + + if (Config.getBoolean("night-skip.instant-skip")) { + world.setTime(Config.getInteger("night-skip.daytime-ticks")); } else { skippingWorlds.add(world); - new AccelerateNightTask(world).runTaskTimer(Harbor.instance, 0L, 1); + new AccelerateNightTask(world).runTaskTimer(Harbor.getHarbor(), 1, 1); } - Messages.sendRandomChatMessage(world, "messages.chat.accelerateNight"); } } @@ -62,7 +61,7 @@ public class Checker implements Runnable { } private boolean isBlacklisted(final World world) { - return Config.getList("blacklist").contains(world.getName()); + return Config.getList("blacklisted-worlds").contains(world.getName()); } private boolean isNight(final World world) { @@ -74,7 +73,7 @@ public class Checker implements Runnable { } public static int getSkipAmount(final World world) { - return (int) Math.ceil(getPlayers(world) * (Config.getDouble("values.percent") / 100)); + return (int) Math.ceil(getPlayers(world) * (Config.getDouble("night-skip.percentage") / 100)); } public static int getPlayers(final World world) { @@ -83,7 +82,7 @@ public class Checker implements Runnable { public static int getNeeded(final World world) { return Math.max(0, (int) Math.ceil((getPlayers(world)) - * (Config.getDouble("values.percent") / 100) + * (Config.getDouble("night-skip.percentage") / 100) - getSleeping(world).size())); } @@ -92,12 +91,14 @@ public class Checker implements Runnable { } private static boolean isExcluded(final Player player) { - final boolean excludedByGameMode = Config.getBoolean("features.ignore") && player.getGameMode() != GameMode.SURVIVAL; - final boolean excludedByPermission = Config.getBoolean("features.bypass") && player.hasPermission("harbor.bypass"); + final boolean excludedByCreative = Config.getBoolean("exclusions.exclude-creative") && player.getGameMode() == GameMode.CREATIVE; + final boolean excludedBySpectator = Config.getBoolean("exclusions.exclude-spectator") && player.getGameMode() == GameMode.SPECTATOR; + final boolean excludedByPermission = Config.getBoolean("exclusions.bypass-permission") && player.hasPermission("harbor.bypass"); final boolean excludedByAfk = Afk.isAfk(player); - if (Config.getBoolean("features.vanish")) { + + if (Config.getBoolean("exclusions.exclude-vanished")) { for (MetadataValue meta : player.getMetadata("vanished")) if (meta.asBoolean()) return true; } - return excludedByGameMode || excludedByPermission || excludedByAfk; + return excludedByCreative || excludedBySpectator || excludedByPermission || excludedByAfk; } } diff --git a/src/main/java/xyz/nkomarn/Harbor/util/Afk.java b/src/main/java/xyz/nkomarn/Harbor/util/Afk.java index 20eed90..0a57bee 100644 --- a/src/main/java/xyz/nkomarn/Harbor/util/Afk.java +++ b/src/main/java/xyz/nkomarn/Harbor/util/Afk.java @@ -10,15 +10,15 @@ public class Afk { private static HashMap activity = new HashMap<>(); public static boolean isAfk(Player player) { - if (!Config.getBoolean("features.afk")) return false; + if (!Config.getBoolean("afk-detection.enabled")) return false; - if (Harbor.essentials != null) { - return Harbor.essentials.getUser(player).isAfk(); + if (Harbor.getEssentials() != null) { + return Harbor.getEssentials().getUser(player).isAfk(); } if (!activity.containsKey(player)) return false; long minutes = TimeUnit.MILLISECONDS.toMinutes(System.currentTimeMillis() - activity.get(player)); - return minutes >= Config.getInteger("values.timeout"); + return minutes >= Config.getInteger("afk-detection.timeout"); } public static void updateActivity(Player player) { diff --git a/src/main/java/xyz/nkomarn/Harbor/util/Config.java b/src/main/java/xyz/nkomarn/Harbor/util/Config.java index 8cc4676..42a63cb 100644 --- a/src/main/java/xyz/nkomarn/Harbor/util/Config.java +++ b/src/main/java/xyz/nkomarn/Harbor/util/Config.java @@ -13,7 +13,7 @@ public class Config { * @param location Configuration location of the boolean */ public static boolean getBoolean(final String location) { - return Harbor.instance.getConfig().getBoolean(location, false); + return Harbor.getHarbor().getConfig().getBoolean(location, false); } /** @@ -23,7 +23,7 @@ public class Config { * @param location Configuration location of the string */ public static String getString(final String location) { - return Harbor.instance.getConfig().getString(location, ""); + return Harbor.getHarbor().getConfig().getString(location, ""); } /** @@ -33,7 +33,7 @@ public class Config { * @param location Configuration location of the integer */ public static int getInteger(final String location) { - return Harbor.instance.getConfig().getInt(location, 0); + return Harbor.getHarbor().getConfig().getInt(location, 0); } /** @@ -43,7 +43,7 @@ public class Config { * @param location Configuration location of the double */ public static double getDouble(final String location) { - return Harbor.instance.getConfig().getDouble(location, 0.0); + return Harbor.getHarbor().getConfig().getDouble(location, 0.0); } /** @@ -53,6 +53,6 @@ public class Config { * @param location Configuration location of the list */ public static List getList(final String location) { - return (List) Harbor.instance.getConfig().getList(location, new ArrayList<>()); + return (List) Harbor.getHarbor().getConfig().getList(location, new ArrayList<>()); } } diff --git a/src/main/java/xyz/nkomarn/Harbor/util/Messages.java b/src/main/java/xyz/nkomarn/Harbor/util/Messages.java index 076f2fd..1a18c4b 100644 --- a/src/main/java/xyz/nkomarn/Harbor/util/Messages.java +++ b/src/main/java/xyz/nkomarn/Harbor/util/Messages.java @@ -23,23 +23,23 @@ public class Messages { } public static void sendWorldChatMessage(final World world, final String message) { - if (!Config.getBoolean("messages.chat.chat") || message.length() < 1) return; + if (!Config.getBoolean("messages.chat.enabled") || message.length() < 1) return; world.getPlayers().forEach(player -> player.sendMessage(ChatColor.translateAlternateColorCodes('&', prepareMessage(world, message)))); } public static void sendActionBarMessage(final World world, final String message) { - if (!Config.getBoolean("messages.actionbar.actionbar") || message.length() < 1) return; + if (!Config.getBoolean("messages.actionbar.enabled") || message.length() < 1) return; world.getPlayers().forEach(player -> player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(prepareMessage(world, message)))); } public static void sendBossBarMessage(final World world, final String message, final BarColor color, final double percentage) { - if (!Config.getBoolean("messages.bossbar.bossbar") || message.length() < 1) return; + if (!Config.getBoolean("messages.bossbar.enabled") || message.length() < 1) return; BossBar bar = Bukkit.createBossBar(Messages.prepareMessage(world, message), color, BarStyle.SOLID); bar.setProgress(percentage); world.getPlayers().forEach(bar::addPlayer); - Bukkit.getScheduler().runTaskLater(Harbor.instance, bar::removeAll, Config.getInteger("values.timer") * 20); + Bukkit.getScheduler().runTaskLater(Harbor.getHarbor(), bar::removeAll, Config.getInteger("interval") * 20); } private static String prepareMessage(final World world, final String message) { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index f4c45a0..bd4182d 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,72 +1,69 @@ -# Harbor - A Sleep Enhancement Plugin! -# An open-source project by Mykyta (TechToolbox) -# https://harbor.nkomarn.xyz +# Harbor - Sleep mechanics enhancement plugin +# An open-source project by TechToolbox (@nkomarn) +# https://github.com/nkomarn/Harbor -# Ahoy, matey! You've arrived at the configuration file, where things get a bit scary. -# Every single thing within this plugin is customizable (at least I tried to make it that way), -# so every message and plugin module can be modified here. If you would like to report a bug -# or suggest a feature, make sure to add an issue on the GitHub page for this plugin! -# GitHub URL: https://github.com/nkomarn/Harbor/issues +# Important note regarding Essentials: +# Please make sure you negate the permission "essentials.sleepingignored" to prevent issues with Harbor and server operators -# Important note regarding Essentials -# Please make sure you negate the permission "essentials.sleepingignored" -# to prevent issues with Harbor and server operators +night-skip: + enabled: true # Skip the night if a percentage of the players in a world are sleeping + percentage: 50 # Percentage of players required to be sleeping to skip the night (0 - 100) + time-rate: 60 # The amount of ticks added to the current time every tick when skipping the night + daytime-ticks: 1000 # The time in ticks that Harbor considers day TODO + instant-skip: false # Instantly skip the night instead of showing the full animation + variable-speed: false # Increase the night skipping speed based on the amount of sleeping players + speed-multiplier: 0.5 # Multiplier used for variable night skipping (TODO explain formula) + clear-rain: true # Clear rain (if it's raining) when the night is skipped + clear-thunder: true # Clear thunder (if it's thundering) when the night is skipped + reset-phantom-statistic: true # Treats everyone online as if they have slept in the last 3 days after the night is skipped (check out /gamerule doInsomnia on 1.15+) -values: - timer: 2 # How often (in seconds) to run the clock task (used to detect sleep, AFK players, time actionbar, etc.) - percent: 50 # Percent of players that need to sleep to skip night (must be between 0 to 100) - interval: 60 # Time skip interval that is added when the night is accelerated. - multiplier: 0.4 # Used as the variable multiplier for the variable-interval feature. - timeout: 15 # Time (in minutes) until a player is considered AFK (for internal AFK detection system only- when Essentials isn't present) +exclusions: + bypass-permission: true # Exclude players with the permission "harbor.bypass" from the sleeping count + exclude-creative: true # Exclude players in creative mode from the sleeping count + exclude-spectator: true # Exclude players in spectator mode from the sleeping count + exclude-vanished: true # Exclude vanished players from the sleeping count -features: - skip: true # Toggle night skipping feature. Configure amount of players needed to skip above (percent) - instant-skip: false # Toggle the instant skipping of night (instead of showing the full animation). Requires "skip" to be true. - variable-interval: false # Change the night skip tick interval based on the amount of online players - clear-rain: true # Clear rain when skipping the night - clear-thunder: true # Clear thunder when skipping the night - phantoms: false # Reset the sleep statistic (practically disables phantom spawns - false = no phantoms | Set the doInsomnia gamerule to false to disable phantoms if you're on 1.15+) - bypass: true # Toggle exclusion of operators/players with permission "harbor.bypass" from sleep count - ignore: true # Toggle exclusion of players in creative and spectator mode - exclude-vanished: true # Toggle exclusion of vanished players - afk: true # Detect AFK players and remove them from the sleep count (Essentials API used for detection when possible) +# Detect AFK players and automatically remove them from the required sleeping count +# Essentials API is used for AFK detection when available- otherwise a fallback system is used +afk-detection: + enabled: true + timeout: 15 # Time in minutes until a player is considered AFK -messages: - chat: - chat: true # Toggle chat messages - skipped: # Night skipped chat messages - - "&eThe night has been skipped." - - "&eAhhh, finally morning." - - "&eArghh, it's so bright outside." - sleeping: "&e[player] is now sleeping ([sleeping]/[needed], [more] more needed to skip)." # Display which player went to bed - left: "&e[player] got out of bed ([sleeping]/[needed], [more] more needed to skip)." # Display when a player left their bed - accelerateNight: # Display when the night is being accelerated. - - "&eAccelerating the night." - - "&eRapidly approaching daytime." - actionbar: - actionbar: true # Enable/disable actionbar messages - sleeping: "&e[sleeping] out of [needed] players are sleeping ([more] more needed to skip)." # Shown when some players are in bed - everyone: "&eEveryone is sleeping. Sweet dreams!" # Shown when all players are in bed - bossbar: # Use colors from https://hub.spigotmc.org/javadocs/spigot/org/bukkit/boss/BarColor.html - bossbar: true # Enable/disable bossbar messages - sleeping: - message: "&f&l[sleeping] out of [needed] are sleeping &7&l([more] more needed)" # Shown when some players are in bed - color: BLUE - everyone: - message: "&f&lEveryone is sleeping. Sweet dreams!" # Shown when all players are in bed - color: GREEN - miscellaneous: - prefix: "&8&l(&6&lHarbor&8&l)&r " # Prefix for Harbor command/miscellaneous messages - permission: "&7Insufficient permissions." # Sent when player doesn't have permissions to run command - unrecognized: "&7Unrecognized command." # Sent when command argument isn't recognized - -# Blacklist for worlds -# Harbor will be disabled in these worlds -blacklist: +# Blacklist for worlds- Harbor will ignore these worlds +blacklisted-worlds: - "world_nether" - "world_the_end" -# Spooky controls -# (don't change) +messages: + chat: + enabled: true + player-sleeping: "&e[player] is now sleeping ([sleeping]/[needed], [more] more needed to skip)." + player-left-bed: "&e[player] got out of bed ([sleeping]/[needed], [more] more needed to skip)." + night-skipping: + - "&eAccelerating the night." + - "&eRapidly approaching daytime." + night-skipped: + - "&eThe night has been skipped." + - "&eAhhh, finally morning." + - "&eArghh, it's so bright outside." + actionbar: + enabled: true + players-sleeping: "&e[sleeping] out of [needed] players are sleeping ([more] more needed to skip)." + night-skipping: "&eEveryone is sleeping. Sweet dreams!" + bossbar: + enabled: true + players-sleeping: + message: "&f&l[sleeping] out of [needed] are sleeping &7&l([more] more needed)" + color: BLUE + night-skipping: + message: "&f&lEveryone is sleeping. Sweet dreams!" + color: GREEN + miscellaneous: + chat-prefix: "&8&l(&6&lHarbor&8&l)&7 " + insufficient-permissions: "Insufficient permissions." + unrecognized-command: "Unrecognized command." + +# Spooky internal controls version: 1.6.2 +interval: 2 debug: false