Skip to content

Commit

Permalink
Accept time durations in timer commands
Browse files Browse the repository at this point in the history
Closes #134
  • Loading branch information
kennytv committed Sep 13, 2024
1 parent f9396fa commit 05af3d3
Show file tree
Hide file tree
Showing 29 changed files with 143 additions and 110 deletions.
2 changes: 2 additions & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ This file contains update logs for this project. The top may contain a `Unreleas
## Unreleased
### Changed
* Added alternative player count and player list hover message for when endtimers are running, similar to the existing ping messages setting. They are disabled by default and can be found in their `player-count-message` and `player-list-hover-message` config sections
* All timer commands now accept durations like `2h30m`, `1h30m5s`, or `90s`. The default behavior without units will still be in minutes
* The language defaults will not automatically update, you might want to manually update the command help strings or just delete your language file
* Slightly reorganized the configuration file (it will be automatically migrated on startup, but new sections will be slapped at the bottom of the file)
* The `fallback` field now also null values next to an empty array for disabling the feature
* Updated language files from [Crowdin](https://crowdin.com/translate/maintenance)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,22 @@
import eu.kennytv.maintenance.core.util.SenderInfo;
import eu.kennytv.maintenance.core.util.ServerType;
import eu.kennytv.maintenance.core.util.Task;
import org.jetbrains.annotations.Blocking;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.jetbrains.annotations.Blocking;
import org.jetbrains.annotations.Nullable;

/**
* @author kennytv
Expand Down Expand Up @@ -146,15 +145,15 @@ public void cancelSingleTask(final Server server) {
}
}

public MaintenanceRunnableBase startSingleMaintenanceRunnable(final Server server, final long duration, final TimeUnit unit, final boolean enable) {
final MaintenanceRunnableBase runnable = new SingleMaintenanceRunnable(this, settingsProxy, (int) unit.toSeconds(duration), enable, server);
public MaintenanceRunnableBase startSingleMaintenanceRunnable(final Server server, final Duration duration, final boolean enable) {
final MaintenanceRunnableBase runnable = new SingleMaintenanceRunnable(this, settingsProxy, (int) duration.getSeconds(), enable, server);
serverTasks.put(server.getName(), runnable.getTask());
return runnable;
}

public MaintenanceRunnableBase scheduleSingleMaintenanceRunnable(final Server server, final long duration, final long maintenanceDuration, final TimeUnit unit) {
public MaintenanceRunnableBase scheduleSingleMaintenanceRunnable(final Server server, final Duration enableIn, final Duration maintenanceDuration) {
final MaintenanceRunnableBase runnable = new SingleMaintenanceScheduleRunnable(this, settingsProxy,
(int) unit.toSeconds(duration), (int) unit.toSeconds(maintenanceDuration), server);
(int) enableIn.getSeconds(), (int) maintenanceDuration.getSeconds(), server);
serverTasks.put(server.getName(), runnable.getTask());
return runnable;
}
Expand Down Expand Up @@ -262,9 +261,9 @@ private ProfileLookup doUUIDLookupAshconAPI(final String name) throws IOExceptio

private UUID fromStringUUIDWithoutDashes(String undashedUUID) {
return UUID.fromString(
undashedUUID.substring(0, 8) + "-" + undashedUUID.substring(8, 12) + "-" +
undashedUUID.substring(12, 16) + "-" + undashedUUID.substring(16, 20) + "-" +
undashedUUID.substring(20, 32)
undashedUUID.substring(0, 8) + "-" + undashedUUID.substring(8, 12) + "-" +
undashedUUID.substring(12, 16) + "-" + undashedUUID.substring(16, 20) + "-" +
undashedUUID.substring(20, 32)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
import eu.kennytv.maintenance.core.proxy.command.ProxyCommandInfo;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnableBase;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

public final class SingleEndtimerCommand extends ProxyCommandInfo {

Expand All @@ -41,7 +41,9 @@ public boolean hasPermission(final SenderInfo sender) {
public void execute(final SenderInfo sender, final String[] args) {
if (args.length == 2) {
if (checkPermission(sender, "timer")) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[1])) {

final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, args[1]);
if (duration == null) {
sender.send(getHelpMessage());
return;
}
Expand All @@ -50,11 +52,13 @@ public void execute(final SenderInfo sender, final String[] args) {
return;
}

plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), TimeUnit.MINUTES, false);
plugin.startMaintenanceRunnable(duration, false);
sender.send(getMessage("endtimerStarted", "%TIME%", plugin.getRunnable().getTime()));
} else if (args.length == 3) {
if (checkPermission(sender, "singleserver.timer")) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[2], false)) {

final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, args[2], false);
if (duration == null) {
sender.send(getHelpMessage());
return;
}
Expand All @@ -66,7 +70,7 @@ public void execute(final SenderInfo sender, final String[] args) {
return;
}

final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, Integer.parseInt(args[2]), TimeUnit.MINUTES, false);
final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, duration, false);
sender.send(getMessage(
"singleEndtimerStarted",
"%TIME%", runnable.getTime(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
import eu.kennytv.maintenance.core.proxy.command.ProxyCommandInfo;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnableBase;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

public final class SingleScheduleTimerCommand extends ProxyCommandInfo {

Expand All @@ -41,8 +41,10 @@ public boolean hasPermission(final SenderInfo sender) {
public void execute(final SenderInfo sender, final String[] args) {
if (args.length == 3) {
if (checkPermission(sender, "timer")) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[1])
|| plugin.getCommandManager().checkTimerArgs(sender, args[2], false)) {

final Duration enableIn = plugin.getCommandManager().parseDurationAndCheckTask(sender, args[1]);
final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, args[2], false);
if (enableIn == null || duration == null) {
sender.send(getHelpMessage());
return;
}
Expand All @@ -51,17 +53,18 @@ public void execute(final SenderInfo sender, final String[] args) {
return;
}

final int duration = Integer.parseInt(args[2]);
plugin.scheduleMaintenanceRunnable(Integer.parseInt(args[1]), duration, TimeUnit.MINUTES);
plugin.scheduleMaintenanceRunnable(duration, enableIn);
sender.send(getMessage(
"scheduletimerStarted",
"%TIME%", plugin.getRunnable().getTime(),
"%DURATION%", plugin.getFormattedTime(duration * 60)
"%DURATION%", plugin.getFormattedTime((int) duration.getSeconds())
));
} else if (args.length == 4) {
if (checkPermission(sender, "singleserver.timer")) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[2], false)
|| plugin.getCommandManager().checkTimerArgs(sender, args[3], false)) {

final Duration enableIn = plugin.getCommandManager().parseDurationAndCheckTask(sender, args[2], false);
final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, args[3], false);
if (enableIn == null || duration == null) {
sender.send(getHelpMessage());
return;
}
Expand All @@ -73,12 +76,11 @@ public void execute(final SenderInfo sender, final String[] args) {
return;
}

final int duration = Integer.parseInt(args[3]);
final MaintenanceRunnableBase runnable = plugin.scheduleSingleMaintenanceRunnable(server, Integer.parseInt(args[2]), duration, TimeUnit.MINUTES);
final MaintenanceRunnableBase runnable = plugin.scheduleSingleMaintenanceRunnable(server, enableIn, duration);
sender.send(getMessage(
"singleScheduletimerStarted",
"%TIME%", runnable.getTime(),
"%DURATION%", plugin.getFormattedTime(duration * 60),
"%DURATION%", plugin.getFormattedTime((int) duration.getSeconds()),
"%SERVER%", server.getName()
));
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
import eu.kennytv.maintenance.core.proxy.command.ProxyCommandInfo;
import eu.kennytv.maintenance.core.runnable.MaintenanceRunnableBase;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

public final class SingleStarttimerCommand extends ProxyCommandInfo {

Expand All @@ -41,7 +41,9 @@ public boolean hasPermission(final SenderInfo sender) {
public void execute(final SenderInfo sender, final String[] args) {
if (args.length == 2) {
if (checkPermission(sender, "timer")) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[1])) {

final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, args[1]);
if (duration == null) {
sender.send(getHelpMessage());
return;
}
Expand All @@ -50,11 +52,13 @@ public void execute(final SenderInfo sender, final String[] args) {
return;
}

plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), TimeUnit.MINUTES, true);
plugin.startMaintenanceRunnable(duration, true);
sender.send(getMessage("starttimerStarted", "%TIME%", plugin.getRunnable().getTime()));
} else if (args.length == 3) {
if (checkPermission(sender, "singleserver.timer")) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[2], false)) {

final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, args[2], false);
if (duration == null) {
sender.send(getHelpMessage());
return;
}
Expand All @@ -66,7 +70,7 @@ public void execute(final SenderInfo sender, final String[] args) {
return;
}

final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, Integer.parseInt(args[2]), TimeUnit.MINUTES, true);
final MaintenanceRunnableBase runnable = plugin.startSingleMaintenanceRunnable(server, duration, true);
sender.send(getMessage(
"singleStarttimerStarted",
"%TIME%", runnable.getTime(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,26 @@
import eu.kennytv.maintenance.core.Settings;
import eu.kennytv.maintenance.core.proxy.MaintenanceProxyPlugin;
import eu.kennytv.maintenance.lib.kyori.adventure.text.Component;

import java.util.concurrent.TimeUnit;
import java.time.Duration;

public final class SingleMaintenanceScheduleRunnable extends SingleMaintenanceRunnable {
private final int maintenanceDuration;
private final int maintenanceDurationSeconds;

public SingleMaintenanceScheduleRunnable(final MaintenancePlugin plugin, final Settings settings, final int seconds, final int maintenanceDuration, final Server server) {
super(plugin, settings, seconds, true, server);
this.maintenanceDuration = maintenanceDuration;
this.maintenanceDurationSeconds = maintenanceDuration;
}

@Override
protected void finish() {
super.finish();
((MaintenanceProxyPlugin) plugin).startSingleMaintenanceRunnable(server, maintenanceDuration, TimeUnit.SECONDS, false);
((MaintenanceProxyPlugin) plugin).startSingleMaintenanceRunnable(server, Duration.ofSeconds(maintenanceDurationSeconds), false);
}

@Override
protected Component getStartMessage() {
return settings.getMessage("singleScheduletimerBroadcast",
"%SERVER%", server.getName(),
"%TIME%", getTime(), "%DURATION%", plugin.getFormattedTime(maintenanceDuration));
"%TIME%", getTime(), "%DURATION%", plugin.getFormattedTime(maintenanceDurationSeconds));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
Expand Down Expand Up @@ -173,16 +174,16 @@ private void append(final StringBuilder builder, final String timeUnit, final in
builder.append(time).append(' ').append(settings.language.getString(time == 1 ? timeUnit : timeUnit + "s"));
}

public void startMaintenanceRunnable(final long duration, final TimeUnit unit, final boolean enable) {
runnable = new MaintenanceRunnable(this, settings, (int) unit.toSeconds(duration), enable);
public void startMaintenanceRunnable(final Duration duration, final boolean enable) {
runnable = new MaintenanceRunnable(this, settings, (int) duration.getSeconds(), enable);
// Save the endtimer to be able to continue it after a server stop
if (settings.isSaveEndtimerOnStop() && !runnable.shouldEnable()) {
settings.setSavedEndtimer(System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(runnable.getSecondsLeft()));
}
}

public void scheduleMaintenanceRunnable(final long duration, final int maintenanceDuration, final TimeUnit unit) {
runnable = new MaintenanceScheduleRunnable(this, settings, (int) unit.toSeconds(duration), (int) unit.toSeconds(maintenanceDuration));
public void scheduleMaintenanceRunnable(final Duration enableIn, final Duration maintenanceDuration) {
runnable = new MaintenanceScheduleRunnable(this, settings, (int) enableIn.getSeconds(), (int) maintenanceDuration.getSeconds());
}

public boolean updateAvailable() {
Expand All @@ -208,7 +209,7 @@ protected void continueLastEndtimer() {
setMaintenance(false);
settings.setSavedEndtimer(0);
} else {
startMaintenanceRunnable(settings.getSavedEndtimer() - current, TimeUnit.MILLISECONDS, false);
startMaintenanceRunnable(Duration.ofMillis(settings.getSavedEndtimer() - current), false);
getLogger().info("The timer has been continued - maintenance will be disabled in: " + getTimerMessage());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,19 @@
import eu.kennytv.maintenance.core.command.subcommand.WhitelistCommand;
import eu.kennytv.maintenance.core.command.subcommand.WhitelistRemoveCommand;
import eu.kennytv.maintenance.core.util.SenderInfo;
import java.time.Duration;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.jetbrains.annotations.Nullable;

public abstract class MaintenanceCommand {
private static final long MAX_TASK_DURATION_SECONDS = TimeUnit.DAYS.toSeconds(28);
protected final MaintenancePlugin plugin;
protected final Settings settings;
private final Map<String, CommandInfo> commandExecutors = new LinkedHashMap<>();
Expand Down Expand Up @@ -123,29 +129,41 @@ public List<String> getSuggestions(final SenderInfo sender, final String[] args)
return info != null && info.hasPermission(sender) ? info.getTabCompletion(sender, args) : Collections.emptyList();
}

public boolean checkTimerArgs(final SenderInfo sender, final String time, final boolean taskCheck) {
if (!plugin.isNumeric(time)) return true;
public @Nullable Duration parseDurationAndCheckTask(final SenderInfo sender, final String time, final boolean taskCheck) {
final Duration duration;
if (plugin.isNumeric(time)) {
// Assume minutes by default as per old command behavior
duration = Duration.ofMinutes(Integer.parseInt(time));
} else {
try {
// Only accept hours, minutes, and seconds
duration = Duration.parse("PT" + time.toUpperCase(Locale.ROOT));
} catch (final DateTimeParseException e) {
return null;
}
}

if (taskCheck) {
if (plugin.isTaskRunning()) {
sender.send(settings.getMessage("timerAlreadyRunning"));
return true;
return null;
}
}

final int minutes = Integer.parseInt(time);
if (minutes > 40320) {
final long seconds = duration.getSeconds();
if (seconds > MAX_TASK_DURATION_SECONDS) {
sender.send(settings.getMessage("timerTooLong"));
return true;
return null;
}
if (minutes < 1) {
if (seconds < 1) {
sender.sendRich("<i><dark_gray>[kennytv whispers to you] <gray>Think about running a timer for a negative amount of minutes. Doesn't work <b>that</b> <gray>well.");
return true;
return null;
}
return false;
return duration;
}

public boolean checkTimerArgs(final SenderInfo sender, final String time) {
return checkTimerArgs(sender, time, true);
public @Nullable Duration parseDurationAndCheckTask(final SenderInfo sender, final String time) {
return parseDurationAndCheckTask(sender, time, true);
}

protected void addToggleAndTimerCommands() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import eu.kennytv.maintenance.core.command.CommandInfo;
import eu.kennytv.maintenance.core.util.SenderInfo;

import java.util.concurrent.TimeUnit;
import java.time.Duration;

public final class EndtimerCommand extends CommandInfo {

Expand All @@ -32,7 +32,9 @@ public EndtimerCommand(final MaintenancePlugin plugin) {
@Override
public void execute(final SenderInfo sender, final String[] args) {
if (checkArgs(sender, args, 2)) return;
if (plugin.getCommandManager().checkTimerArgs(sender, args[1])) {

final Duration duration = plugin.getCommandManager().parseDurationAndCheckTask(sender, args[1]);
if (duration == null) {
sender.send(getHelpMessage());
return;
}
Expand All @@ -41,7 +43,7 @@ public void execute(final SenderInfo sender, final String[] args) {
return;
}

plugin.startMaintenanceRunnable(Integer.parseInt(args[1]), TimeUnit.MINUTES, false);
plugin.startMaintenanceRunnable(duration, false);
sender.send(getMessage("endtimerStarted", "%TIME%", plugin.getRunnable().getTime()));
}
}
Loading

0 comments on commit 05af3d3

Please sign in to comment.