Files
PlayHours/src/main/java/com/mrkayjaydee/playhours/command/HoursCommand.java
Mr¤KayJayDee c0fd2a2787 feat(docs): complete PlayHours mod implementation with comprehensive documentation
- Add complete PlayHours mod source code with all features:
  * Schedule enforcement with per-day schedules and midnight-spanning support
  * Login control with configurable thresholds and exemptions
  * Warnings and auto-kick system with countdown functionality
  * Force modes (NORMAL/FORCE_OPEN/FORCE_CLOSED) for maintenance
  * Whitelist/blacklist system for player access control
  * Date exceptions for holidays and special events
  * Multi-language support (English/French) with smart time formatting
  * LuckPerms integration with vanilla ops fallback
  * Dynamic MOTD system with real-time schedule display
  * Comprehensive command system with permission integration
  * TOML configuration with hot-reload support

- Add comprehensive documentation suite:
  * Installation guide with step-by-step setup instructions
  * Complete configuration reference with all options
  * Commands reference with usage examples
  * Features overview with detailed explanations
  * MOTD system configuration and customization guide
  * Permissions system documentation with LuckPerms integration
  * Technical details covering architecture and limitations
  * Usage examples with real-world scenarios
  * Changelog with version history

- Add resource files:
  * Language files (en_us.json, fr_fr.json) with localized messages
  * Mod metadata (mods.toml) with proper Forge configuration
  * Resource pack metadata (pack.mcmeta)

- Update build configuration:
  * Gradle build system with proper dependencies
  * Project properties and version management
  * Development environment setup

- Restructure documentation:
  * Replace old README.txt with new comprehensive README.md
  * Create modular documentation structure in docs/ directory
  * Add cross-references and navigation between documents
  * Include quick start guide and common use cases

This commit represents the complete v1.0.0 release of PlayHours, a production-ready server operation hours enforcement mod for Minecraft Forge 1.20.1.
2025-10-23 23:28:20 +02:00

115 lines
5.6 KiB
Java

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<CommandSourceStack> 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<CommandSourceStack> 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<CommandSourceStack> 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<CommandSourceStack> 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<CommandSourceStack> 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<String> 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<String> 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;
}
}