diff --git a/1.7.10/build.gradle b/1.7.10/build.gradle index daf22a6..e01b7a7 100644 --- a/1.7.10/build.gradle +++ b/1.7.10/build.gradle @@ -26,12 +26,8 @@ buildscript apply plugin: 'forge' apply from: '../common.gradle' -minecraft -{ - version = "1.7.10-10.13.4.1448-1.7.10" -} +// Sets the Forge version to use +minecraft.version = "1.7.10-10.13.4.1448-1.7.10" -jar -{ - classifier "1.7.10" -} \ No newline at end of file +// Sets the built jar's suffix +jar.classifier "1.7.10" \ No newline at end of file diff --git a/1.7.10/src/main/java/roycurtis/autoshutdown/Config.java b/1.7.10/src/main/java/roycurtis/autoshutdown/Config.java index cdcf6f1..96debc8 100644 --- a/1.7.10/src/main/java/roycurtis/autoshutdown/Config.java +++ b/1.7.10/src/main/java/roycurtis/autoshutdown/Config.java @@ -1,6 +1,7 @@ package roycurtis.autoshutdown; import net.minecraftforge.common.config.Configuration; +import org.apache.logging.log4j.Logger; import java.io.File; @@ -19,6 +20,7 @@ class Config static boolean scheduleEnabled = true; static boolean scheduleWarning = true; static boolean scheduleDelay = false; + static boolean scheduleUptime = false; static int scheduleHour = 6; static int scheduleMinute = 0; static int scheduleDelayBy = 5; @@ -51,15 +53,18 @@ static void init(File configFile) "All times are 24 hour (military) format, relative to machine's local time"); scheduleEnabled = config.getBoolean("Enabled", SCHEDULE, scheduleEnabled, - "If true, server will automatically shutdown at given time of day"); + "If true, server will automatically shutdown"); scheduleWarning = config.getBoolean("Warnings", SCHEDULE, scheduleWarning, "If true, server will give five minutes of warnings prior to shutdown"); scheduleDelay = config.getBoolean("Delay", SCHEDULE, scheduleDelay, "If true, server will delay shutdown until server is empty"); - scheduleHour = config.getInt("Hour", SCHEDULE, scheduleHour, 0, 23, - "Hour of the shutdown process (e.g. 8 for 8 AM)"); + scheduleUptime = config.getBoolean("Uptime", SCHEDULE, scheduleUptime, + "If true, server will use Hour and Minute as uptime until shutdown.\n" + + "If false, server will use Hour and Minute as time of day to shutdown."); + scheduleHour = config.getInt("Hour", SCHEDULE, scheduleHour, 0, 720, + "Hour of the shutdown process (e.g. 8 for 8 AM OR 8 hours uptime)"); scheduleMinute = config.getInt("Minute", SCHEDULE, scheduleMinute, 0, 59, - "Minute of the shutdown process (e.g. 30 for half-past)"); + "Minute of the shutdown process (e.g. 30 for half-past OR 30 mins uptime)"); scheduleDelayBy = config.getInt( "DelayBy", SCHEDULE, scheduleDelayBy, 1, 1440, @@ -104,9 +109,35 @@ static void init(File configFile) msgKick = config.getString("Kick", MESSAGES, msgKick, "Message shown to player on disconnect during shutdown"); + check(); config.save(); } + /** + * Checks the loaded configuration and makes adjustments based on other config + */ + static void check() + { + final Logger LOGGER = ForgeAutoShutdown.LOGGER; + + // Ensure daily shutdown hour is not set to more than 23:00 + if (!scheduleUptime && scheduleHour >= 24) + { + LOGGER.warn("Uptime shutdown is disabled, but the shutdown hour is more " + + "than 23! Please fix this in the config. It will be set to 00 hours."); + scheduleHour = 0; + } + + // Ensure uptime shutdown is not set to zero hours zero minutes + if (scheduleUptime && scheduleHour == 0 && scheduleMinute == 0) + { + LOGGER.warn("Uptime shutdown is enabled, but is set to shutdown after " + + "0 hours and 0 minutes of uptime! Please fix this in the config. " + + "It will be set to 24 hours."); + scheduleHour = 24; + } + } + static boolean isNothingEnabled() { return !scheduleEnabled && !voteEnabled && !watchdogEnabled; diff --git a/1.7.10/src/main/java/roycurtis/autoshutdown/ShutdownTask.java b/1.7.10/src/main/java/roycurtis/autoshutdown/ShutdownTask.java index eb6d425..1ec94a7 100644 --- a/1.7.10/src/main/java/roycurtis/autoshutdown/ShutdownTask.java +++ b/1.7.10/src/main/java/roycurtis/autoshutdown/ShutdownTask.java @@ -44,14 +44,23 @@ public static void create() Timer timer = new Timer("ForgeAutoShutdown timer"); Calendar shutdownAt = Calendar.getInstance(); - shutdownAt.set(Calendar.HOUR_OF_DAY, Config.scheduleHour); - shutdownAt.set(Calendar.MINUTE, Config.scheduleMinute); - shutdownAt.set(Calendar.SECOND, 0); - // Adjust for when current time surpasses shutdown schedule - // (e.g. if shutdown time is 07:00 and current time is 13:21) - if ( shutdownAt.before( Calendar.getInstance() ) ) - shutdownAt.add(Calendar.DAY_OF_MONTH, 1); + if (Config.scheduleUptime) + { + shutdownAt.add(Calendar.HOUR_OF_DAY, Config.scheduleHour); + shutdownAt.add(Calendar.MINUTE, Config.scheduleMinute); + } + else + { + shutdownAt.set(Calendar.HOUR_OF_DAY, Config.scheduleHour); + shutdownAt.set(Calendar.MINUTE, Config.scheduleMinute); + shutdownAt.set(Calendar.SECOND, 0); + + // Adjust for when current time surpasses shutdown schedule + // (e.g. if shutdown time is 07:00 and current time is 13:21) + if ( shutdownAt.before( Calendar.getInstance() ) ) + shutdownAt.add(Calendar.DAY_OF_MONTH, 1); + } Date shutdownAtDate = shutdownAt.getTime(); @@ -98,11 +107,12 @@ public void onServerTick(TickEvent.ServerTickEvent event) } if (Config.scheduleWarning && warningsLeft > 0) + { performWarning(); + LOGGER.debug("ShutdownTask ticked; %d warning(s) to go", warningsLeft); + } else Server.shutdown(Config.msgKick); - - LOGGER.debug("ShutdownTask ticked; %d warning(s) to go", warningsLeft); } private boolean performDelay() diff --git a/1.8/build.gradle b/1.8/build.gradle index f0c9336..d6eb60f 100644 --- a/1.8/build.gradle +++ b/1.8/build.gradle @@ -26,12 +26,8 @@ buildscript apply plugin: 'forge' apply from: '../common.gradle' -minecraft -{ - version = "1.8-11.14.3.1450" -} +// Sets the Forge version to use +minecraft.version = "1.8-11.14.3.1450" -jar -{ - classifier "1.8" -} \ No newline at end of file +// Sets the built jar's suffix +jar.classifier "1.8" \ No newline at end of file diff --git a/1.8/src/main/java/roycurtis/autoshutdown/Config.java b/1.8/src/main/java/roycurtis/autoshutdown/Config.java index cdcf6f1..96debc8 100644 --- a/1.8/src/main/java/roycurtis/autoshutdown/Config.java +++ b/1.8/src/main/java/roycurtis/autoshutdown/Config.java @@ -1,6 +1,7 @@ package roycurtis.autoshutdown; import net.minecraftforge.common.config.Configuration; +import org.apache.logging.log4j.Logger; import java.io.File; @@ -19,6 +20,7 @@ class Config static boolean scheduleEnabled = true; static boolean scheduleWarning = true; static boolean scheduleDelay = false; + static boolean scheduleUptime = false; static int scheduleHour = 6; static int scheduleMinute = 0; static int scheduleDelayBy = 5; @@ -51,15 +53,18 @@ static void init(File configFile) "All times are 24 hour (military) format, relative to machine's local time"); scheduleEnabled = config.getBoolean("Enabled", SCHEDULE, scheduleEnabled, - "If true, server will automatically shutdown at given time of day"); + "If true, server will automatically shutdown"); scheduleWarning = config.getBoolean("Warnings", SCHEDULE, scheduleWarning, "If true, server will give five minutes of warnings prior to shutdown"); scheduleDelay = config.getBoolean("Delay", SCHEDULE, scheduleDelay, "If true, server will delay shutdown until server is empty"); - scheduleHour = config.getInt("Hour", SCHEDULE, scheduleHour, 0, 23, - "Hour of the shutdown process (e.g. 8 for 8 AM)"); + scheduleUptime = config.getBoolean("Uptime", SCHEDULE, scheduleUptime, + "If true, server will use Hour and Minute as uptime until shutdown.\n" + + "If false, server will use Hour and Minute as time of day to shutdown."); + scheduleHour = config.getInt("Hour", SCHEDULE, scheduleHour, 0, 720, + "Hour of the shutdown process (e.g. 8 for 8 AM OR 8 hours uptime)"); scheduleMinute = config.getInt("Minute", SCHEDULE, scheduleMinute, 0, 59, - "Minute of the shutdown process (e.g. 30 for half-past)"); + "Minute of the shutdown process (e.g. 30 for half-past OR 30 mins uptime)"); scheduleDelayBy = config.getInt( "DelayBy", SCHEDULE, scheduleDelayBy, 1, 1440, @@ -104,9 +109,35 @@ static void init(File configFile) msgKick = config.getString("Kick", MESSAGES, msgKick, "Message shown to player on disconnect during shutdown"); + check(); config.save(); } + /** + * Checks the loaded configuration and makes adjustments based on other config + */ + static void check() + { + final Logger LOGGER = ForgeAutoShutdown.LOGGER; + + // Ensure daily shutdown hour is not set to more than 23:00 + if (!scheduleUptime && scheduleHour >= 24) + { + LOGGER.warn("Uptime shutdown is disabled, but the shutdown hour is more " + + "than 23! Please fix this in the config. It will be set to 00 hours."); + scheduleHour = 0; + } + + // Ensure uptime shutdown is not set to zero hours zero minutes + if (scheduleUptime && scheduleHour == 0 && scheduleMinute == 0) + { + LOGGER.warn("Uptime shutdown is enabled, but is set to shutdown after " + + "0 hours and 0 minutes of uptime! Please fix this in the config. " + + "It will be set to 24 hours."); + scheduleHour = 24; + } + } + static boolean isNothingEnabled() { return !scheduleEnabled && !voteEnabled && !watchdogEnabled; diff --git a/1.8/src/main/java/roycurtis/autoshutdown/ShutdownTask.java b/1.8/src/main/java/roycurtis/autoshutdown/ShutdownTask.java index 1a61a4e..fc77d6d 100644 --- a/1.8/src/main/java/roycurtis/autoshutdown/ShutdownTask.java +++ b/1.8/src/main/java/roycurtis/autoshutdown/ShutdownTask.java @@ -44,14 +44,23 @@ public static void create() Timer timer = new Timer("ForgeAutoShutdown timer"); Calendar shutdownAt = Calendar.getInstance(); - shutdownAt.set(Calendar.HOUR_OF_DAY, Config.scheduleHour); - shutdownAt.set(Calendar.MINUTE, Config.scheduleMinute); - shutdownAt.set(Calendar.SECOND, 0); - // Adjust for when current time surpasses shutdown schedule - // (e.g. if shutdown time is 07:00 and current time is 13:21) - if ( shutdownAt.before( Calendar.getInstance() ) ) - shutdownAt.add(Calendar.DAY_OF_MONTH, 1); + if (Config.scheduleUptime) + { + shutdownAt.add(Calendar.HOUR_OF_DAY, Config.scheduleHour); + shutdownAt.add(Calendar.MINUTE, Config.scheduleMinute); + } + else + { + shutdownAt.set(Calendar.HOUR_OF_DAY, Config.scheduleHour); + shutdownAt.set(Calendar.MINUTE, Config.scheduleMinute); + shutdownAt.set(Calendar.SECOND, 0); + + // Adjust for when current time surpasses shutdown schedule + // (e.g. if shutdown time is 07:00 and current time is 13:21) + if ( shutdownAt.before( Calendar.getInstance() ) ) + shutdownAt.add(Calendar.DAY_OF_MONTH, 1); + } Date shutdownAtDate = shutdownAt.getTime(); @@ -98,11 +107,12 @@ public void onServerTick(TickEvent.ServerTickEvent event) } if (Config.scheduleWarning && warningsLeft > 0) + { performWarning(); + LOGGER.debug("ShutdownTask ticked; %d warning(s) to go", warningsLeft); + } else Server.shutdown(Config.msgKick); - - LOGGER.debug("ShutdownTask ticked; %d warning(s) to go", warningsLeft); } private boolean performDelay() diff --git a/README.md b/README.md index eb83e0b..3dc17a2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ForgeAutoShutdown is a server-only mod that can: -* Schedules a specific time of the day for the server to shut down. This allows the server to be automatically restarted daily by a shell script, Windows batch file or service. -* Allow players to vote for a manual shutdown, so a lagged out server would not require admin intervention +* Schedule the server to automatically shut down at a specific time of day, or after X hours and minutes of uptime. This allows the server to be automatically restarted by a shell script, Windows batch file or service. +* Allow players to vote for a manual shutdown, so a lagged out server does not require admin intervention * Shutdown or kill a server that is hung (stalled) or laggy # Requirements @@ -23,14 +23,17 @@ ForgeAutoShutdown is a server-only mod that can: *Any of these features may be disabled in the config* -## Scheduled daily shutdown +## Scheduled shutdown ForgeAutoShutdown will log a message at the INFO level on server startup, with a date and time of the next scheduled shutdown. For example: `[10:50:09] [Server thread/INFO] [ForgeAutoShutdown]: Next automatic shutdown: 08:30:00 19-June-2015` If this message is missing, the mod has not been correctly installed or the schedule is disabled in config. If the mod is installed on a Minecraft client, it will log an ERROR to the console and not perform any function. It will not crash or disable the client. -Scheduled shutdown will always happen within the next 24 hours after server startup. This means that if the server starts and has missed the shutdown time even by a few minutes, it will schedule for the next day. +### Mode +By default, the shutdown will be scheduled to happen at a specific time of day. This is the time local to the server and will always happen within the next 24 hours after server startup. This means that if the server starts and has missed the shutdown time even by a few minutes, it will schedule for the next day. + +Alternatively, setting `Uptime` to true means the server can shutdown after a specific amount of hours or minutes instead. This can allow the server to restart multiple times a day, or after a few days, etc. ### Warnings By default a scheduled shutdown will give a warning to all players, each minute for five minutes, after the scheduled time. This can be disabled by setting `Warnings` to `false`. This means the server will shutdown, without warning, by the scheduled time. @@ -40,7 +43,6 @@ If desired, the shutdown can be delayed by a configurable amount if players are The shutdown will be repeatedly delayed until the server is empty. When checking if the server for players, fake players (e.g. BuildCraft's quarry) are excluded. Note that shutdown warnings are ineffective with delays, and a pending shutdown will be cancelled if a player comes online during the countdown. - ## Voting If enabled, players may vote a manual shutdown. To do so, a player must execute `/shutdown`. Then, **all** players (including the vote initiator) must vote using `/shutdown yes` or `/shutdown no`. diff --git a/common.gradle b/common.gradle index 0a13b53..11d1154 100644 --- a/common.gradle +++ b/common.gradle @@ -1,61 +1,65 @@ -/** - * Common build properties for all versions of ForgeAutoShutdown - */ - -version = "1.0.6" -group = "roycurtis.autoshutdown" - -// Specifies the output jar file's prefix -archivesBaseName = "ForgeAutoShutdown" - -minecraft -{ - runDir = "debug" -} - -jar -{ - // Sets the output directory of the mod's jar file - destinationDir = file '../output' -} - -compileJava -{ - // Enforces use of Java 1.7 language level - sourceCompatibility = "1.8" - targetCompatibility = "1.8" -} - -idea -{ - module - { - outputDir = file 'classes/production/' - testOutputDir = file 'classes/test/' - } -} - -processResources -{ - inputs.property "modid", project.archivesBaseName - inputs.property "version", project.version - inputs.property "mcversion", project.minecraft.version - - // Only replace properties in mcmod.info - from(sourceSets.main.resources.srcDirs) - { - include 'mcmod.info' - - // replace version and mcversion - expand ( - 'modid' : project.archivesBaseName, - 'version' : project.version, - 'mcversion' : project.minecraft.version - ) - } - - from(sourceSets.main.resources.srcDirs) - { - exclude 'mcmod.info' - } +/** + * Common build properties for all versions of ForgeAutoShutdown + */ + +// Gradle project properties +version = "1.0.7" +group = "roycurtis.autoshutdown" + +// Specifies the output jar file's prefix +archivesBaseName = "ForgeAutoShutdown" + +// Specifies the working directory for ForgeGradle run configs +minecraft.runDir = "debug" + +// Sets the output directory of the mod's jar file +jar.destinationDir = file '../output' + +// Enforces use of Java 1.8 language level +compileJava +{ + sourceCompatibility = "1.8" + targetCompatibility = "1.8" +} + +// Fixes issues with debugging in IntelliJ +idea +{ + module + { + outputDir = file 'classes/production/' + testOutputDir = file 'classes/test/' + } +} + +// Fixes issues with ยต character in source files +// From https://discuss.gradle.org/t/special-characters-in-java-string-literals-arent-interpreted-correctly/4665 +tasks.withType(JavaCompile) +{ + options.encoding = "UTF-8" +} + +processResources +{ + inputs.property "modid", project.archivesBaseName + inputs.property "version", project.version + inputs.property "mcversion", project.minecraft.version + + // Only replace properties in mcmod.info + from(sourceSets.main.resources.srcDirs) + { + include 'mcmod.info' + + // replace version and mcversion + expand ( + 'modid' : project.archivesBaseName, + 'version' : project.version, + 'mcversion' : project.minecraft.version + ) + } + + from(sourceSets.main.resources.srcDirs) + { + exclude 'mcmod.info' + } } \ No newline at end of file