Add DimensionScheduler and DimensionScheduleCommand for managing dimension access timings

This commit is contained in:
besiece committed 2026-11-08 18:42:32 +01:00
1 parent d18ddc7b07
commit 3b43b594f4
3 files changed
+119

No files matched your search

@@ -0,0 +1,39 @@
package eu.mhsl.craftattack.spawn.common.appliances.tooling.dimensionScheduler;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.InvalidConfigurationException;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.util.List;
class DimensionScheduleCommand extends ApplianceCommand<DimensionScheduler> {
public DimensionScheduleCommand() {
super("dimensionSchedule");
}
@Override
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if(!sender.isOp()) throw new Error("Dieser Befehl ist nur für die Konsole und OPs verfügbar.");
if(args.length != 1 || !args[0].equalsIgnoreCase("reload")) {
throw new Error("Verwendung: /dimensionSchedule reload");
}
try {
this.getAppliance().reload();
} catch(IOException | InvalidConfigurationException | IllegalArgumentException e) {
throw new Error("dimension-schedule.yml konnte nicht neu eingelesen werden: " + e.getMessage());
}
sender.sendMessage(Component.text("dimension-schedule.yml wurde neu eingelesen.", NamedTextColor.GREEN));
}
@Override
public @NotNull List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if(!sender.isOp() || args.length != 1) return List.of();
return this.tabCompleteReducer(List.of("reload"), args);
}
}
@@ -0,0 +1,75 @@
package eu.mhsl.craftattack.spawn.common.appliances.tooling.dimensionScheduler;
import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.format.DateTimeParseException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Level;
/** Reads named times only; applying them to dimension access is handled separately. */
public class DimensionScheduler extends Appliance {
private static final String FILE_NAME = "dimension-schedule.yml";
private final File scheduleFile = new File(Main.instance().getDataFolder(), FILE_NAME);
private Map<String, Instant> times = Map.of();
@Override
public void onEnable() {
try {
if(!this.scheduleFile.exists()) Main.instance().saveResource(FILE_NAME, false);
this.reload();
} catch(IOException | InvalidConfigurationException | IllegalArgumentException e) {
Main.logger().log(Level.WARNING, "Could not load " + FILE_NAME + "; keeping previous times", e);
}
}
/** Validates all entries before replacing the current times. Never creates or writes the file. */
public void reload() throws IOException, InvalidConfigurationException {
YamlConfiguration configuration = new YamlConfiguration();
configuration.load(this.scheduleFile);
Map<String, Instant> loadedTimes = new HashMap<>();
for(Map.Entry<String, Object> entry : configuration.getValues(false).entrySet()) {
readTime(entry.getKey(), entry.getValue()).ifPresent(time -> loadedTimes.put(entry.getKey(), time));
}
this.times = Map.copyOf(loadedTimes);
}
private static Optional<Instant> readTime(String key, Object configured) {
if(configured == null) return Optional.empty();
if(!(configured instanceof String value)) {
throw new IllegalArgumentException(key + " muss null oder ein Datum in Anführungszeichen mit UTC-Offset sein.");
}
if(value.isBlank()) return Optional.empty();
try {
return Optional.of(OffsetDateTime.parse(value.trim()).toInstant());
} catch(DateTimeParseException e) {
throw new IllegalArgumentException("Ungültiger Zeitpunkt für " + key + ". Beispiel: \"2026-11-15T18:00:00+01:00\"", e);
}
}
public Optional<Instant> getTime(String name) {
return Optional.ofNullable(this.times.get(name));
}
/** Immutable snapshot of all configured, non-empty times. */
public Map<String, Instant> getTimes() {
return this.times;
}
@Override
protected @NotNull List<ApplianceCommand<?>> commands() {
return List.of(new DimensionScheduleCommand());
}
}
@@ -0,0 +1,5 @@
# Datum mit UTC-Offset, z. B. "2026-11-15T18:00:00+01:00"
# null bedeutet: kein Termin
# Weitere Einträge mit frei wählbaren Namen können ergänzt werden.
end-open-at: null
outer-end-open-at: null