From b339f4c0294b7c3d635cb2b5f035776691a8e244 Mon Sep 17 00:00:00 2001 From: loki5512344 Date: Wed, 3 Jun 2026 20:03:31 +0200 Subject: [PATCH] fix: wand listener, killer/survivor spawn commands, double phase exit, generatorManager null check --- .../java/dev/loki/command/SetupCommand.java | 70 +++++++++++++++---- .../java/dev/loki/config/LocationsConfig.java | 10 +++ src/main/java/dev/loki/core/GameSession.java | 9 +-- .../loki/listener/PlayerInteractListener.java | 52 +++++++++++++- src/main/java/dev/loki/mdbd.java | 5 +- 5 files changed, 125 insertions(+), 21 deletions(-) diff --git a/src/main/java/dev/loki/command/SetupCommand.java b/src/main/java/dev/loki/command/SetupCommand.java index 1e1ac69..ced2efb 100644 --- a/src/main/java/dev/loki/command/SetupCommand.java +++ b/src/main/java/dev/loki/command/SetupCommand.java @@ -83,6 +83,13 @@ public class SetupCommand implements TabExecutor { return true; } + /** Called by PlayerInteractListener when wand is used. */ + public void setWandPos(Player player, int num, Location loc) { + String key = player.getUniqueId().toString(); + selectionCorners.put(key + "_pos" + num, loc); + player.sendMessage(TextUtil.color("<#00FF00>[Wand] Точка " + num + ": " + formatLoc(loc))); + } + private boolean saveTemplate(Player player, String[] args) { if (args.length < 2) { player.sendMessage(TextUtil.color("<#FF0000>Использование: /dbdsetup save ")); @@ -132,28 +139,65 @@ public class SetupCommand implements TabExecutor { private boolean setObject(Player player, String[] args) { if (args.length < 2) { - player.sendMessage(TextUtil.color("<#FF0000>Использование: /dbdsetup set ")); + player.sendMessage(TextUtil.color("<#FF0000>Использование: /dbdsetup set <тип>")); + player.sendMessage(TextUtil.color("<#FFD700>Типы: generator, hook, pallet, gate, killer-spawn, survivor-spawn, lobby")); return true; } - Location loc = player.getLocation().getBlock().getLocation(); + // For spawns and hooks use exact player location (with yaw/pitch) + // For block-based objects (generator) use block location String type = args[1].toLowerCase(); var locations = plugin.getConfigManager().getLocations(); switch (type) { - case "generator" -> locations.addLocation("generators", loc); - case "hook" -> locations.addLocation("hooks", loc); - case "pallet" -> locations.addLocation("pallets", loc); - case "chest" -> locations.addLocation("chests", loc); - case "totem" -> locations.addLocation("totems", loc); - case "gate" -> locations.addLocation("exitgates", loc); - case "lobby" -> locations.setLobby(loc); + case "generator" -> { + Location loc = player.getLocation().getBlock().getLocation(); + loc.add(0.5, 0, 0.5); // center of block + locations.addLocation("generators", loc); + plugin.getConfigManager().saveConfig("locations.yml", locations.getConfig()); + player.sendMessage(TextUtil.color("<#00FF00>Генератор установлен на " + formatLoc(loc))); + } + case "hook" -> { + Location loc = player.getLocation(); + locations.addLocation("hooks", loc); + plugin.getConfigManager().saveConfig("locations.yml", locations.getConfig()); + player.sendMessage(TextUtil.color("<#00FF00>Крюк установлен на " + formatLoc(loc))); + } + case "pallet" -> { + Location loc = player.getLocation().getBlock().getLocation(); + locations.addLocation("pallets", loc); + plugin.getConfigManager().saveConfig("locations.yml", locations.getConfig()); + player.sendMessage(TextUtil.color("<#00FF00>Паллет установлен на " + formatLoc(loc))); + } + case "gate" -> { + Location loc = player.getLocation(); + locations.addLocation("exitgates", loc); + plugin.getConfigManager().saveConfig("locations.yml", locations.getConfig()); + player.sendMessage(TextUtil.color("<#00FF00>Ворота установлены на " + formatLoc(loc))); + } + case "killer-spawn", "killer_spawn" -> { + Location loc = player.getLocation(); + locations.setKillerSpawn(loc); + plugin.getConfigManager().saveConfig("locations.yml", locations.getConfig()); + player.sendMessage(TextUtil.color("<#FF4444>Спавн киллера установлен на " + formatLoc(loc))); + } + case "survivor-spawn", "survivor_spawn" -> { + Location loc = player.getLocation(); + locations.addLocation("survivor-spawns", loc); + plugin.getConfigManager().saveConfig("locations.yml", locations.getConfig()); + int count = locations.getSurvivorSpawns().size(); + player.sendMessage(TextUtil.color("<#00FF00>Спавн выжившего #" + count + " установлен на " + formatLoc(loc))); + } + case "lobby" -> { + Location loc = player.getLocation(); + locations.setLobby(loc); + plugin.getConfigManager().saveConfig("locations.yml", locations.getConfig()); + player.sendMessage(TextUtil.color("<#00FF00>Лобби установлено на " + formatLoc(loc))); + } default -> { player.sendMessage(TextUtil.color("<#FF0000>Неизвестный тип: " + type)); - return true; + player.sendMessage(TextUtil.color("<#FFD700>Типы: generator, hook, pallet, gate, killer-spawn, survivor-spawn, lobby")); } } - plugin.getConfigManager().saveConfig("locations.yml", locations.getConfig()); - player.sendMessage(TextUtil.color("<#00FF00>Установлен: " + type + " на " + formatLoc(loc))); return true; } @@ -210,7 +254,7 @@ public class SetupCommand implements TabExecutor { .toList(); } if (args.length == 2 && args[0].equalsIgnoreCase("set")) { - return Arrays.asList("generator", "hook", "pallet", "chest", "totem", "gate", "lobby") + return Arrays.asList("generator", "hook", "pallet", "gate", "killer-spawn", "survivor-spawn", "lobby") .stream() .filter(s -> s.startsWith(args[1].toLowerCase())) .toList(); diff --git a/src/main/java/dev/loki/config/LocationsConfig.java b/src/main/java/dev/loki/config/LocationsConfig.java index d499ecc..de5bf66 100644 --- a/src/main/java/dev/loki/config/LocationsConfig.java +++ b/src/main/java/dev/loki/config/LocationsConfig.java @@ -109,6 +109,16 @@ public class LocationsConfig { return spawns.isEmpty() ? null : spawns.get(0); } + public void setKillerSpawn(Location loc) { + // killer-spawn is a single location stored as a list with one entry + List list = new java.util.ArrayList<>(); + list.add(String.format("%s,%.2f,%.2f,%.2f,%.1f,%.1f", + loc.getWorld().getName(), + loc.getX(), loc.getY(), loc.getZ(), + loc.getYaw(), loc.getPitch())); + config.set("killer-spawn", list); + } + public List getSurvivorSpawns() { return loadLocationList("survivor-spawns"); } diff --git a/src/main/java/dev/loki/core/GameSession.java b/src/main/java/dev/loki/core/GameSession.java index a3be4fd..3504639 100644 --- a/src/main/java/dev/loki/core/GameSession.java +++ b/src/main/java/dev/loki/core/GameSession.java @@ -67,10 +67,11 @@ public class GameSession { } private void transitionToNextPhase() { - currentPhase.exit(this); - Phase nextPhase = determineNextPhase(); - if (nextPhase != null) { - switchPhase(nextPhase); + Phase next = determineNextPhase(); + if (next != null) { + currentPhase.exit(this); + currentPhase = next; + currentPhase.enter(this); } } diff --git a/src/main/java/dev/loki/listener/PlayerInteractListener.java b/src/main/java/dev/loki/listener/PlayerInteractListener.java index d5a52fd..b71f312 100644 --- a/src/main/java/dev/loki/listener/PlayerInteractListener.java +++ b/src/main/java/dev/loki/listener/PlayerInteractListener.java @@ -1,15 +1,19 @@ package dev.loki.listener; +import dev.loki.command.SetupCommand; import dev.loki.core.GameManager; import dev.loki.objective.GeneratorManager; import dev.loki.player.BasePlayer; import dev.loki.player.PlayerState; +import dev.loki.util.TextUtil; +import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; import java.util.Map; @@ -21,6 +25,7 @@ public class PlayerInteractListener implements Listener { private final Plugin plugin; private final GameManager gameManager; private final GeneratorManager generatorManager; + private SetupCommand setupCommand; private BiConsumer onGeneratorInteract; private BiConsumer onAttack; @@ -38,6 +43,10 @@ public class PlayerInteractListener implements Listener { this.generatorManager = generatorManager; } + public void setSetupCommand(SetupCommand setupCommand) { + this.setupCommand = setupCommand; + } + public void setOnGeneratorInteract(BiConsumer h) { this.onGeneratorInteract = h; } public void setOnAttack(BiConsumer h) { this.onAttack = h; } public void setOnPalletInteract(BiConsumer h) { this.onPalletInteract = h; } @@ -49,6 +58,10 @@ public class PlayerInteractListener implements Listener { public void onInteract(PlayerInteractEvent event) { if (event.getHand() != EquipmentSlot.HAND) return; Player player = event.getPlayer(); + + // Handle wand regardless of game state + if (handleWand(event, player)) return; + if (!gameManager.isInGame(player.getUniqueId())) return; var session = gameManager.getPlayerSession(player.getUniqueId()); if (session == null) return; @@ -63,6 +76,41 @@ public class PlayerInteractListener implements Listener { else if (action.isLeftClick()) handleLeftClick(event, player, bp); } + /** + * Handles the DBD wand (STICK with custom display name). + * LMB on block = pos1, RMB on block = pos2. + * Returns true if the event was consumed by the wand. + */ + private boolean handleWand(PlayerInteractEvent event, Player player) { + if (setupCommand == null) return false; + if (!player.hasPermission("mdbd.admin")) return false; + + ItemStack item = event.getItem(); + if (item == null || item.getType() != Material.STICK) return false; + if (!item.hasItemMeta()) return false; + + var meta = item.getItemMeta(); + // Check it's the DBD wand by display name component + if (meta.displayName() == null) return false; + String plain = net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer.plainText() + .serialize(meta.displayName()); + if (!plain.contains("DBD Wand")) return false; + + event.setCancelled(true); + + Action action = event.getAction(); + if (action == Action.LEFT_CLICK_BLOCK || action == Action.LEFT_CLICK_AIR) { + setupCommand.setWandPos(player, 1, event.getClickedBlock() != null + ? event.getClickedBlock().getLocation() + : player.getLocation().getBlock().getLocation()); + } else if (action == Action.RIGHT_CLICK_BLOCK || action == Action.RIGHT_CLICK_AIR) { + setupCommand.setWandPos(player, 2, event.getClickedBlock() != null + ? event.getClickedBlock().getLocation() + : player.getLocation().getBlock().getLocation()); + } + return true; + } + private boolean isIncapacitated(BasePlayer bp) { return bp.getState() == PlayerState.DOWNED || bp.getState() == PlayerState.HOOKED; } @@ -77,7 +125,7 @@ public class PlayerInteractListener implements Listener { private void handleRightClick(PlayerInteractEvent event, Player player, BasePlayer bp) { if (event.getClickedBlock() == null) { - if (!bp.isKiller() && onGeneratorInteract != null && generatorManager.isInAnyZone(player)) { + if (!bp.isKiller() && onGeneratorInteract != null && generatorManager != null && generatorManager.isInAnyZone(player)) { onGeneratorInteract.accept(player, event.getAction()); return; } @@ -85,7 +133,7 @@ public class PlayerInteractListener implements Listener { return; } - if (!bp.isKiller() && onGeneratorInteract != null && generatorManager.isInAnyZone(player)) { + if (!bp.isKiller() && onGeneratorInteract != null && generatorManager != null && generatorManager.isInAnyZone(player)) { onGeneratorInteract.accept(player, event.getAction()); return; } diff --git a/src/main/java/dev/loki/mdbd.java b/src/main/java/dev/loki/mdbd.java index 7dfbbc7..20033ba 100644 --- a/src/main/java/dev/loki/mdbd.java +++ b/src/main/java/dev/loki/mdbd.java @@ -64,8 +64,9 @@ public final class mdbd extends JavaPlugin { new GeneratorSelectListener(dbdAdminCommand, generatorData), this); getServer().getPluginManager().registerEvents( new PlayerQuitListener(this, gameManager), this); - getServer().getPluginManager().registerEvents( - new PlayerInteractListener(this, gameManager, null), this); + var interactListener = new PlayerInteractListener(this, gameManager, null); + interactListener.setSetupCommand(setupCommand); + getServer().getPluginManager().registerEvents(interactListener, this); getLogger().info("Mdbd Plugin enabled successfully!"); getLogger().info("Loaded " + templateManager.getAllTemplates().size() + " templates");