291 lines
12 KiB
Java
291 lines
12 KiB
Java
package dev.loki.loparkour.command;
|
|
|
|
import dev.loki.loparkour.LoParkour;
|
|
import dev.loki.loparkour.api.core.Registry;
|
|
import dev.loki.loparkour.command.admin.AdminCommandHandler;
|
|
import dev.loki.loparkour.command.player.PlayerCommandHandler;
|
|
import dev.loki.loparkour.command.schematic.SchematicCommandHandler;
|
|
import dev.loki.loparkour.config.locale.Locales;
|
|
import dev.loki.loparkour.leaderboard.core.Leaderboard;
|
|
import dev.loki.loparkour.menu.core.Menus;
|
|
import dev.loki.loparkour.menu.core.ParkourOption;
|
|
import dev.loki.loparkour.mode.base.Mode;
|
|
import dev.loki.loparkour.mode.base.Modes;
|
|
import dev.loki.loparkour.mode.base.MultiMode;
|
|
import dev.loki.loparkour.player.core.ParkourPlayer;
|
|
import dev.loki.loparkour.player.core.ParkourUser;
|
|
import dev.loki.loparkour.schematic.core.SchematicManager;
|
|
import dev.loki.loparkour.session.core.Session;
|
|
import dev.loki.loparkour.util.text.ColorUtil;
|
|
import org.bukkit.Bukkit;
|
|
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;
|
|
import org.jetbrains.annotations.NotNull;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import java.util.logging.Level;
|
|
|
|
/**
|
|
* Main command router for /LoParkour and /parkour.
|
|
* Delegates to {@link PlayerCommandHandler}, {@link AdminCommandHandler},
|
|
* and {@link SchematicCommandHandler}.
|
|
*/
|
|
public class LoParkourCommand implements CommandExecutor, TabCompleter {
|
|
|
|
private static final List<String> SCHEMATIC_DIFFICULTIES = List.of("0.0", "0.25", "0.5", "0.75", "1.0");
|
|
private static final List<String> SCHEMATIC_SUBCOMMANDS = List.of(
|
|
"wand", "pos1", "pos2", "create", "convert", "paste", "list", "reload"
|
|
);
|
|
|
|
private final PlayerCommandHandler player = new PlayerCommandHandler();
|
|
private final AdminCommandHandler admin = new AdminCommandHandler(player);
|
|
|
|
@Override
|
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command,
|
|
@NotNull String label, @NotNull String[] args) {
|
|
try {
|
|
Player p = sender instanceof Player ? (Player) sender : null;
|
|
|
|
switch (args.length) {
|
|
case 0 -> player.handleNoArgs(sender, p);
|
|
case 1 -> player.handle(args[0], sender, p);
|
|
case 2 -> handle2(args[0], args[1], sender, p);
|
|
case 3 -> handle3(args[0], args[1], args[2], sender, p);
|
|
case 4 -> handle4(args[0], args[1], args[2], args[3], sender, p);
|
|
default -> Locales.send(sender, "commands.too_many_args");
|
|
}
|
|
return true;
|
|
} catch (Throwable t) {
|
|
LoParkour.getPlugin().getLogger().log(Level.SEVERE,
|
|
"LoParkour command failed (" + label + " " + String.join(" ", args) + ")", t);
|
|
Locales.send(sender, "commands.error");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// ── 2-arg routing ──────────────────────────────────────────────────────────
|
|
|
|
private void handle2(String a1, String a2, CommandSender sender, @Nullable Player p) {
|
|
// Admin commands that don't need a player
|
|
switch (a1.toLowerCase()) {
|
|
case "forcejoin", "forceleave", "reset", "recoverinventory" -> {
|
|
admin.handle(a1, a2, sender, p);
|
|
return;
|
|
}
|
|
default -> {
|
|
}
|
|
}
|
|
|
|
if (p == null) {
|
|
return;
|
|
}
|
|
|
|
if ("create".equalsIgnoreCase(a1) && p.hasPermission(ParkourOption.ADMIN.permission)) {
|
|
SchematicCommandHandler.handleCreateDifficultyOnly(a2, sender, p, player);
|
|
return;
|
|
}
|
|
|
|
switch (a1.toLowerCase()) {
|
|
case "join" -> handleJoin(a2, sender, p);
|
|
case "leaderboard" -> handleLeaderboard(a2, sender, p);
|
|
case "schematic" -> {
|
|
if (!p.hasPermission(ParkourOption.ADMIN.permission)) {
|
|
send(sender, Locales.getString(p, "other.no_do"));
|
|
return;
|
|
}
|
|
SchematicCommandHandler.handleSubcommand(a2, sender, p, player);
|
|
}
|
|
default -> {
|
|
}
|
|
}
|
|
}
|
|
|
|
// ── 3-arg routing ──────────────────────────────────────────────────────────
|
|
|
|
private void handle3(String a1, String a2, String a3, CommandSender sender, @Nullable Player p) {
|
|
if (p == null) {
|
|
return;
|
|
}
|
|
if (!p.hasPermission(ParkourOption.ADMIN.permission)) {
|
|
return;
|
|
}
|
|
|
|
if ("schematic".equalsIgnoreCase(a1)) {
|
|
if ("create".equalsIgnoreCase(a2)) {
|
|
SchematicCommandHandler.handleCreateDifficultyOnly(a3, sender, p, player);
|
|
return;
|
|
}
|
|
SchematicCommandHandler.handleSubcommandWithName(a2, a3, sender, p);
|
|
}
|
|
}
|
|
|
|
private void handle4(String a1, String a2, String a3, String a4, CommandSender sender, @Nullable Player p) {
|
|
if (p == null) {
|
|
return;
|
|
}
|
|
if (!p.hasPermission(ParkourOption.ADMIN.permission)) {
|
|
return;
|
|
}
|
|
if (!"schematic".equalsIgnoreCase(a1) || !"create".equalsIgnoreCase(a2)) {
|
|
return;
|
|
}
|
|
SchematicCommandHandler.handleCreateWithDifficulty(a3, a4, sender, p, player);
|
|
}
|
|
|
|
// ── join logic ─────────────────────────────────────────────────────────────
|
|
|
|
private void handleJoin(String arg, CommandSender sender, Player p) {
|
|
if (!player.cooldown(sender, "join", 2500) || !ParkourOption.JOIN.mayPerform(p)) {
|
|
return;
|
|
}
|
|
|
|
Mode mode = Registry.getMode(arg);
|
|
if (mode != null) {
|
|
mode.create(p);
|
|
return;
|
|
}
|
|
|
|
Player other = Bukkit.getPlayer(arg);
|
|
if (other == null) {
|
|
send(sender, LoParkour.PREFIX + Locales.getString(sender, "commands.unknown_player"));
|
|
return;
|
|
}
|
|
|
|
ParkourPlayer pp = ParkourPlayer.getPlayer(other);
|
|
if (pp == null) {
|
|
send(sender, LoParkour.PREFIX + Locales.getString(sender, "commands.not_playing"));
|
|
return;
|
|
}
|
|
|
|
ParkourUser user = ParkourUser.getUser(p);
|
|
Session session = pp.session;
|
|
if (user != null && user.session == session) {
|
|
return;
|
|
}
|
|
|
|
if (session.isAcceptingPlayers()) {
|
|
Mode sessionMode = session.generator.getMode();
|
|
if (sessionMode instanceof MultiMode mm) {
|
|
mm.join(p, session);
|
|
} else {
|
|
Modes.SPECTATOR.create(p, session);
|
|
}
|
|
} else {
|
|
Modes.SPECTATOR.create(p, session);
|
|
}
|
|
}
|
|
|
|
// ── leaderboard logic ──────────────────────────────────────────────────────
|
|
|
|
private void handleLeaderboard(String arg, CommandSender sender, Player p) {
|
|
if (!ParkourOption.LEADERBOARDS.mayPerform(p)) {
|
|
send(sender, Locales.getString(p, "other.no_do"));
|
|
return;
|
|
}
|
|
Mode mode = Registry.getMode(arg.toLowerCase());
|
|
if (mode == null) {
|
|
Menus.LEADERBOARDS.open(p);
|
|
} else {
|
|
Menus.SINGLE_LEADERBOARD.open(p, mode, Leaderboard.Sort.SCORE);
|
|
}
|
|
}
|
|
|
|
// ── tab complete ───────────────────────────────────────────────────────────
|
|
|
|
@Override
|
|
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
|
|
@NotNull String alias, @NotNull String[] args) {
|
|
List<String> completions = new ArrayList<>();
|
|
|
|
if (args.length == 1) {
|
|
if (ParkourOption.JOIN.mayPerform(sender)) { completions.add("join"); completions.add("leave"); }
|
|
if (ParkourOption.MAIN.mayPerform(sender)) completions.add("menu");
|
|
if (ParkourOption.PLAY.mayPerform(sender)) completions.add("play");
|
|
if (ParkourOption.LEADERBOARDS.mayPerform(sender)) completions.add("leaderboard");
|
|
if (sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
|
completions.addAll(List.of("schematic", "create", "reload", "forcejoin", "forceleave", "reset", "recoverinventory"));
|
|
}
|
|
return filter(args[0], completions);
|
|
}
|
|
|
|
if (args.length == 2) {
|
|
String a1 = args[0].toLowerCase();
|
|
if (a1.equals("reset") && sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
|
completions.add("everyone");
|
|
ParkourPlayer.getPlayers().forEach(pp -> completions.add(pp.getName()));
|
|
} else if (a1.equals("join") && ParkourOption.JOIN.mayPerform(sender)) {
|
|
Registry.getModes().forEach(m -> completions.add(m.getName()));
|
|
ParkourPlayer.getPlayers().forEach(pp -> completions.add(pp.getName()));
|
|
} else if (a1.equals("leaderboard") && ParkourOption.LEADERBOARDS.mayPerform(sender)) {
|
|
Registry.getModes().forEach(m -> completions.add(m.getName()));
|
|
} else if (a1.equals("schematic") && sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
|
completions.addAll(SCHEMATIC_SUBCOMMANDS);
|
|
} else if (a1.equals("create") && sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
|
completions.addAll(SCHEMATIC_DIFFICULTIES);
|
|
} else if ((a1.equals("forcejoin") || a1.equals("forceleave")) && sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
|
completions.add("everyone");
|
|
if (a1.equals("forcejoin")) completions.add("nearest");
|
|
Bukkit.getOnlinePlayers().forEach(pl -> completions.add(pl.getName()));
|
|
} else if (a1.equals("recoverinventory") && sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
|
Bukkit.getOnlinePlayers().forEach(pl -> completions.add(pl.getName()));
|
|
}
|
|
return filter(args[1], completions);
|
|
}
|
|
|
|
if (args.length == 3 && sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
|
String a1 = args[0].toLowerCase();
|
|
String a2 = args[1].toLowerCase();
|
|
if (a1.equals("schematic")) {
|
|
if (a2.equals("paste")) {
|
|
addLoadedSchematicIds(completions);
|
|
} else if (a2.equals("create")) {
|
|
completions.addAll(SCHEMATIC_DIFFICULTIES);
|
|
}
|
|
}
|
|
return filter(args[2], completions);
|
|
}
|
|
|
|
if (args.length == 4 && sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
|
String a1 = args[0].toLowerCase();
|
|
String a2 = args[1].toLowerCase();
|
|
if (a1.equals("schematic") && a2.equals("create")) {
|
|
completions.addAll(SCHEMATIC_DIFFICULTIES);
|
|
}
|
|
return filter(args[3], completions);
|
|
}
|
|
|
|
return Collections.emptyList();
|
|
}
|
|
|
|
private static void addLoadedSchematicIds(@NotNull List<String> completions) {
|
|
SchematicManager manager = LoParkour.getSchematicManager();
|
|
if (manager == null) {
|
|
return;
|
|
}
|
|
for (String id : manager.getAll().keySet()) {
|
|
completions.add(id);
|
|
String shortId = SchematicManager.configKey(id);
|
|
if (!shortId.equalsIgnoreCase(id)) {
|
|
completions.add(shortId);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ── util ───────────────────────────────────────────────────────────────────
|
|
|
|
private List<String> filter(String input, List<String> options) {
|
|
String lower = input.toLowerCase();
|
|
return options.stream().filter(s -> s.toLowerCase().startsWith(lower)).toList();
|
|
}
|
|
|
|
private void send(CommandSender sender, String msg) {
|
|
sender.sendMessage(ColorUtil.color(msg));
|
|
}
|
|
}
|