169 lines
6.6 KiB
Java
169 lines
6.6 KiB
Java
package games.dmg.spigotquestboard;
|
|
|
|
import java.io.IOException;
|
|
import java.time.Clock;
|
|
import java.time.Instant;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.Objects;
|
|
import org.bukkit.command.Command;
|
|
import org.bukkit.command.CommandExecutor;
|
|
import org.bukkit.command.CommandSender;
|
|
import org.bukkit.command.TabCompleter;
|
|
import org.bukkit.entity.Player;
|
|
|
|
final class QuestCommand implements CommandExecutor, TabCompleter {
|
|
private static final List<String> QUANTITIES = List.of("1", "16", "32", "64");
|
|
private final QuestCreationGateway creator;
|
|
private final QuestBrowser browser;
|
|
private final QuestCompletionGateway completer;
|
|
private final QuestCancellationGateway canceller;
|
|
private final Clock clock;
|
|
|
|
QuestCommand(QuestCreationGateway creator, QuestBrowser browser, Clock clock) {
|
|
this(creator, browser, null, null, clock);
|
|
}
|
|
|
|
QuestCommand(
|
|
QuestCreationGateway creator,
|
|
QuestBrowser browser,
|
|
QuestCompletionGateway completer,
|
|
Clock clock
|
|
) {
|
|
this(creator, browser, completer, null, clock);
|
|
}
|
|
|
|
QuestCommand(
|
|
QuestCreationGateway creator,
|
|
QuestBrowser browser,
|
|
QuestCompletionGateway completer,
|
|
QuestCancellationGateway canceller,
|
|
Clock clock
|
|
) {
|
|
this.creator = Objects.requireNonNull(creator, "creator");
|
|
this.browser = Objects.requireNonNull(browser, "browser");
|
|
this.completer = completer;
|
|
this.canceller = canceller;
|
|
this.clock = Objects.requireNonNull(clock, "clock");
|
|
}
|
|
|
|
@Override
|
|
public boolean onCommand(
|
|
CommandSender sender, Command command, String label, String[] arguments
|
|
) {
|
|
if (arguments.length == 0
|
|
|| (arguments.length == 1 && "list".equalsIgnoreCase(arguments[0]))) {
|
|
Instant now = clock.instant();
|
|
sender.sendMessage(QuestListingFormatter.formatAll(browser.activeQuests(now), now));
|
|
return true;
|
|
}
|
|
if (arguments.length == 2 && "complete".equalsIgnoreCase(arguments[0])) {
|
|
if (!(sender instanceof Player player)) {
|
|
sender.sendMessage("Only players can complete quests with inventory items.");
|
|
return true;
|
|
}
|
|
if (completer == null) {
|
|
sender.sendMessage("Quest completion is unavailable.");
|
|
return true;
|
|
}
|
|
try {
|
|
completer.complete(player, arguments[1], clock.instant());
|
|
} catch (IllegalArgumentException | IllegalStateException exception) {
|
|
sender.sendMessage(exception.getMessage());
|
|
} catch (IOException exception) {
|
|
sender.sendMessage(
|
|
"The quest could not be saved. Your delivered blocks were restored."
|
|
);
|
|
}
|
|
return true;
|
|
}
|
|
if (arguments.length == 2 && "cancel".equalsIgnoreCase(arguments[0])) {
|
|
if (!(sender instanceof Player player)) {
|
|
sender.sendMessage("Only players can cancel quests.");
|
|
return true;
|
|
}
|
|
if (canceller == null) {
|
|
sender.sendMessage("Quest cancellation is unavailable.");
|
|
return true;
|
|
}
|
|
try {
|
|
canceller.cancel(player, arguments[1], clock.instant());
|
|
} catch (IllegalArgumentException | IllegalStateException exception) {
|
|
sender.sendMessage(exception.getMessage());
|
|
} catch (IOException exception) {
|
|
sender.sendMessage(
|
|
"The quest could not be saved. It remains active and its reward remains escrowed."
|
|
);
|
|
}
|
|
return true;
|
|
}
|
|
if (arguments.length != 3 || !"create".equalsIgnoreCase(arguments[0])) {
|
|
usage(sender);
|
|
return true;
|
|
}
|
|
if (!(sender instanceof Player player)) {
|
|
sender.sendMessage("Only players can create quests with inventory rewards.");
|
|
return true;
|
|
}
|
|
final int quantity;
|
|
try {
|
|
quantity = Integer.parseInt(arguments[2]);
|
|
} catch (NumberFormatException exception) {
|
|
sender.sendMessage("Quest quantity must be a positive whole number.");
|
|
return true;
|
|
}
|
|
try {
|
|
Quest quest = creator.create(player, arguments[1], quantity, clock.instant());
|
|
sender.sendMessage("Quest " + quest.id() + " created. Your exact held stack is now escrowed.");
|
|
} catch (IllegalArgumentException exception) {
|
|
sender.sendMessage(exception.getMessage());
|
|
} catch (IOException exception) {
|
|
sender.sendMessage("The quest could not be saved. Your held reward was restored.");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public List<String> onTabComplete(
|
|
CommandSender sender, Command command, String alias, String[] arguments
|
|
) {
|
|
if (!(sender instanceof Player)) {
|
|
return List.of();
|
|
}
|
|
if (arguments.length == 1) {
|
|
return startsWith(List.of("create", "list", "complete", "cancel"), arguments[0]);
|
|
}
|
|
if (arguments.length == 2 && "create".equalsIgnoreCase(arguments[0])) {
|
|
return creator.suggestBlockMaterials(arguments[1]);
|
|
}
|
|
if (arguments.length == 3 && "create".equalsIgnoreCase(arguments[0])) {
|
|
return startsWith(QUANTITIES, arguments[2]);
|
|
}
|
|
if (arguments.length == 2 && "complete".equalsIgnoreCase(arguments[0])) {
|
|
return startsWith(browser.completableQuestIds(clock.instant()), arguments[1]);
|
|
}
|
|
if (arguments.length == 2 && "cancel".equalsIgnoreCase(arguments[0])) {
|
|
Player player = (Player) sender;
|
|
return startsWith(
|
|
browser.cancellableQuestIds(player.getUniqueId(), clock.instant()), arguments[1]
|
|
);
|
|
}
|
|
return List.of();
|
|
}
|
|
|
|
private static List<String> startsWith(List<String> candidates, String prefix) {
|
|
String normalized = prefix.toLowerCase(Locale.ROOT);
|
|
return candidates.stream()
|
|
.filter(candidate -> candidate.toLowerCase(Locale.ROOT).startsWith(normalized))
|
|
.toList();
|
|
}
|
|
|
|
private static void usage(CommandSender sender) {
|
|
sender.sendMessage(
|
|
"Usage: /quests [list] | /quests create <block> <quantity> | "
|
|
+ "/quests complete <quest> | /quests cancel <quest>"
|
|
);
|
|
sender.sendMessage("Hold the entire reward stack in your main hand; its exact metadata will be escrowed.");
|
|
}
|
|
}
|