fix and migrate 70%
This commit is contained in:
parent
8705cad578
commit
d1dcf6ab57
138 changed files with 3736 additions and 4735 deletions
|
|
@ -1,11 +1,9 @@
|
|||
package dev.loki.loparkour;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import dev.loki.loparkour.api.Registry;
|
||||
import dev.loki.loparkour.config.Config;
|
||||
import dev.loki.loparkour.command.AdminCommandHandler;
|
||||
import dev.loki.loparkour.command.PlayerCommandHandler;
|
||||
import dev.loki.loparkour.command.SchematicCommandHandler;
|
||||
import dev.loki.loparkour.config.Locales;
|
||||
import dev.loki.loparkour.leaderboard.Leaderboard;
|
||||
import dev.loki.loparkour.menu.Menus;
|
||||
|
|
@ -15,613 +13,170 @@ import dev.loki.loparkour.mode.Modes;
|
|||
import dev.loki.loparkour.mode.MultiMode;
|
||||
import dev.loki.loparkour.player.ParkourPlayer;
|
||||
import dev.loki.loparkour.player.ParkourUser;
|
||||
import dev.loki.loparkour.player.data.InventoryData;
|
||||
import dev.loki.loparkour.schematic.lpschem.LPSchematic;
|
||||
import dev.loki.loparkour.schematic.lpschem.LPSchematicBuilder;
|
||||
import dev.loki.loparkour.session.Session;
|
||||
import dev.loki.loparkour.util.ColorUtil;
|
||||
import dev.loki.loparkour.util.ParticleUtil;
|
||||
import dev.loki.loparkour.util.Locations;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.command.BlockCommandSender;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.BoundingBox;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Main command router for /LoParkour and /parkour.
|
||||
* Delegates to {@link PlayerCommandHandler}, {@link AdminCommandHandler},
|
||||
* and {@link SchematicCommandHandler}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class LoParkourCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
public static final HashMap<Player, Location[]> selections = new HashMap<>();
|
||||
|
||||
private static final ItemStack WAND = createWand();
|
||||
|
||||
private static ItemStack createWand() {
|
||||
ItemStack wand = new ItemStack(Material.GOLDEN_AXE);
|
||||
var meta = wand.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.setDisplayName(ColorUtil.color("<red><bold>LPSchematic Wand"));
|
||||
meta.setLore(List.of(
|
||||
ColorUtil.color("<gray>Left click: first position"),
|
||||
ColorUtil.color("<gray>Right click: second position")
|
||||
));
|
||||
wand.setItemMeta(meta);
|
||||
}
|
||||
return wand;
|
||||
}
|
||||
private final PlayerCommandHandler player = new PlayerCommandHandler();
|
||||
private final AdminCommandHandler admin = new AdminCommandHandler(player);
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
Player player = null;
|
||||
if (sender instanceof Player) {
|
||||
player = (Player) sender;
|
||||
}
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command,
|
||||
@NotNull String label, @NotNull String[] args) {
|
||||
Player p = sender instanceof Player ? (Player) sender : null;
|
||||
|
||||
switch (args.length) {
|
||||
case 0 -> handle0Args(sender, player);
|
||||
case 1 -> handle1Args(args[0], sender, player);
|
||||
case 2 -> handle2Args(args[0], args[1], sender, player);
|
||||
case 3 -> handle3Args(args[0], args[1], args[2], sender, player);
|
||||
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);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||
List<String> completions = new ArrayList<>();
|
||||
switch (args.length) {
|
||||
case 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.add("schematic");
|
||||
completions.add("reload");
|
||||
completions.add("forcejoin");
|
||||
completions.add("forceleave");
|
||||
completions.add("reset");
|
||||
completions.add("recoverinventory");
|
||||
}
|
||||
return completions(args[0], completions);
|
||||
}
|
||||
case 2 -> {
|
||||
if (args[0].equalsIgnoreCase("reset") && sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
completions.add("everyone");
|
||||
for (ParkourPlayer pp : ParkourPlayer.getPlayers()) {
|
||||
completions.add(pp.getName());
|
||||
}
|
||||
} else if (args[0].equalsIgnoreCase("join") && sender.hasPermission(ParkourOption.JOIN.permission)) {
|
||||
for (ParkourPlayer pp : ParkourPlayer.getPlayers()) {
|
||||
completions.add(pp.getName());
|
||||
}
|
||||
} else if (args[0].equalsIgnoreCase("schematic") && sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
completions.addAll(Arrays.asList("wand", "pos1", "pos2", "save", "paste"));
|
||||
} else if (args[0].equalsIgnoreCase("forcejoin") && sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
completions.add("nearest");
|
||||
completions.add("everyone");
|
||||
// ── 2-arg routing ──────────────────────────────────────────────────────────
|
||||
|
||||
for (Player pl : Bukkit.getOnlinePlayers()) {
|
||||
completions.add(pl.getName());
|
||||
}
|
||||
} else if (args[0].equalsIgnoreCase("forceleave") && sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
completions.add("everyone");
|
||||
|
||||
for (Player pl : Bukkit.getOnlinePlayers()) {
|
||||
completions.add(pl.getName());
|
||||
}
|
||||
} else if (args[0].equalsIgnoreCase("recoverinventory") && sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
for (Player pl : Bukkit.getOnlinePlayers()) {
|
||||
completions.add(pl.getName());
|
||||
}
|
||||
}
|
||||
return completions(args[1], completions);
|
||||
}
|
||||
default -> {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handle0Args(@NotNull CommandSender sender, @Nullable Player player) {
|
||||
if (player != null && ParkourOption.MAIN.mayPerform(player)) {
|
||||
// TODO: Migrate to LoLib GUI
|
||||
// Menus.MAIN.open(player);
|
||||
player.sendMessage("§cМеню временно недоступно во время миграции");
|
||||
return;
|
||||
}
|
||||
sendHelpMessages(sender);
|
||||
}
|
||||
|
||||
private void sendHelpMessages(CommandSender sender) {
|
||||
send(sender, "");
|
||||
send(sender, "<dark_gray><strikethrough>---------------<reset> %s <dark_gray><strikethrough>---------------<reset>".formatted(LoParkour.NAME));
|
||||
send(sender, "");
|
||||
send(sender, "<gray>/parkour <dark_gray>- Main command");
|
||||
if (sender.hasPermission(ParkourOption.JOIN.permission)) {
|
||||
send(sender, "<gray>/parkour join [mode/player] <dark_gray>- Join the default mode or specify one.");
|
||||
send(sender, "<gray>/parkour leave <dark_gray>- Leave the game on this server");
|
||||
}
|
||||
if (sender.hasPermission(ParkourOption.MAIN.permission)) {
|
||||
send(sender, "<gray>/parkour menu <dark_gray>- Open the menu");
|
||||
}
|
||||
if (sender.hasPermission(ParkourOption.PLAY.permission)) {
|
||||
send(sender, "<gray>/parkour play <dark_gray>- Mode selection menu");
|
||||
}
|
||||
if (sender.hasPermission(ParkourOption.LEADERBOARDS.permission)) {
|
||||
send(sender, "<gray>/parkour leaderboard [type]<dark_gray>- Open the leaderboard of a mode");
|
||||
}
|
||||
if (sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
send(sender, "<gray>/LoParkour schematic <dark_gray>- Create a schematic");
|
||||
send(sender, "<gray>/LoParkour reload <dark_gray>- Reloads the messages-v3.yml file");
|
||||
send(sender, "<gray>/LoParkour reset <everyone/player> <dark_gray>- Resets all high scores. <red>This can't be recovered!");
|
||||
send(sender, "<gray>/LoParkour forcejoin <everyone/nearest/player> <dark_gray>- Forces a specific player, the nearest or everyone to join");
|
||||
send(sender, "<gray>/LoParkour forceleave <everyone/nearest/player> <dark_gray>- Forces a specific player, the nearest or everyone to leave");
|
||||
send(sender, "<gray>/LoParkour recoverinventory <player> <dark_gray>- Recover a player's saved inventory. <red>Useful for recovering data after server crashes or errors when leaving.");
|
||||
}
|
||||
send(sender, "");
|
||||
}
|
||||
|
||||
private void handle1Args(@NotNull String arg, @NotNull CommandSender sender, @Nullable Player player) {
|
||||
switch (arg.toLowerCase()) {
|
||||
case "help" -> sendHelpMessages(sender);
|
||||
case "reload" -> {
|
||||
if (!cooldown(sender, "reload", 2500)) {
|
||||
return;
|
||||
}
|
||||
if (!sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
send(sender, Locales.getString(player, "other.no_do"));
|
||||
return;
|
||||
}
|
||||
|
||||
Config.reload(false);
|
||||
|
||||
send(sender, "%sReloaded config files.".formatted(LoParkour.PREFIX));
|
||||
}
|
||||
}
|
||||
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (arg.toLowerCase()) {
|
||||
case "join" -> {
|
||||
if (!cooldown(sender, "join", 2500)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ParkourOption.JOIN.mayPerform(player)) {
|
||||
send(sender, Locales.getString(player, "other.no_do"));
|
||||
return;
|
||||
}
|
||||
|
||||
ParkourUser user = ParkourUser.getUser(player);
|
||||
if (user != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Modes.DEFAULT.create(player);
|
||||
}
|
||||
case "play" -> {
|
||||
if (ParkourOption.PLAY.mayPerform(player)) {
|
||||
// TODO: Migrate to LoLib GUI
|
||||
// Menus.PLAY.open(player);
|
||||
player.sendMessage("§cМеню временно недоступно во время миграции");
|
||||
}
|
||||
}
|
||||
case "leave" -> {
|
||||
if (!cooldown(sender, "leave", 2500)) {
|
||||
return;
|
||||
}
|
||||
ParkourUser.leave(player);
|
||||
}
|
||||
case "menu", "main" -> {
|
||||
if (!ParkourOption.MAIN.mayPerform(player)) {
|
||||
// TODO: Migrate to LoLib GUI
|
||||
// Menus.MAIN.open(player);
|
||||
player.sendMessage("§cМеню временно недоступно во время миграции");
|
||||
}
|
||||
}
|
||||
case "leaderboard" -> player.performCommand("LoParkour leaderboard invalid");
|
||||
case "schematic" -> {
|
||||
if (!player.hasPermission(ParkourOption.ADMIN.permission)) { // default players shouldn't have access even if perms are disabled
|
||||
send(sender, Locales.getString(player, "other.no_do"));
|
||||
return;
|
||||
}
|
||||
|
||||
send(player, "");
|
||||
send(player, "<red>/LoParkour schematic wand <dark_gray>- <gray>Get the schematic wand");
|
||||
send(player, "<red>/LoParkour schematic pos1 <dark_gray>- <gray>Set the first position of your selection");
|
||||
send(player, "<red>/LoParkour schematic pos2 <dark_gray>- <gray>Set the second position of your selection");
|
||||
send(player, "<red>/LoParkour schematic save <name> <dark_gray>- <gray>Save selection to .lpschem format");
|
||||
send(player, "<red>/LoParkour schematic paste <name> <dark_gray>- <gray>Paste a .lpschem schematic");
|
||||
send(player, "<red>/LoParkour schematic list <dark_gray>- <gray>List all loaded schematics");
|
||||
send(player, "<red>/LoParkour schematic reload <dark_gray>- <gray>Reload all schematics");
|
||||
send(player, "");
|
||||
send(player, "<dark_gray><underlined>Have any questions or need help? Join the Discord.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handle2Args(@NotNull String arg1, @NotNull String arg2, @NotNull CommandSender sender, @Nullable Player player) {
|
||||
switch (arg1.toLowerCase()) {
|
||||
case "forcejoin" -> {
|
||||
if (!sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (arg2.equalsIgnoreCase("everyone")) {
|
||||
Bukkit.getOnlinePlayers().forEach(other -> Modes.DEFAULT.create(other));
|
||||
send(sender, LoParkour.PREFIX + "Successfully force joined everyone!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (arg2.equalsIgnoreCase("nearest")) {
|
||||
Player closest = null;
|
||||
double distance = Double.MAX_VALUE;
|
||||
|
||||
// if player is found get location from player
|
||||
// if no player is found, get location from command block
|
||||
// if no command block is found, return null
|
||||
Location from = sender instanceof Player ? ((Player) sender).getLocation() : (sender instanceof BlockCommandSender ? ((BlockCommandSender) sender).getBlock().getLocation() : null);
|
||||
|
||||
if (from == null || from.getWorld() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get the closest player
|
||||
for (Player p : from.getWorld().getPlayers()) {
|
||||
double d = p.getLocation().distance(from);
|
||||
|
||||
if (d < distance) {
|
||||
distance = d;
|
||||
closest = p;
|
||||
}
|
||||
}
|
||||
|
||||
// no closest player found
|
||||
if (closest == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
send(sender, LoParkour.PREFIX + "Successfully force joined " + closest.getName() + "!");
|
||||
Modes.DEFAULT.create(closest);
|
||||
return;
|
||||
}
|
||||
|
||||
Player other = Bukkit.getPlayer(arg2);
|
||||
if (other == null) {
|
||||
send(sender, LoParkour.PREFIX + "That player isn't online!");
|
||||
return;
|
||||
}
|
||||
|
||||
Modes.DEFAULT.create(other);
|
||||
}
|
||||
case "forceleave" -> {
|
||||
if (!sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (arg2.equalsIgnoreCase("everyone")) {
|
||||
ParkourPlayer.getPlayers().forEach(ParkourUser::leave);
|
||||
send(sender, LoParkour.PREFIX + "Successfully force kicked everyone!");
|
||||
return;
|
||||
}
|
||||
|
||||
Player other = Bukkit.getPlayer(arg2);
|
||||
if (other == null) {
|
||||
send(sender, LoParkour.PREFIX + "That player isn't online!");
|
||||
return;
|
||||
}
|
||||
|
||||
ParkourUser user = ParkourUser.getUser(other);
|
||||
if (user == null) {
|
||||
send(sender, LoParkour.PREFIX + "That player isn't currently playing!");
|
||||
return;
|
||||
}
|
||||
|
||||
ParkourUser.leave(user);
|
||||
}
|
||||
case "reset" -> {
|
||||
if (!sender.hasPermission(ParkourOption.ADMIN.permission) || !cooldown(sender, "reset", 2500)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (arg2.equalsIgnoreCase("everyone")) {
|
||||
for (Mode mode : Registry.getModes()) {
|
||||
Leaderboard leaderboard = mode.getLeaderboard();
|
||||
|
||||
if (leaderboard == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
leaderboard.resetAll();
|
||||
leaderboard.write(true);
|
||||
}
|
||||
|
||||
send(sender, LoParkour.PREFIX + "Successfully reset all high scores in memory and the files.");
|
||||
return;
|
||||
}
|
||||
String name = null;
|
||||
UUID uuid = null;
|
||||
|
||||
// Check online players
|
||||
Player online = Bukkit.getPlayerExact(arg2);
|
||||
if (online != null) {
|
||||
name = online.getName();
|
||||
uuid = online.getUniqueId();
|
||||
}
|
||||
|
||||
// Check uuid
|
||||
if (arg2.contains("-")) {
|
||||
uuid = UUID.fromString(arg2);
|
||||
}
|
||||
|
||||
// Check offline player
|
||||
if (uuid == null) {
|
||||
OfflinePlayer offline = Bukkit.getOfflinePlayer(arg2);
|
||||
name = offline.getName();
|
||||
uuid = offline.getUniqueId();
|
||||
}
|
||||
|
||||
UUID finalUuid = uuid;
|
||||
String finalName = name;
|
||||
|
||||
for (Mode mode : Registry.getModes()) {
|
||||
Leaderboard leaderboard = mode.getLeaderboard();
|
||||
|
||||
if (leaderboard == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
leaderboard.remove(finalUuid);
|
||||
leaderboard.write(true);
|
||||
}
|
||||
|
||||
send(sender, LoParkour.PREFIX + "Successfully reset the high score of " + finalName + " in memory and the files.");
|
||||
}
|
||||
case "recoverinventory" -> {
|
||||
if (!cooldown(sender, "recoverinventory", 2500) || !sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player other = Bukkit.getPlayer(arg2);
|
||||
if (other == null) {
|
||||
send(sender, LoParkour.PREFIX + "That player isn't online!");
|
||||
return;
|
||||
}
|
||||
|
||||
new InventoryData(other).load(result -> {
|
||||
if (result != null) {
|
||||
send(sender, "%sSuccessfully recovered the inventory of %s from their file".formatted(LoParkour.PREFIX, other.getName()));
|
||||
send(sender, "%sGiving %s their items now...".formatted(LoParkour.PREFIX, other.getName()));
|
||||
} else {
|
||||
send(sender, "%s<red>There was an error recovering the inventory of %s from their file".formatted(LoParkour.PREFIX, other.getName()));
|
||||
send(sender, "%s%s has no saved inventory or there was an error. Check the console.".formatted(LoParkour.PREFIX, other.getName()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (arg1) {
|
||||
case "join" -> {
|
||||
if (!cooldown(sender, "join", 2500) || !ParkourOption.JOIN.mayPerform(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Mode mode = Registry.getMode(arg2);
|
||||
|
||||
if (mode != null) {
|
||||
mode.create(player);
|
||||
return;
|
||||
}
|
||||
|
||||
Player other = Bukkit.getPlayer(arg2);
|
||||
|
||||
if (other == null) {
|
||||
send(sender, "%sUnknown player! Try typing the name again.".formatted(LoParkour.PREFIX)); // could not find, so go to default
|
||||
return;
|
||||
}
|
||||
|
||||
ParkourPlayer parkourPlayer = ParkourPlayer.getPlayer(other);
|
||||
|
||||
if (parkourPlayer == null) {
|
||||
send(sender, "%sUnknown player! Try typing the name again.".formatted(LoParkour.PREFIX)); // could not find, so go to default
|
||||
return;
|
||||
}
|
||||
|
||||
ParkourUser user = ParkourUser.getUser(player);
|
||||
Session session = parkourPlayer.session;
|
||||
if (user != null && user.session == session) { // already in same session
|
||||
return;
|
||||
}
|
||||
|
||||
if (session.isAcceptingPlayers()) {
|
||||
((MultiMode) session.generator.getMode()).join(player, session);
|
||||
} else {
|
||||
Modes.SPECTATOR.create(player, session);
|
||||
}
|
||||
}
|
||||
case "leaderboard" -> {
|
||||
if (!ParkourOption.LEADERBOARDS.mayPerform(player)) {
|
||||
send(sender, Locales.getString(player, "other.no_do"));
|
||||
return;
|
||||
}
|
||||
|
||||
Mode mode = Registry.getMode(arg2.toLowerCase());
|
||||
|
||||
// if found gamemode is null, return to default
|
||||
if (mode == null) {
|
||||
// TODO: Migrate to LoLib GUI
|
||||
// Menus.LEADERBOARDS.open(player);
|
||||
player.sendMessage("§cМеню временно недоступно во время миграции");
|
||||
} else {
|
||||
// TODO: Migrate to LoLib GUI
|
||||
// Menus.SINGLE_LEADERBOARD.open(player, mode, Leaderboard.Sort.SCORE);
|
||||
player.sendMessage("§cМеню временно недоступно во время миграции");
|
||||
}
|
||||
}
|
||||
case "schematic" -> {
|
||||
if (!sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
send(sender, Locales.getString(player, "other.no_do"));
|
||||
return;
|
||||
}
|
||||
|
||||
Location playerLocation = player.getLocation();
|
||||
Location[] existingSelection = selections.get(player);
|
||||
|
||||
switch (arg2.toLowerCase()) {
|
||||
case "wand" -> {
|
||||
player.getInventory().addItem(WAND);
|
||||
|
||||
send(player, "<dark_gray>----------- <dark_red><bold>Schematics <reset><dark_gray>-----------");
|
||||
send(player, "<gray><red>Left click<gray> -> set first position | <red>Right click<gray> -> set second position");
|
||||
send(player, "<gray>If you can't place a block and need to set a position mid-air, use <dark_gray>/LoParkour schematic pos1/pos2 <gray>instead.");
|
||||
}
|
||||
case "pos1" -> {
|
||||
send(player, "%sPosition 1 was set to %s".formatted(LoParkour.PREFIX, Locations.toString(playerLocation, true)));
|
||||
|
||||
if (existingSelection == null) {
|
||||
selections.put(player, new Location[]{playerLocation, null});
|
||||
return;
|
||||
}
|
||||
|
||||
selections.put(player, new Location[]{playerLocation, existingSelection[1]});
|
||||
|
||||
ParticleUtil.box(BoundingBox.of(playerLocation, existingSelection[1]), player.getWorld(), Particle.END_ROD, player, 0.2);
|
||||
}
|
||||
case "pos2" -> {
|
||||
send(player, "%sPosition 2 was set to %s".formatted(LoParkour.PREFIX, Locations.toString(playerLocation, true)));
|
||||
|
||||
if (existingSelection == null) {
|
||||
selections.put(player, new Location[]{null, playerLocation});
|
||||
return;
|
||||
}
|
||||
|
||||
selections.put(player, new Location[]{existingSelection[0], playerLocation});
|
||||
|
||||
ParticleUtil.box(BoundingBox.of(existingSelection[0], playerLocation), player.getWorld(), Particle.END_ROD, player, 0.2);
|
||||
}
|
||||
case "save" -> {
|
||||
if (!cooldown(sender, "LoParkour save schematic", 2500)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (existingSelection == null || existingSelection[0] == null || existingSelection[1] == null) {
|
||||
send(player, "<dark_red><bold>Schematics <reset><gray>Your schematic isn't complete yet. Make sure you've set the first and second position.");
|
||||
return;
|
||||
}
|
||||
|
||||
String code = UUID.randomUUID().toString().split("-")[0];
|
||||
|
||||
send(player, ("<dark_red><bold>Schematics <reset><gray>Your schematic is being saved. It will use code <red>'%s'<gray>. " + "You can change the code to whatever you like. " + "Don't forget to add this schematic to <dark_gray>schematics.yml<gray>.").formatted(code));
|
||||
|
||||
// Old vilib schematic save - deprecated, use .lpschem format instead
|
||||
send(player, "<red>Warning: Old schematic format is deprecated. Use '/loparkour schematic save <name>' for .lpschem format.");
|
||||
}
|
||||
case "list" -> {
|
||||
send(player, "<dark_red><bold>Schematics <reset><gray>Loaded schematics:");
|
||||
LoParkour.getSchematicManager().getAllSchematics().forEach((name, schem) -> {
|
||||
send(player, "<gray>- <red>" + name + " <dark_gray>(" + schem.getMetadata().getDifficulty() + ")");
|
||||
});
|
||||
}
|
||||
case "reload" -> {
|
||||
if (!cooldown(sender, "LoParkour reload schematics", 2500)) {
|
||||
return;
|
||||
}
|
||||
LoParkour.getSchematicManager().reload();
|
||||
send(player, "<dark_red><bold>Schematics <reset><gray>Reloaded all schematics.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handle3Args(@NotNull String arg1, @NotNull String arg2, @NotNull String arg3, @NotNull CommandSender sender, @Nullable Player player) {
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (arg1.equalsIgnoreCase("schematic")) {
|
||||
if (!player.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
switch (arg2.toLowerCase()) {
|
||||
case "save" -> {
|
||||
if (!cooldown(sender, "LoParkour save schematic", 2500)) {
|
||||
return;
|
||||
}
|
||||
if (p == null) return;
|
||||
|
||||
Location[] selection = selections.get(player);
|
||||
if (selection == null || selection[0] == null || selection[1] == null) {
|
||||
send(player, "<dark_red><bold>Schematics <reset><gray>Your schematic isn't complete yet. Make sure you've set the first and second position.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
int width = Math.abs(selection[1].getBlockX() - selection[0].getBlockX()) + 1;
|
||||
int height = Math.abs(selection[1].getBlockY() - selection[0].getBlockY()) + 1;
|
||||
int length = Math.abs(selection[1].getBlockZ() - selection[0].getBlockZ()) + 1;
|
||||
|
||||
LPSchematic schematic = new LPSchematicBuilder(arg3, player.getName(), 0.5, width, height, length)
|
||||
.fromWorld(player.getWorld(), selection[0], selection[1])
|
||||
.build();
|
||||
|
||||
LoParkour.getSchematicManager().saveSchematic(schematic);
|
||||
send(player, "<dark_red><bold>Schematics <reset><gray>Saved schematic as <red>" + arg3 + "<gray>!");
|
||||
} catch (Exception e) {
|
||||
send(player, "<dark_red><bold>Schematics <reset><gray>Failed to save schematic: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
case "paste" -> {
|
||||
LPSchematic lpSchematic = LoParkour.getSchematicManager().getSchematic(arg3);
|
||||
if (lpSchematic != null) {
|
||||
lpSchematic.paste(player.getLocation(), player.getWorld());
|
||||
send(sender, "%sPasted .lpschem schematic %s".formatted(LoParkour.PREFIX, arg3));
|
||||
return;
|
||||
}
|
||||
|
||||
send(sender, "%sCouldn't find %s. Only .lpschem format is supported.".formatted(LoParkour.PREFIX, arg3));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void send(CommandSender sender, String message) {
|
||||
sender.sendMessage(ColorUtil.color(message));
|
||||
// ── 3-arg routing ──────────────────────────────────────────────────────────
|
||||
|
||||
private void handle3(String a1, String a2, String a3, CommandSender sender, @Nullable Player p) {
|
||||
if (p == null) return;
|
||||
if (!a1.equalsIgnoreCase("schematic")) return;
|
||||
if (!p.hasPermission(ParkourOption.ADMIN.permission)) return;
|
||||
SchematicCommandHandler.handleSubcommandWithName(a2, a3, sender, p, player);
|
||||
}
|
||||
|
||||
private List<String> completions(String arg, List<String> options) {
|
||||
String lower = arg.toLowerCase();
|
||||
return options.stream()
|
||||
.filter(option -> option.toLowerCase().startsWith(lower))
|
||||
.toList();
|
||||
// ── 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 + "Unknown player."); return; }
|
||||
|
||||
ParkourPlayer pp = ParkourPlayer.getPlayer(other);
|
||||
if (pp == null) { send(sender, LoParkour.PREFIX + "That player isn't playing."); return; }
|
||||
|
||||
ParkourUser user = ParkourUser.getUser(p);
|
||||
Session session = pp.session;
|
||||
if (user != null && user.session == session) return;
|
||||
|
||||
if (session.isAcceptingPlayers()) {
|
||||
((MultiMode) session.generator.getMode()).join(p, session);
|
||||
} else {
|
||||
Modes.SPECTATOR.create(p, session);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean cooldown(CommandSender sender, String key, long millis) {
|
||||
// Simple cooldown implementation - can be enhanced later
|
||||
return true;
|
||||
// ── 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", "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)) {
|
||||
ParkourPlayer.getPlayers().forEach(pp -> completions.add(pp.getName()));
|
||||
} else if (a1.equals("schematic") && sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
completions.addAll(Arrays.asList("wand", "pos1", "pos2", "save", "paste", "list", "reload"));
|
||||
} 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);
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// ── 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