diff --git a/src/main/java/me/sashegdev/blackknife/BlackKnife.java b/src/main/java/me/sashegdev/blackknife/BlackKnife.java new file mode 100644 index 0000000..0d537af --- /dev/null +++ b/src/main/java/me/sashegdev/blackknife/BlackKnife.java @@ -0,0 +1,91 @@ +package me.sashegdev.blackknife; + +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +/** + * Единая точка входа для всего плагина. + * Любой менеджер, режим ножа, выдача предметов, TP и перезагрузка — + * всё доступно отсюда: BlackKnife.tension().getTP(p) и т.д. + * Команды /blackknife и /magic построены поверх этого класса. + */ +public final class BlackKnife { + private static BlackKnifePlugin plugin; + + private BlackKnife() {} + + static void init(BlackKnifePlugin plugin) { BlackKnife.plugin = plugin; } + + public static BlackKnifePlugin plugin() { return plugin; } + public static TensionManager tension() { return plugin.getTension(); } + public static MagicManager magic() { return plugin.getMagicManager(); } + public static MagicListener magicListener() { return plugin.getMagicListener(); } + public static BlackKnifeListener knife() { return plugin.getKnifeListener(); } + public static SwoonHandler swoon() { return plugin.getSwoonHandler(); } + public static ChatHandler chat() { return plugin.getChatHandler(); } + public static AwakeningManager awakening() { return plugin.getAwakeningManager(); } + + // --- Режимы ножа --- + + public static String[] modes() { return BlackKnifeListener.MODES.clone(); } + + public static boolean isMode(String m) { + if (m == null) return false; + for (String mm : BlackKnifeListener.MODES) if (mm.equalsIgnoreCase(m)) return true; + return false; + } + + public static String mode(Player p) { return knife().getMode(p); } + + public static boolean setMode(Player p, String mode) { return knife().setMode(p, mode); } + + // --- Предметы --- + + public static void giveKnife(Player p) { + p.getInventory().addItem(BlackKnifeItem.create()); + tension().invalidateOwnerCache(p); + } + + public static void giveOrb(Player p) { + MagicProfile prof = magic().getOrCreate(p); + p.getInventory().addItem(MagicItem.create(prof)); + } + + // --- TP --- + + public static float tp(Player p) { return tension().getTP(p); } + + public static void setTp(Player p, float v) { tension().setTP(p, v); } + + public static void addTp(Player p, float v, String reason) { tension().addTP(p, v, reason); } + + // --- Перезагрузка --- + + public static void reloadAll() { + plugin.getChatConfig().load(); + plugin.reloadConfig(); + plugin.reloadLang(); + } + + // --- Хелперы для команд и таб-комплитов --- + + public static Player player(String name) { return plugin.getServer().getPlayer(name); } + + public static List filter(List in, String prefix) { + String low = prefix == null ? "" : prefix.toLowerCase(); + List out = new ArrayList<>(); + for (String s : in) if (s.toLowerCase().startsWith(low)) out.add(s); + return out; + } + + public static List players(String prefix) { + List out = new ArrayList<>(); + String low = prefix == null ? "" : prefix.toLowerCase(); + for (Player p : plugin.getServer().getOnlinePlayers()) { + if (p.getName().toLowerCase().startsWith(low)) out.add(p.getName()); + } + return out; + } +} diff --git a/src/main/java/me/sashegdev/blackknife/BlackKnifeCommand.java b/src/main/java/me/sashegdev/blackknife/BlackKnifeCommand.java index 1eb59ca..c443454 100644 --- a/src/main/java/me/sashegdev/blackknife/BlackKnifeCommand.java +++ b/src/main/java/me/sashegdev/blackknife/BlackKnifeCommand.java @@ -3,11 +3,19 @@ package me.sashegdev.blackknife; 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 net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -public class BlackKnifeCommand implements CommandExecutor { +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class BlackKnifeCommand implements CommandExecutor, TabCompleter { + private static final List SUBS = Arrays.asList("give", "reload", "mode", "tp"); + private static final List TP_OPS = Arrays.asList("get", "set", "add"); + private final BlackKnifePlugin plugin; private final ChatConfig chatConfig; private final ChatHandler chatHandler; @@ -16,23 +24,80 @@ public class BlackKnifeCommand implements CommandExecutor { @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (args.length >= 1 && args[0].equalsIgnoreCase("give")) { + if (args.length == 0) { usage(sender); return true; } + if (args[0].equalsIgnoreCase("give")) { Player target = null; - if (args.length >= 2) target = plugin.getServer().getPlayer(args[1]); + if (args.length >= 2) target = BlackKnife.player(args[1]); else if (sender instanceof Player p) target = p; if (target == null) { sender.sendMessage(Component.text("Player not found").color(NamedTextColor.RED)); return true; } - target.getInventory().addItem(BlackKnifeItem.create()); + BlackKnife.giveKnife(target); sender.sendMessage(Component.text("Gave Black Knife to " + target.getName()).color(NamedTextColor.GREEN)); return true; } - if (args.length >= 1 && args[0].equalsIgnoreCase("reload")) { + if (args[0].equalsIgnoreCase("reload")) { if (chatConfig != null) chatConfig.load(); plugin.reloadConfig(); plugin.reloadLang(); sender.sendMessage(Component.text("Chat+config reloaded lang=" + plugin.getLang()).color(NamedTextColor.GREEN)); return true; } - sender.sendMessage(Component.text("Usage: /blackknife give [player] | /blackknife reload").color(NamedTextColor.YELLOW)); + if (args[0].equalsIgnoreCase("mode")) { + if (args.length < 2) { sender.sendMessage(Component.text("Usage: /blackknife mode [player]").color(NamedTextColor.YELLOW)); return true; } + Player target = null; + if (args.length >= 3) target = BlackKnife.player(args[2]); + else if (sender instanceof Player p) target = p; + if (target == null) { sender.sendMessage(Component.text("Player not found").color(NamedTextColor.RED)); return true; } + if (!BlackKnife.setMode(target, args[1])) { + sender.sendMessage(Component.text("Unknown mode. Available: " + String.join(", ", BlackKnife.modes())).color(NamedTextColor.RED)); + return true; + } + sender.sendMessage(Component.text("Set mode " + BlackKnife.mode(target) + " for " + target.getName()).color(NamedTextColor.GREEN)); + return true; + } + if (args[0].equalsIgnoreCase("tp")) { + if (args.length < 3) { sender.sendMessage(Component.text("Usage: /blackknife tp [amount]").color(NamedTextColor.YELLOW)); return true; } + Player target = BlackKnife.player(args[2]); + if (target == null) { sender.sendMessage(Component.text("Player not found").color(NamedTextColor.RED)); return true; } + if (args[1].equalsIgnoreCase("get")) { + sender.sendMessage(Component.text("TP of " + target.getName() + ": " + (int) BlackKnife.tp(target)).color(NamedTextColor.YELLOW)); + return true; + } + if (args.length < 4) { sender.sendMessage(Component.text("Usage: /blackknife tp ").color(NamedTextColor.YELLOW)); return true; } + float amount; + try { amount = Float.parseFloat(args[3]); } catch (NumberFormatException e) { sender.sendMessage(Component.text("Not a number: " + args[3]).color(NamedTextColor.RED)); return true; } + if (args[1].equalsIgnoreCase("set")) { + BlackKnife.setTp(target, amount); + sender.sendMessage(Component.text("Set TP of " + target.getName() + " to " + (int) BlackKnife.tp(target)).color(NamedTextColor.GREEN)); + return true; + } + if (args[1].equalsIgnoreCase("add")) { + BlackKnife.addTp(target, amount, "ADMIN"); + sender.sendMessage(Component.text("TP of " + target.getName() + " now " + (int) BlackKnife.tp(target)).color(NamedTextColor.GREEN)); + return true; + } + sender.sendMessage(Component.text("Usage: /blackknife tp [amount]").color(NamedTextColor.YELLOW)); + return true; + } + usage(sender); return true; } + + private void usage(CommandSender sender) { + sender.sendMessage(Component.text("Usage: /blackknife give [player] | mode [player] | tp [amount] | reload").color(NamedTextColor.YELLOW)); + } + + @Override + public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { + if (args.length == 1) return BlackKnife.filter(SUBS, args[0]); + if (args[0].equalsIgnoreCase("give")) { + if (args.length == 2) return BlackKnife.players(args[1]); + } else if (args[0].equalsIgnoreCase("mode")) { + if (args.length == 2) return BlackKnife.filter(Arrays.asList(BlackKnife.modes()), args[1]); + if (args.length == 3) return BlackKnife.players(args[2]); + } else if (args[0].equalsIgnoreCase("tp")) { + if (args.length == 2) return BlackKnife.filter(TP_OPS, args[1]); + if (args.length == 3) return BlackKnife.players(args[2]); + } + return Collections.emptyList(); + } } diff --git a/src/main/java/me/sashegdev/blackknife/BlackKnifeListener.java b/src/main/java/me/sashegdev/blackknife/BlackKnifeListener.java index b1883d4..1ba3b9d 100644 --- a/src/main/java/me/sashegdev/blackknife/BlackKnifeListener.java +++ b/src/main/java/me/sashegdev/blackknife/BlackKnifeListener.java @@ -25,12 +25,24 @@ public class BlackKnifeListener implements Listener { private final java.util.Map previewTasks = new java.util.HashMap<>(); private final java.util.Map lungeHighlightTasks = new java.util.HashMap<>(); private final java.util.Map swordCombo = new java.util.HashMap<>(); - private static final String[] MODES = {"STARS", "SWORD", "DIAMOND", "DIAMOND_TRI", "BARRAGE", "LUNGE", "SNIPE", "TRI", "OVERHEAD", "GRENADE", "DIVE"}; + public static final String[] MODES = {"STARS", "SWORD", "DIAMOND", "DIAMOND_TRI", "BARRAGE", "LUNGE", "SNIPE", "TRI", "OVERHEAD", "GRENADE", "DIVE"}; public BlackKnifeListener(BlackKnifePlugin plugin) { this.plugin = plugin; } public String getMode(Player p) { return mode.getOrDefault(p.getUniqueId(), "STARS"); } + public boolean setMode(Player p, String m) { + for (String mm : MODES) { + if (mm.equalsIgnoreCase(m)) { + mode.put(p.getUniqueId(), mm); + updatePreview(p, mm); + p.sendActionBar(Component.text("Mode: " + mm).color(NamedTextColor.LIGHT_PURPLE)); + return true; + } + } + return false; + } + public void cleanupPlayer(Player p) { mode.remove(p.getUniqueId()); swordCombo.remove(p.getUniqueId()); diff --git a/src/main/java/me/sashegdev/blackknife/BlackKnifePlugin.java b/src/main/java/me/sashegdev/blackknife/BlackKnifePlugin.java index c235bac..61cef47 100644 --- a/src/main/java/me/sashegdev/blackknife/BlackKnifePlugin.java +++ b/src/main/java/me/sashegdev/blackknife/BlackKnifePlugin.java @@ -37,8 +37,13 @@ public class BlackKnifePlugin extends JavaPlugin { getServer().getPluginManager().registerEvents(chatHandler, this); getServer().getPluginManager().registerEvents(awakeningManager, this); getServer().getPluginManager().registerEvents(new KillMessageHandler(this), this); - getCommand("blackknife").setExecutor(new BlackKnifeCommand(this, chatConfig, chatHandler)); - getCommand("magic").setExecutor(new MagicCommand(magicManager, this)); + BlackKnife.init(this); + var bkCmd = new BlackKnifeCommand(this, chatConfig, chatHandler); + getCommand("blackknife").setExecutor(bkCmd); + getCommand("blackknife").setTabCompleter(bkCmd); + var magicCmd = new MagicCommand(magicManager, this); + getCommand("magic").setExecutor(magicCmd); + getCommand("magic").setTabCompleter(magicCmd); getServer().getScheduler().runTaskTimer(this, () -> tension.tickShield(), 20L, 1L); cleanupLegacyKnocked(); getLogger().info("BlackKnife 1.0.0 enabled - Paper 1.21.1 lang=" + lang); @@ -50,6 +55,9 @@ public class BlackKnifePlugin extends JavaPlugin { public MagicListener getMagicListener() { return magicListener; } public BlackKnifeListener getKnifeListener() { return knifeListener; } public SwoonHandler getSwoonHandler() { return swoonHandler; } + public ChatConfig getChatConfig() { return chatConfig; } + public ChatHandler getChatHandler() { return chatHandler; } + public AwakeningManager getAwakeningManager() { return awakeningManager; } public String getLang() { return lang; } public void reloadLang() { lang = getConfig().getString("lang", "ru"); if (awakeningManager != null) awakeningManager.reloadChances(); } diff --git a/src/main/java/me/sashegdev/blackknife/MagicCommand.java b/src/main/java/me/sashegdev/blackknife/MagicCommand.java index 247b1a2..659faa0 100644 --- a/src/main/java/me/sashegdev/blackknife/MagicCommand.java +++ b/src/main/java/me/sashegdev/blackknife/MagicCommand.java @@ -3,18 +3,35 @@ package me.sashegdev.blackknife; 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; -public class MagicCommand implements CommandExecutor { +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class MagicCommand implements CommandExecutor, TabCompleter { + private static final List SUBS = Arrays.asList("give", "reroll", "stats", "awaken"); + private static final List CAUSES = Arrays.asList("mob", "kill", "fall", "lava", "void", "generic"); + private final MagicManager mgr; private final BlackKnifePlugin plugin; public MagicCommand(MagicManager mgr, BlackKnifePlugin plugin) { this.mgr = mgr; this.plugin = plugin; } + private static List types(String prefix) { + String low = prefix == null ? "" : prefix.toLowerCase(); + List out = new java.util.ArrayList<>(); + for (MagicType mt : MagicType.values()) { + if (mt.name().toLowerCase().startsWith(low)) out.add(mt.name()); + } + return out; + } + @Override public boolean onCommand(CommandSender s, Command cmd, String label, String[] args) { - if (args.length == 0) { s.sendMessage("§d/magic give [type] §7| §dreroll §7| §dstats "); return true; } + if (args.length == 0) { s.sendMessage("§d/magic give [type] §7| §dreroll §7| §dstats [player] §7| §dawaken [cause]"); return true; } if (args[0].equalsIgnoreCase("give")) { - Player t = args.length > 1 ? plugin.getServer().getPlayer(args[1]) : (s instanceof Player p ? p : null); + Player t = args.length > 1 ? BlackKnife.player(args[1]) : (s instanceof Player p ? p : null); if (t == null) { s.sendMessage("§cPlayer not found"); return true; } MagicProfile prof = mgr.getOrCreate(t); if (args.length > 2) { @@ -25,21 +42,43 @@ public class MagicCommand implements CommandExecutor { return true; } if (args[0].equalsIgnoreCase("reroll") && args.length > 1) { - Player t = plugin.getServer().getPlayer(args[1]); + Player t = BlackKnife.player(args[1]); if (t == null) { s.sendMessage("§cPlayer not found"); return true; } MagicProfile prof = mgr.getOrCreate(t); prof.rareRolled = false; prof.rare.clear(); if (Math.random() < 0.05) { String[] pool = {"DETERMORE","FROSHE","PRAYER","SHIELDO"}; String pick = pool[(int)(Math.random()*pool.length)]; prof.rare.add(pick); s.sendMessage("§aReroll: got rare " + pick); } else s.sendMessage("§7Reroll: no rare (5%)"); mgr.save(prof); return true; } - if (args[0].equalsIgnoreCase("stats") && args.length > 1) { - Player t = plugin.getServer().getPlayer(args[1]); + if (args[0].equalsIgnoreCase("stats")) { + Player t = args.length > 1 ? BlackKnife.player(args[1]) : (s instanceof Player p ? p : null); if (t == null) { s.sendMessage("§cPlayer not found"); return true; } MagicProfile prof = mgr.getOrCreate(t); s.sendMessage("§d" + prof.nick + " casts:" + prof.casts + " tpSpent:" + (int)prof.tpSpent + " heals:" + prof.heals + " pack:" + prof.all()); return true; } + if (args[0].equalsIgnoreCase("awaken") && args.length > 1) { + Player t = BlackKnife.player(args[1]); + if (t == null) { s.sendMessage("§cPlayer not found"); return true; } + String cause = args.length > 2 ? args[2].toLowerCase() : "generic"; + MagicProfile prof = mgr.awaken(t, cause); + t.getInventory().addItem(MagicItem.create(prof)); + s.sendMessage("§aAwakened " + t.getName() + " via " + cause); + return true; + } s.sendMessage("§cUnknown subcommand"); return true; } + + @Override + public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { + if (args.length == 1) return BlackKnife.filter(SUBS, args[0]); + if (args[0].equalsIgnoreCase("give")) { + if (args.length == 2) return BlackKnife.players(args[1]); + if (args.length == 3) return types(args[2]); + } else if (args[0].equalsIgnoreCase("reroll") || args[0].equalsIgnoreCase("stats") || args[0].equalsIgnoreCase("awaken")) { + if (args.length == 2) return BlackKnife.players(args[1]); + if (args[0].equalsIgnoreCase("awaken") && args.length == 3) return BlackKnife.filter(CAUSES, args[2]); + } + return Collections.emptyList(); + } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 0f5a558..a283ab9 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -9,11 +9,11 @@ description: Black Knife with Roaring Knight attacks (SWOON, Stars, etc.) for Pa commands: blackknife: description: BlackKnife admin - usage: /blackknife give [player] + usage: /blackknife give|mode|tp|reload permission: blackknife.admin magic: description: Magic orb - usage: /magic give|reroll|stats + usage: /magic give|reroll|stats|awaken permission: blackknife.admin permissions: blackknife.use: