feat: BlackKnife facade manager + tab completion + mode/tp/awaken subcommands

This commit is contained in:
SashegDev
2026-09-24 18:54:36 +00:00
parent 45c7250c08
commit 014a823c1b
6 changed files with 232 additions and 17 deletions
@@ -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<String> filter(List<String> in, String prefix) {
String low = prefix == null ? "" : prefix.toLowerCase();
List<String> out = new ArrayList<>();
for (String s : in) if (s.toLowerCase().startsWith(low)) out.add(s);
return out;
}
public static List<String> players(String prefix) {
List<String> 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;
}
}
@@ -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<String> SUBS = Arrays.asList("give", "reload", "mode", "tp");
private static final List<String> 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 <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 <get|set|add> <player> [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 <set|add> <player> <amount>").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 <get|set|add> <player> [amount]").color(NamedTextColor.YELLOW));
return true;
}
usage(sender);
return true;
}
private void usage(CommandSender sender) {
sender.sendMessage(Component.text("Usage: /blackknife give [player] | mode <mode> [player] | tp <get|set|add> <player> [amount] | reload").color(NamedTextColor.YELLOW));
}
@Override
public List<String> 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();
}
}
@@ -25,12 +25,24 @@ public class BlackKnifeListener implements Listener {
private final java.util.Map<java.util.UUID, BukkitRunnable> previewTasks = new java.util.HashMap<>();
private final java.util.Map<java.util.UUID, BukkitRunnable> lungeHighlightTasks = new java.util.HashMap<>();
private final java.util.Map<java.util.UUID, Integer> 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());
@@ -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(); }
@@ -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<String> SUBS = Arrays.asList("give", "reroll", "stats", "awaken");
private static final List<String> 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<String> types(String prefix) {
String low = prefix == null ? "" : prefix.toLowerCase();
List<String> 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 <player> [type] §7| §dreroll <player> §7| §dstats <player>"); return true; }
if (args.length == 0) { s.sendMessage("§d/magic give <player> [type] §7| §dreroll <player> §7| §dstats [player] §7| §dawaken <player> [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<String> 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();
}
}