fix and migrate 70%
This commit is contained in:
parent
8705cad578
commit
d1dcf6ab57
138 changed files with 3736 additions and 4735 deletions
|
|
@ -0,0 +1,162 @@
|
|||
package dev.loki.loparkour.command;
|
||||
|
||||
import dev.loki.loparkour.LoParkour;
|
||||
import dev.loki.loparkour.api.Registry;
|
||||
import dev.loki.loparkour.config.Locales;
|
||||
import dev.loki.loparkour.leaderboard.Leaderboard;
|
||||
import dev.loki.loparkour.menu.ParkourOption;
|
||||
import dev.loki.loparkour.mode.Mode;
|
||||
import dev.loki.loparkour.mode.Modes;
|
||||
import dev.loki.loparkour.player.ParkourPlayer;
|
||||
import dev.loki.loparkour.player.ParkourUser;
|
||||
import dev.loki.loparkour.player.data.InventoryData;
|
||||
import dev.loki.loparkour.util.ColorUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.BlockCommandSender;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Handles admin-only /LoParkour sub-commands:
|
||||
* forcejoin, forceleave, reset, recoverinventory.
|
||||
*/
|
||||
public class AdminCommandHandler {
|
||||
|
||||
private final PlayerCommandHandler base;
|
||||
|
||||
public AdminCommandHandler(PlayerCommandHandler base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
public void handle(@NotNull String arg1, @NotNull String arg2,
|
||||
@NotNull CommandSender sender, @Nullable Player player) {
|
||||
|
||||
if (!sender.hasPermission(ParkourOption.ADMIN.permission)) return;
|
||||
|
||||
switch (arg1.toLowerCase()) {
|
||||
case "forcejoin" -> handleForceJoin(arg2, sender);
|
||||
case "forceleave" -> handleForceLeave(arg2, sender);
|
||||
case "reset" -> handleReset(arg2, sender);
|
||||
case "recoverinventory" -> handleRecoverInventory(arg2, sender);
|
||||
}
|
||||
|
||||
if (player == null) return;
|
||||
|
||||
if (arg1.equals("schematic")) {
|
||||
SchematicCommandHandler.handleSubcommand(arg2, sender, player, base);
|
||||
}
|
||||
}
|
||||
|
||||
// ── forcejoin ──────────────────────────────────────────────────────────────
|
||||
|
||||
private void handleForceJoin(String target, CommandSender sender) {
|
||||
if (target.equalsIgnoreCase("everyone")) {
|
||||
Bukkit.getOnlinePlayers().forEach(p -> Modes.DEFAULT.create(p));
|
||||
send(sender, LoParkour.PREFIX + "Force joined everyone!");
|
||||
return;
|
||||
}
|
||||
if (target.equalsIgnoreCase("nearest")) {
|
||||
Player closest = findNearest(sender);
|
||||
if (closest == null) return;
|
||||
Modes.DEFAULT.create(closest);
|
||||
send(sender, LoParkour.PREFIX + "Force joined " + closest.getName() + "!");
|
||||
return;
|
||||
}
|
||||
Player other = Bukkit.getPlayer(target);
|
||||
if (other == null) { send(sender, LoParkour.PREFIX + "Player not online!"); return; }
|
||||
Modes.DEFAULT.create(other);
|
||||
}
|
||||
|
||||
// ── forceleave ─────────────────────────────────────────────────────────────
|
||||
|
||||
private void handleForceLeave(String target, CommandSender sender) {
|
||||
if (target.equalsIgnoreCase("everyone")) {
|
||||
ParkourPlayer.getPlayers().forEach(ParkourUser::leave);
|
||||
send(sender, LoParkour.PREFIX + "Force kicked everyone!");
|
||||
return;
|
||||
}
|
||||
Player other = Bukkit.getPlayer(target);
|
||||
if (other == null) { send(sender, LoParkour.PREFIX + "Player not online!"); return; }
|
||||
ParkourUser user = ParkourUser.getUser(other);
|
||||
if (user == null) { send(sender, LoParkour.PREFIX + "Player isn't playing!"); return; }
|
||||
ParkourUser.leave(user);
|
||||
}
|
||||
|
||||
// ── reset ──────────────────────────────────────────────────────────────────
|
||||
|
||||
private void handleReset(String target, CommandSender sender) {
|
||||
if (!base.cooldown(sender, "reset", 2500)) return;
|
||||
|
||||
if (target.equalsIgnoreCase("everyone")) {
|
||||
Registry.getModes().stream()
|
||||
.map(Mode::getLeaderboard)
|
||||
.filter(lb -> lb != null)
|
||||
.forEach(lb -> { lb.resetAll(); lb.write(true); });
|
||||
send(sender, LoParkour.PREFIX + "Reset all high scores.");
|
||||
return;
|
||||
}
|
||||
|
||||
UUID uuid = resolveUUID(target);
|
||||
String name = resolvePlayerName(target, uuid);
|
||||
|
||||
Registry.getModes().stream()
|
||||
.map(Mode::getLeaderboard)
|
||||
.filter(lb -> lb != null)
|
||||
.forEach(lb -> { lb.remove(uuid); lb.write(true); });
|
||||
|
||||
send(sender, LoParkour.PREFIX + "Reset high score of " + name + ".");
|
||||
}
|
||||
|
||||
// ── recoverinventory ───────────────────────────────────────────────────────
|
||||
|
||||
private void handleRecoverInventory(String target, CommandSender sender) {
|
||||
if (!base.cooldown(sender, "recoverinventory", 2500)) return;
|
||||
Player other = Bukkit.getPlayer(target);
|
||||
if (other == null) { send(sender, LoParkour.PREFIX + "Player not online!"); return; }
|
||||
|
||||
new InventoryData(other).load(result -> {
|
||||
if (result != null) {
|
||||
send(sender, LoParkour.PREFIX + "Recovered inventory of " + other.getName() + ".");
|
||||
} else {
|
||||
send(sender, LoParkour.PREFIX + "<red>No saved inventory found for " + other.getName() + ".");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ── helpers ────────────────────────────────────────────────────────────────
|
||||
|
||||
private @Nullable Player findNearest(CommandSender sender) {
|
||||
Location from = sender instanceof Player p ? p.getLocation()
|
||||
: sender instanceof BlockCommandSender b ? b.getBlock().getLocation()
|
||||
: null;
|
||||
if (from == null || from.getWorld() == null) return null;
|
||||
|
||||
return from.getWorld().getPlayers().stream()
|
||||
.min((a, b) -> Double.compare(a.getLocation().distance(from), b.getLocation().distance(from)))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private UUID resolveUUID(String input) {
|
||||
Player online = Bukkit.getPlayerExact(input);
|
||||
if (online != null) return online.getUniqueId();
|
||||
if (input.contains("-")) return UUID.fromString(input);
|
||||
return Bukkit.getOfflinePlayer(input).getUniqueId();
|
||||
}
|
||||
|
||||
private String resolvePlayerName(String input, UUID uuid) {
|
||||
Player online = Bukkit.getPlayerExact(input);
|
||||
if (online != null) return online.getName();
|
||||
OfflinePlayer op = Bukkit.getOfflinePlayer(uuid);
|
||||
return op.getName() != null ? op.getName() : input;
|
||||
}
|
||||
|
||||
private void send(CommandSender sender, String msg) {
|
||||
sender.sendMessage(ColorUtil.color(msg));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
package dev.loki.loparkour.command;
|
||||
|
||||
import dev.loki.loparkour.LoParkour;
|
||||
import dev.loki.loparkour.config.Config;
|
||||
import dev.loki.loparkour.config.Locales;
|
||||
import dev.loki.loparkour.menu.Menus;
|
||||
import dev.loki.loparkour.menu.ParkourOption;
|
||||
import dev.loki.loparkour.mode.Modes;
|
||||
import dev.loki.loparkour.player.ParkourUser;
|
||||
import dev.loki.loparkour.util.ColorUtil;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Handles all player-facing /parkour sub-commands.
|
||||
* Admin commands are in {@link AdminCommandHandler}.
|
||||
*/
|
||||
public class PlayerCommandHandler {
|
||||
|
||||
private final Map<String, Long> cooldowns = new HashMap<>();
|
||||
|
||||
public void handleNoArgs(@NotNull CommandSender sender, @Nullable Player player) {
|
||||
if (player != null && ParkourOption.MAIN.mayPerform(player)) {
|
||||
Menus.MAIN.open(player);
|
||||
} else {
|
||||
sendHelp(sender);
|
||||
}
|
||||
}
|
||||
|
||||
public void handle(@NotNull String arg, @NotNull CommandSender sender, @Nullable Player player) {
|
||||
switch (arg.toLowerCase()) {
|
||||
case "help" -> sendHelp(sender);
|
||||
case "reload" -> handleReload(sender, player);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (ParkourUser.getUser(player) != null) return;
|
||||
Modes.DEFAULT.create(player);
|
||||
}
|
||||
case "leave" -> {
|
||||
if (!cooldown(sender, "leave", 2500)) return;
|
||||
ParkourUser.leave(player);
|
||||
}
|
||||
case "play" -> {
|
||||
if (ParkourOption.PLAY.mayPerform(player)) Menus.PLAY.open(player);
|
||||
}
|
||||
case "menu", "main" -> {
|
||||
if (ParkourOption.MAIN.mayPerform(player)) Menus.MAIN.open(player);
|
||||
}
|
||||
case "leaderboard" -> player.performCommand("LoParkour leaderboard invalid");
|
||||
case "schematic" -> {
|
||||
if (!player.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
send(sender, Locales.getString(player, "other.no_do"));
|
||||
return;
|
||||
}
|
||||
SchematicCommandHandler.sendHelp(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleReload(@NotNull CommandSender sender, @Nullable Player player) {
|
||||
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, LoParkour.PREFIX + "Reloaded config files.");
|
||||
}
|
||||
|
||||
public void sendHelp(@NotNull CommandSender sender) {
|
||||
send(sender, "");
|
||||
send(sender, "<dark_gray><strikethrough>---------------<reset> " + LoParkour.NAME + " <dark_gray><strikethrough>---------------<reset>");
|
||||
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 a mode");
|
||||
send(sender, "<gray>/parkour leave <dark_gray>- Leave parkour");
|
||||
}
|
||||
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>- Leaderboard");
|
||||
if (sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
send(sender, "<gray>/LoParkour schematic <dark_gray>- Schematic tools");
|
||||
send(sender, "<gray>/LoParkour reload <dark_gray>- Reload configs");
|
||||
send(sender, "<gray>/LoParkour reset <everyone/player> <dark_gray>- Reset scores");
|
||||
send(sender, "<gray>/LoParkour forcejoin/forceleave <target> <dark_gray>- Force join/leave");
|
||||
send(sender, "<gray>/LoParkour recoverinventory <player> <dark_gray>- Recover inventory");
|
||||
}
|
||||
send(sender, "");
|
||||
}
|
||||
|
||||
public boolean cooldown(CommandSender sender, String key, long millis) {
|
||||
String fullKey = sender.getName() + ":" + key;
|
||||
long now = System.currentTimeMillis();
|
||||
Long last = cooldowns.get(fullKey);
|
||||
if (last != null && now - last < millis) return false;
|
||||
cooldowns.put(fullKey, now);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void send(CommandSender sender, String message) {
|
||||
sender.sendMessage(ColorUtil.color(message));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
package dev.loki.loparkour.command;
|
||||
|
||||
import dev.loki.loparkour.LoParkour;
|
||||
import dev.loki.loparkour.schematic.lpschem.LPSchematic;
|
||||
import dev.loki.loparkour.schematic.lpschem.LPSchematicBuilder;
|
||||
import dev.loki.loparkour.util.ColorUtil;
|
||||
import dev.loki.loparkour.util.Locations;
|
||||
import dev.loki.loparkour.util.ParticleUtil;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.util.BoundingBox;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Handles /LoParkour schematic sub-commands (wand, pos1, pos2, save, paste, list, reload).
|
||||
*/
|
||||
public class SchematicCommandHandler {
|
||||
|
||||
public static final Map<Player, Location[]> selections = new HashMap<>();
|
||||
|
||||
private static final ItemStack WAND = buildWand();
|
||||
|
||||
private static ItemStack buildWand() {
|
||||
ItemStack item = new ItemStack(Material.GOLDEN_AXE);
|
||||
ItemMeta meta = item.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")
|
||||
));
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
public static ItemStack getWand() {
|
||||
return WAND.clone();
|
||||
}
|
||||
|
||||
public static void sendHelp(Player player) {
|
||||
send(player, "");
|
||||
send(player, "<dark_red><bold>Schematics <reset><dark_gray>-----------");
|
||||
send(player, "<red>/LoParkour schematic wand <dark_gray>- <gray>Get the wand");
|
||||
send(player, "<red>/LoParkour schematic pos1 <dark_gray>- <gray>Set position 1");
|
||||
send(player, "<red>/LoParkour schematic pos2 <dark_gray>- <gray>Set position 2");
|
||||
send(player, "<red>/LoParkour schematic save <n> <dark_gray>- <gray>Save selection");
|
||||
send(player, "<red>/LoParkour schematic paste <n> <dark_gray>- <gray>Paste schematic");
|
||||
send(player, "<red>/LoParkour schematic list <dark_gray>- <gray>List loaded schematics");
|
||||
send(player, "<red>/LoParkour schematic reload <dark_gray>- <gray>Reload schematics");
|
||||
send(player, "");
|
||||
}
|
||||
|
||||
/** Called for 2-arg schematic commands (wand/pos1/pos2/list/reload) */
|
||||
public static void handleSubcommand(String sub, CommandSender sender, Player player, PlayerCommandHandler cooldowns) {
|
||||
Location playerLoc = player.getLocation();
|
||||
Location[] sel = selections.get(player);
|
||||
|
||||
switch (sub.toLowerCase()) {
|
||||
case "wand" -> {
|
||||
player.getInventory().addItem(WAND.clone());
|
||||
send(player, "<dark_red><bold>Schematics <reset><gray>Wand given. Left/Right click to set positions.");
|
||||
}
|
||||
case "pos1" -> setPos(player, sel, playerLoc, 0);
|
||||
case "pos2" -> setPos(player, sel, playerLoc, 1);
|
||||
case "list" -> {
|
||||
send(player, "<dark_red><bold>Schematics <reset><gray>Loaded schematics:");
|
||||
LoParkour.getSchematicManager().getAllSchematics().forEach((name, s) ->
|
||||
send(player, "<gray>- <red>" + name + " <dark_gray>(" + s.getMetadata().getDifficulty() + ")"));
|
||||
}
|
||||
case "reload" -> {
|
||||
if (!cooldowns.cooldown(sender, "schematic-reload", 2500)) return;
|
||||
LoParkour.getSchematicManager().reload();
|
||||
send(player, "<dark_red><bold>Schematics <reset><gray>Reloaded.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Called for 3-arg schematic commands (save <n>, paste <n>) */
|
||||
public static void handleSubcommandWithName(String sub, String name, CommandSender sender,
|
||||
Player player, PlayerCommandHandler cooldowns) {
|
||||
switch (sub.toLowerCase()) {
|
||||
case "save" -> handleSave(name, sender, player, cooldowns);
|
||||
case "paste" -> handlePaste(name, sender, player);
|
||||
}
|
||||
}
|
||||
|
||||
// ── internal ───────────────────────────────────────────────────────────────
|
||||
|
||||
private static void setPos(Player player, Location[] existing, Location loc, int index) {
|
||||
String label = index == 0 ? "1" : "2";
|
||||
send(player, LoParkour.PREFIX + "Position " + label + " set to " + Locations.toString(loc, true));
|
||||
|
||||
Location[] updated = existing != null ? existing.clone() : new Location[]{null, null};
|
||||
updated[index] = loc;
|
||||
selections.put(player, updated);
|
||||
|
||||
if (updated[0] != null && updated[1] != null) {
|
||||
ParticleUtil.box(BoundingBox.of(updated[0], updated[1]), player.getWorld(), Particle.END_ROD, player, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleSave(String name, CommandSender sender, Player player, PlayerCommandHandler cooldowns) {
|
||||
if (!cooldowns.cooldown(sender, "schematic-save", 2500)) return;
|
||||
|
||||
Location[] sel = selections.get(player);
|
||||
if (sel == null || sel[0] == null || sel[1] == null) {
|
||||
send(player, "<dark_red><bold>Schematics <reset><red>Selection incomplete. Set both positions first.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
int w = Math.abs(sel[1].getBlockX() - sel[0].getBlockX()) + 1;
|
||||
int h = Math.abs(sel[1].getBlockY() - sel[0].getBlockY()) + 1;
|
||||
int l = Math.abs(sel[1].getBlockZ() - sel[0].getBlockZ()) + 1;
|
||||
|
||||
LPSchematic schematic = new LPSchematicBuilder(name, player.getName(), 0.5, w, h, l)
|
||||
.fromWorld(player.getWorld(), sel[0], sel[1])
|
||||
.build();
|
||||
|
||||
LoParkour.getSchematicManager().saveSchematic(schematic);
|
||||
send(player, "<dark_red><bold>Schematics <reset><gray>Saved as <red>" + name + "<gray>!");
|
||||
} catch (Exception e) {
|
||||
send(player, "<dark_red><bold>Schematics <reset><red>Failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void handlePaste(String name, CommandSender sender, Player player) {
|
||||
LPSchematic s = LoParkour.getSchematicManager().getSchematic(name);
|
||||
if (s == null) {
|
||||
send(sender, LoParkour.PREFIX + "Schematic '" + name + "' not found.");
|
||||
return;
|
||||
}
|
||||
s.paste(player.getLocation(), player.getWorld());
|
||||
send(sender, LoParkour.PREFIX + "Pasted " + name + ".");
|
||||
}
|
||||
|
||||
private static void send(CommandSender sender, String msg) {
|
||||
sender.sendMessage(ColorUtil.color(msg));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue