fix: wand listener, killer/survivor spawn commands, double phase exit, generatorManager null check

This commit is contained in:
loki5512344 2026-06-03 20:03:31 +02:00
parent 1adb8c84fd
commit b339f4c029
5 changed files with 125 additions and 21 deletions

View file

@ -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 <name>"));
@ -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 <generator|hook|pallet|chest|totem|gate|lobby>"));
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();

View file

@ -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<String> 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<Location> getSurvivorSpawns() {
return loadLocationList("survivor-spawns");
}

View file

@ -67,10 +67,11 @@ public class GameSession {
}
private void transitionToNextPhase() {
Phase next = determineNextPhase();
if (next != null) {
currentPhase.exit(this);
Phase nextPhase = determineNextPhase();
if (nextPhase != null) {
switchPhase(nextPhase);
currentPhase = next;
currentPhase.enter(this);
}
}

View file

@ -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<Player, Action> onGeneratorInteract;
private BiConsumer<Player, Boolean> 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<Player, Action> h) { this.onGeneratorInteract = h; }
public void setOnAttack(BiConsumer<Player, Boolean> h) { this.onAttack = h; }
public void setOnPalletInteract(BiConsumer<Player, Boolean> 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;
}

View file

@ -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");