refactor: reorganize packages and replace LPSchematic with WorldEdit
Restructure core modules into subpackages (generator, schematic, config, session, etc.); add .schem/.nbt schematic pipeline, commands, adaptive stats skeleton, and bootstrap wiring.
This commit is contained in:
parent
6ba6e5137d
commit
fd0ba2cc0e
203 changed files with 5652 additions and 2367 deletions
262
src/main/java/dev/loki/loparkour/command/LoParkourCommand.java
Normal file
262
src/main/java/dev/loki/loparkour/command/LoParkourCommand.java
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (p == null) return;
|
||||
|
||||
if (a1.equalsIgnoreCase("create") && 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 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 (a1.equalsIgnoreCase("schematic")) {
|
||||
if (a2.equalsIgnoreCase("create")) {
|
||||
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 (!a1.equalsIgnoreCase("schematic") || !a2.equalsIgnoreCase("create")) 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));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue