remove: template save/load/list from SetupCommand

This commit is contained in:
loki5512344 2026-06-03 20:46:35 +02:00
parent fcf2debbd4
commit 78fc8bfb55
5 changed files with 182 additions and 132 deletions

View file

@ -198,6 +198,17 @@ public class DBDAdminCommand implements TabExecutor {
return selectingGenerator.contains(uuid);
}
public void toggleGeneratorMode(org.bukkit.entity.Player player) {
if (selectingGenerator.contains(player.getUniqueId())) {
selectingGenerator.remove(player.getUniqueId());
player.sendMessage(TextUtil.color("<#FFA500>Режим выбора генератора отключен"));
} else {
selectingGenerator.add(player.getUniqueId());
player.sendMessage(TextUtil.color("<#00FF00>Режим выбора генератора включен!"));
player.sendMessage(TextUtil.color("<#FFD700>Сломайте блок чтобы установить генератор"));
}
}
public void shutdown() {
if (actionBarTask != null) {
actionBarTask.cancel();

View file

@ -18,6 +18,8 @@ import java.util.List;
public class SetupCommand implements TabExecutor {
private final mdbd plugin;
private final java.util.Map<String, Location> selectionCorners;
private final java.util.Set<java.util.UUID> selectingKillerSpawn = new java.util.HashSet<>();
private final java.util.Set<java.util.UUID> selectingSurvivorSpawn = new java.util.HashSet<>();
public SetupCommand(mdbd plugin) {
this.plugin = plugin;
@ -31,36 +33,29 @@ public class SetupCommand implements TabExecutor {
sender.sendMessage(Component.text("Нет прав!", NamedTextColor.RED));
return true;
}
if (!(sender instanceof Player player)) {
sender.sendMessage(Component.text("Только игроки!", NamedTextColor.RED));
return true;
}
if (args.length == 0) {
sendUsage(sender);
return true;
}
String sub = args[0].toLowerCase();
return switch (sub) {
return switch (args[0].toLowerCase()) {
case "wand" -> giveWand(player);
case "pos1" -> setPos(player, 1);
case "pos2" -> setPos(player, 2);
case "save" -> saveTemplate(player, args);
case "load" -> loadTemplate(player, args);
case "list" -> listTemplates(sender);
case "set" -> setObject(player, args);
case "build" -> buildMap(player);
case "clear" -> clearMap(player);
case "lobby" -> setLobby(player);
default -> {
sendUsage(sender);
yield true;
}
default -> { sendUsage(sender); yield true; }
};
}
// ── wand ─────────────────────────────────────────────────────────────────
private boolean giveWand(Player player) {
var wand = new org.bukkit.inventory.ItemStack(org.bukkit.Material.STICK);
wand.editMeta(meta -> {
@ -69,9 +64,12 @@ public class SetupCommand implements TabExecutor {
TextUtil.color("<#FFD700>ЛКМ — Первая точка"),
TextUtil.color("<#FFD700>ПКМ — Вторая точка")
));
var key = new org.bukkit.NamespacedKey(plugin, "dbd_wand");
meta.getPersistentDataContainer().set(key,
org.bukkit.persistence.PersistentDataType.BYTE, (byte) 1);
});
player.getInventory().addItem(wand);
player.sendMessage(TextUtil.color("<#00FF00>Получена палочка выделения!"));
player.sendMessage(TextUtil.color("<#00FF00>Получена палочка! <gray>ЛКМ=pos1 ПКМ=pos2"));
return true;
}
@ -83,59 +81,14 @@ public class SetupCommand implements TabExecutor {
return true;
}
/** Called by PlayerInteractListener when wand is used. */
/** Called by PlayerInteractListener when wand is used on a block. */
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>"));
return true;
}
String key = player.getUniqueId().toString();
Location pos1 = selectionCorners.get(key + "_pos1");
Location pos2 = selectionCorners.get(key + "_pos2");
if (pos1 == null || pos2 == null) {
player.sendMessage(TextUtil.color("<#FF0000>Сначала установите обе точки!"));
return true;
}
plugin.getTemplateManager().saveTemplate(args[1], pos1, pos2);
player.sendMessage(TextUtil.color("<#00FF00>Шаблон '" + args[1] + "' сохранен!"));
return true;
}
private boolean loadTemplate(Player player, String[] args) {
if (args.length < 2) {
player.sendMessage(TextUtil.color("<#FF0000>Использование: /dbdsetup load <name>"));
return true;
}
var template = plugin.getTemplateManager().getTemplate(args[1]);
if (template == null) {
player.sendMessage(TextUtil.color("<#FF0000>Шаблон не найден!"));
return true;
}
template.place(player.getLocation(), false);
player.sendMessage(TextUtil.color("<#00FF00>Шаблон '" + args[1] + "' загружен!"));
return true;
}
private boolean listTemplates(CommandSender sender) {
var templates = plugin.getTemplateManager().getAllTemplates();
sender.sendMessage(TextUtil.color("<#FFD700>=== Шаблоны ==="));
if (templates.isEmpty()) {
sender.sendMessage(TextUtil.color("<#808080>Нет шаблонов"));
} else {
templates.keySet().forEach(name ->
sender.sendMessage(TextUtil.color("<#00CED1>- " + name))
);
}
return true;
}
// ── set <type> ────────────────────────────────────────────────────────────
private boolean setObject(Player player, String[] args) {
if (args.length < 2) {
@ -143,55 +96,59 @@ public class SetupCommand implements TabExecutor {
player.sendMessage(TextUtil.color("<#FFD700>Типы: generator, hook, pallet, gate, killer-spawn, survivor-spawn, lobby"));
return true;
}
// 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" -> {
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)));
plugin.getDbdAdminCommand().toggleGeneratorMode(player);
return true;
}
case "killer-spawn", "killer_spawn" -> {
if (selectingKillerSpawn.remove(player.getUniqueId())) {
player.sendMessage(TextUtil.color("<#FFA500>Режим спавна киллера отключен"));
} else {
selectingKillerSpawn.add(player.getUniqueId());
player.sendMessage(TextUtil.color("<#FF4444>Режим спавна киллера включен!"));
player.sendMessage(TextUtil.color("<#FFD700>Сломайте блок для установки (блок не сломается)"));
}
return true;
}
case "survivor-spawn", "survivor_spawn" -> {
if (selectingSurvivorSpawn.remove(player.getUniqueId())) {
player.sendMessage(TextUtil.color("<#FFA500>Режим спавна выжившего отключен"));
} else {
selectingSurvivorSpawn.add(player.getUniqueId());
int current = locations.getSurvivorSpawns().size();
player.sendMessage(TextUtil.color("<#00FF00>Режим спавна выжившего включен! Уже: " + current));
player.sendMessage(TextUtil.color("<#FFD700>Сломайте блок для установки (блок не сломается)"));
}
return true;
}
case "hook" -> {
Location loc = player.getLocation();
locations.addLocation("hooks", loc);
plugin.getConfigManager().saveConfig("locations.yml", locations.getConfig());
player.sendMessage(TextUtil.color("<#00FF00>Крюк установлен на " + formatLoc(loc)));
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)));
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)));
player.sendMessage(TextUtil.color("<#00FF00>Ворота установлены: " + 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)));
player.sendMessage(TextUtil.color("<#00FF00>Лобби установлено: " + formatLoc(loc)));
}
default -> {
player.sendMessage(TextUtil.color("<#FF0000>Неизвестный тип: " + type));
@ -201,6 +158,33 @@ public class SetupCommand implements TabExecutor {
return true;
}
// ── spawn selection callbacks (called by SetupBlockBreakListener) ─────────
public boolean isSelectingKillerSpawn(java.util.UUID uuid) {
return selectingKillerSpawn.contains(uuid);
}
public boolean isSelectingSurvivorSpawn(java.util.UUID uuid) {
return selectingSurvivorSpawn.contains(uuid);
}
public void onKillerSpawnSelected(Player player, Location loc) {
plugin.getConfigManager().getLocations().setKillerSpawn(loc);
plugin.getConfigManager().saveConfig("locations.yml",
plugin.getConfigManager().getLocations().getConfig());
player.sendMessage(TextUtil.color("<#FF4444>Спавн киллера установлен: " + formatLoc(loc)));
}
public void onSurvivorSpawnSelected(Player player, Location loc) {
var locations = plugin.getConfigManager().getLocations();
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)));
}
// ── build / clear / lobby ─────────────────────────────────────────────────
private boolean buildMap(Player player) {
player.sendMessage(TextUtil.color("<#FFD700>Строительство карты..."));
plugin.getMapBuilder().buildMap(plugin.getConfigManager().getLocations());
@ -220,21 +204,20 @@ public class SetupCommand implements TabExecutor {
plugin.getConfigManager().getLocations().setLobby(loc);
plugin.getConfigManager().saveConfig("locations.yml",
plugin.getConfigManager().getLocations().getConfig());
player.sendMessage(TextUtil.color("<#00FF00>Лобби установлено на " + formatLoc(loc)));
player.sendMessage(TextUtil.color("<#00FF00>Лобби установлено: " + formatLoc(loc)));
return true;
}
// ── usage / helpers ───────────────────────────────────────────────────────
private void sendUsage(CommandSender sender) {
sender.sendMessage(TextUtil.color("<#FF6B00>=== DBD Setup ==="));
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup wand — Получить палочку"));
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup pos1/pos2 — Установить точки"));
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup save <name> — Сохранить шаблон"));
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup load <name> — Загрузить шаблон"));
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup list — Список шаблонов"));
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup set <type> — Установить объект"));
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup wand — Получить палочку выделения"));
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup pos1/pos2 — Установить точки выделения"));
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup set <type> — Установить объект на карте"));
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup build — Построить карту"));
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup clear — Очистить карту"));
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup lobby — Установить лобби"));
sender.sendMessage(TextUtil.color("<#FFD700>/dbdsetup lobby — Установить спавн лобби"));
}
private String formatLoc(Location loc) {
@ -248,22 +231,18 @@ public class SetupCommand implements TabExecutor {
if (!sender.hasPermission("mdbd.admin")) return List.of();
if (args.length == 1) {
return Arrays.asList("wand", "pos1", "pos2", "save", "load", "list",
"set", "build", "clear", "lobby").stream()
return Arrays.asList("wand", "pos1", "pos2", "set", "build", "clear", "lobby")
.stream()
.filter(s -> s.startsWith(args[0].toLowerCase()))
.toList();
}
if (args.length == 2 && args[0].equalsIgnoreCase("set")) {
return Arrays.asList("generator", "hook", "pallet", "gate", "killer-spawn", "survivor-spawn", "lobby")
return Arrays.asList("generator", "hook", "pallet", "gate",
"killer-spawn", "survivor-spawn", "lobby")
.stream()
.filter(s -> s.startsWith(args[1].toLowerCase()))
.toList();
}
if (args.length == 2 && (args[0].equalsIgnoreCase("save") || args[0].equalsIgnoreCase("load"))) {
return plugin.getTemplateManager().getAllTemplates().keySet().stream()
.filter(s -> s.startsWith(args[1].toLowerCase()))
.toList();
}
return List.of();
}
}

View file

@ -5,7 +5,7 @@ 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.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -89,24 +89,24 @@ public class PlayerInteractListener implements Listener {
if (item == null || item.getType() != Material.STICK) return false;
if (!item.hasItemMeta()) return false;
// Reliable check: look for NBT persistent data tag instead of display name parsing
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;
var key = new org.bukkit.NamespacedKey("mdbd", "dbd_wand");
if (!meta.getPersistentDataContainer().has(key, org.bukkit.persistence.PersistentDataType.BYTE)) {
return false;
}
event.setCancelled(true);
Action action = event.getAction();
Location loc = event.getClickedBlock() != null
? event.getClickedBlock().getLocation()
: player.getLocation().getBlock().getLocation();
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());
setupCommand.setWandPos(player, 1, loc);
} 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());
setupCommand.setWandPos(player, 2, loc);
}
return true;
}

View file

@ -0,0 +1,45 @@
package dev.loki.listener;
import dev.loki.command.SetupCommand;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
/**
* Handles block-break selection for killer-spawn and survivor-spawn setup modes.
* Generator selection is handled by GeneratorSelectListener.
*/
public class SetupBlockBreakListener implements Listener {
private final SetupCommand setupCommand;
public SetupBlockBreakListener(SetupCommand setupCommand) {
this.setupCommand = setupCommand;
}
@EventHandler
public void onBlockBreak(BlockBreakEvent event) {
Player player = event.getPlayer();
boolean killerMode = setupCommand.isSelectingKillerSpawn(player.getUniqueId());
boolean survivorMode = setupCommand.isSelectingSurvivorSpawn(player.getUniqueId());
if (!killerMode && !survivorMode) return;
event.setCancelled(true);
// Center of block, standing on top
Location loc = event.getBlock().getLocation()
.add(0.5, 1.0, 0.5);
loc.setYaw(player.getLocation().getYaw());
loc.setPitch(0f);
if (killerMode) {
setupCommand.onKillerSpawnSelected(player, loc);
} else {
setupCommand.onSurvivorSpawnSelected(player, loc);
}
}
}

View file

@ -5,8 +5,6 @@ import dev.loki.core.GameSession;
import dev.loki.player.BasePlayer;
import dev.loki.player.Killer;
import dev.loki.player.Survivor;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
@ -32,52 +30,69 @@ public class RoleAssigner {
public void assignRoles(GameSession session) {
Map<UUID, BasePlayer> players = session.getPlayers();
if (players.isEmpty()) return;
if (players.isEmpty()) {
session.getPlugin().getLogger().warning("[RoleAssigner] No players in session!");
return;
}
List<UUID> uuids = new ArrayList<>(players.keySet());
UUID killerUuid = selectKiller(uuids);
Location killerSpawn = locations.getKillerSpawn();
List<Location> survivorSpawns = locations.getSurvivorSpawns();
if (killerSpawn == null) {
session.getPlugin().getLogger().warning("[RoleAssigner] killer-spawn not set! Using game world spawn.");
}
if (survivorSpawns.isEmpty()) {
session.getPlugin().getLogger().warning("[RoleAssigner] survivor-spawns not set! Using game world spawn.");
}
int spawnIndex = 0;
for (UUID uuid : uuids) {
BasePlayer newPlayer;
if (uuid.equals(killerUuid)) {
newPlayer = new Killer(uuid);
Location spawn = locations.getKillerSpawn();
if (spawn != null) newPlayer.setSpawnLocation(spawn);
if (killerSpawn != null) newPlayer.setSpawnLocation(killerSpawn);
} else {
newPlayer = new Survivor(uuid);
if (!survivorSpawns.isEmpty()) {
Location spawn = survivorSpawns.get(spawnIndex % survivorSpawns.size());
newPlayer.setSpawnLocation(spawn);
newPlayer.setSpawnLocation(survivorSpawns.get(spawnIndex % survivorSpawns.size()));
spawnIndex++;
}
}
// Actually replace the player object in session
session.replacePlayer(uuid, newPlayer);
// Announce role and teleport
Player bukkit = Bukkit.getPlayer(uuid);
if (bukkit != null && bukkit.isOnline()) {
if (newPlayer.isKiller()) {
bukkit.sendTitle("§4§lКИЛЛЕР", "§cОхоться на выживших!", 10, 60, 20);
bukkit.sendMessage(Component.text("[DBD] Ваша роль: Киллер", NamedTextColor.RED));
bukkit.showTitle(net.kyori.adventure.title.Title.title(
net.kyori.adventure.text.Component.text("КИЛЛЕР").color(net.kyori.adventure.text.format.TextColor.color(0xFF2222)),
net.kyori.adventure.text.Component.text("Охоться на выживших!").color(net.kyori.adventure.text.format.NamedTextColor.RED)
));
bukkit.sendMessage(net.kyori.adventure.text.Component.text("[DBD] Ваша роль: Киллер", net.kyori.adventure.text.format.NamedTextColor.RED));
} else {
bukkit.sendTitle("§a§lВЫЖИВШИЙ", "§eЧини генераторы и сбегай!", 10, 60, 20);
bukkit.sendMessage(Component.text("[DBD] Ваша роль: Выживший", NamedTextColor.GREEN));
bukkit.showTitle(net.kyori.adventure.title.Title.title(
net.kyori.adventure.text.Component.text("ВЫЖИВШИЙ").color(net.kyori.adventure.text.format.TextColor.color(0x00FF00)),
net.kyori.adventure.text.Component.text("Чини генераторы и сбегай!").color(net.kyori.adventure.text.format.NamedTextColor.YELLOW)
));
bukkit.sendMessage(net.kyori.adventure.text.Component.text("[DBD] Ваша роль: Выживший", net.kyori.adventure.text.format.NamedTextColor.GREEN));
}
// Teleport to game world spawn (or role spawn)
Location spawn = newPlayer.getSpawnLocation();
if (spawn != null) {
bukkit.teleport(spawn);
session.getPlugin().getLogger().info("[RoleAssigner] Teleported " + bukkit.getName() + " to " + spawn);
} else {
// Fallback: game world spawn
var gameWorld = session.getPlugin().getLobbyManager().getGameWorld();
if (gameWorld != null) {
bukkit.teleport(gameWorld.getSpawnLocation());
Location fallback = gameWorld.getSpawnLocation();
bukkit.teleport(fallback);
session.getPlugin().getLogger().info("[RoleAssigner] Teleported " + bukkit.getName() + " to game world spawn (no spawn set)");
} else {
session.getPlugin().getLogger().severe("[RoleAssigner] Game world is null! Cannot teleport " + bukkit.getName());
}
}
}