/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package pluginbase.command; import pluginbase.messages.BundledMessage; import pluginbase.messages.Message; import pluginbase.minecraft.BasePlayer; import org.jetbrains.annotations.NotNull; import pluginbase.util.time.Duration; /** * A PluginBase user queued command that requires confirmation before executing. * <p/> * This is for commands to be used on the server by the server operator or the players on the server. * A queued command waits for the user to execute a confirmation command before performing the actual * command. A queued command will have an expiration time after which it will stop waiting for the confirm * command and simply not run. A queued command that is expired must be typed in again and confirmed. * <br/> * Queued commands for PluginBase's command handler <b>must</b> implement this class AND annotate it with the * {@link CommandInfo} annotation. * * @param <P> the plugin that this command belongs to. */ public abstract class QueuedCommand<P> extends Command<P> implements Runnable { /** * Constructs a queued command. * <p/> * You will never need to call this constructor. It is used by {@link CommandHandler} * * @param plugin your plugin. */ protected QueuedCommand(@NotNull final CommandProvider<P> plugin) { super(plugin); } private BasePlayer sender; private CommandContext context; /** * This method should return a user friendly message explaining that this command * requires confirmation using the appropriate confirm command. * <p/> * The confirm command is "/" + {@link pluginbase.command.CommandProvider#getCommandPrefix()} + " confirm" by default. * <br/> * This returns a built in message and must be overridden to provide a custom message. * * @return The confirm required message. */ @NotNull protected BundledMessage getConfirmMessage() { return CommandHandler.MUST_CONFIRM.bundle(Duration.valueOf(getExpirationDuration()).asVerboseString()); } final void confirm() { getCommandProvider().getLog().finer("Confirming queued command '%s' for '%s' with '%s'", this, sender, context); onConfirm(sender, context); getCommandProvider().getCommandHandler().removedQueuedCommand(sender, this); } private void expire() { getCommandProvider().getLog().finer("Expiring queued command '%s' for '%s' with '%s'", this, sender, context); onExpire(sender, context); getCommandProvider().getCommandHandler().removedQueuedCommand(sender, this); } /** * How long the queued command will wait for confirmation before expiring. * * @return the expiration time in seconds. */ public abstract long getExpirationDuration(); /** * Gives the command a chance to do something before the confirm command has been used. * <p/> * This is called internally and must simply be implemented. It is okay for this method to be blank. * * @param sender the command sender. * @param context the command context containing details about the command's usage. * @return true to indicate the command was used as indicated and false to indicate improper usage. */ protected abstract boolean preConfirm(@NotNull final BasePlayer sender, @NotNull final CommandContext context); /** * This runs the actual command once it is confirmed. * <p/> * Implement with what the command should actually do. * * @param sender the command sender. * @param context the command context containing details about the command's usage. */ protected abstract void onConfirm(@NotNull final BasePlayer sender, @NotNull final CommandContext context); /** * Gives the command a chance to do something when the user has missed the confirmation window. * <p/> * This is called internally and must simply be implemented. It is okay for this method to be blank. * <br/> * If you desire for the command sender to know when the command has expired, you must use this to send a * message as no other warning is given. * * @param sender the command sender. * @param context the command context containing details about the command's usage. */ protected abstract void onExpire(@NotNull final BasePlayer sender, @NotNull final CommandContext context); /** {@inheritDoc} */ @Override public final boolean runCommand(@NotNull final BasePlayer sender, @NotNull final CommandContext context) throws CommandException { this.sender = sender; this.context = context; getCommandProvider().scheduleQueuedCommandExpiration(this); return preConfirm(sender, context); } /** * This will cause the expiration of the queued command. * <p/> * This is mostly for use internally. */ @Override public final void run() { expire(); } }