package com.mrkayjaydee.playhours.command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mrkayjaydee.playhours.core.ScheduleService; import com.mrkayjaydee.playhours.core.TimeRange; import com.mrkayjaydee.playhours.core.ForceModeFormatter; import com.mrkayjaydee.playhours.text.Messages; import com.mrkayjaydee.playhours.config.*; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import java.time.ZonedDateTime; import java.time.format.TextStyle; import java.util.*; /** * Main entry point for /hours command registration. * Delegates to specialized builders for different command groups. */ public final class HoursCommand { private HoursCommand() {} /** * Registers the /hours command tree with the Minecraft command dispatcher. * @param d the command dispatcher */ public static void register(CommandDispatcher d) { d.register(Commands.literal("hours") .requires(src -> src.hasPermission(0)) .then(registerStatusCommand()) .then(registerForceCommand()) .then(registerReloadCommand()) .then(SetCommandBuilder.build()) .then(registerExceptionsCommand()) .then(ListsCommandBuilder.build()) .then(MOTDCommandBuilder.build()) .then(MessagesCommandBuilder.build()) ); } private static LiteralArgumentBuilder registerStatusCommand() { return CommandBuilder.viewLiteral("status") .executes(ctx -> { if (!ConfigEventHandler.isReady()) { ctx.getSource().sendFailure(Messages.configNotReady()); return 0; } ScheduleService s = ScheduleService.get(); ZonedDateTime now = ZonedDateTime.now(s.getZoneId()); boolean open = s.isOpen(now); String nextClose = s.nextClose(now).map(z -> TimeRange.formatTime(z.toLocalTime(), Messages.getJavaLocale())).orElse("-"); var no = s.nextOpen(now); String day = no.map(z -> z.getDayOfWeek().getDisplayName(TextStyle.FULL, Messages.getJavaLocale())).orElse("-"); String time = no.map(z -> TimeRange.formatTime(z.toLocalTime(), Messages.getJavaLocale())).orElse("-"); String modeDisplay = ForceModeFormatter.format(s.getForceMode()); ctx.getSource().sendSuccess(() -> Messages.statusLine(modeDisplay, open, nextClose, day, time), false); return 1; }); } private static LiteralArgumentBuilder registerForceCommand() { return CommandBuilder.adminLiteral("force") .then(Commands.literal("normal").executes(ctx -> setForce("NORMAL", ctx.getSource()))) .then(Commands.literal("open").executes(ctx -> setForce("FORCE_OPEN", ctx.getSource()))) .then(Commands.literal("close").executes(ctx -> setForce("FORCE_CLOSED", ctx.getSource()))); } private static LiteralArgumentBuilder registerReloadCommand() { return CommandBuilder.adminLiteral("reload") .executes(ctx -> { com.mrkayjaydee.playhours.PlayHoursMod.LOGGER.info("/hours reload invoked by {}", ctx.getSource().getTextName()); ConfigEventHandler.reloadFromDisk(); ctx.getSource().sendSuccess(() -> Messages.configReloaded(), true); return 1; }); } private static LiteralArgumentBuilder registerExceptionsCommand() { return CommandBuilder.adminLiteral("exceptions") .then(Commands.literal("add-open").then(Commands.argument("spec", StringArgumentType.greedyString()).executes(ctx -> { String spec = StringArgumentType.getString(ctx, "spec"); List list = new ArrayList<>(ExceptionsConfig.OPEN_DATES.get()); list.add(spec); ExceptionsConfig.OPEN_DATES.set(list); CommandBuilder.saveAndRebuild(ctx.getSource()); return 1; }))) .then(Commands.literal("add-closed").then(Commands.argument("spec", StringArgumentType.greedyString()).executes(ctx -> { String spec = StringArgumentType.getString(ctx, "spec"); List list = new ArrayList<>(ExceptionsConfig.CLOSED_DATES.get()); list.add(spec); ExceptionsConfig.CLOSED_DATES.set(list); CommandBuilder.saveAndRebuild(ctx.getSource()); return 1; }))) .then(Commands.literal("clear").executes(ctx -> { ExceptionsConfig.OPEN_DATES.set(new ArrayList<>()); ExceptionsConfig.CLOSED_DATES.set(new ArrayList<>()); CommandBuilder.saveAndRebuild(ctx.getSource()); return 1; })); } private static int setForce(String mode, CommandSourceStack src) { GeneralConfig.FORCE_MODE.set(mode); CommandBuilder.saveAndRebuild(src); if ("FORCE_OPEN".equals(mode)) src.sendSuccess(() -> Messages.forceOpen(), true); if ("FORCE_CLOSED".equals(mode)) src.sendSuccess(() -> Messages.forceClosed(), true); return 1; } }