// OptimizedRocket.java
package com.yourname.rocketplugin;

import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;

import java.util.HashSet;
import java.util.Set;

/**
 * Класс, представляющий оптимизированную ракету для разрушения.
 */
public class OptimizedRocket extends Rocket {

    /**
     * Конструктор OptimizedRocket.
     *
     * @param launcher Игрок, запустивший ракету.
     * @param type     Тип ракеты.
     * @param target   Целевая локация.
     * @param plugin   Главный плагин.
     */
    public OptimizedRocket(Player launcher, RocketType type, Location target, RocketPlugin plugin) {
        super(launcher, type, target, plugin);
    }

    @Override
    protected void explode() {
        final World world = this.target.getWorld();
        if (world == null) {
            this.launcher.sendMessage("§cОшибка: Целевая локация не найдена.");
            return;
        }

        if (type.getName().equalsIgnoreCase("USSR")) {
            performUSSRExplosion(world);
        } else {
            super.explode();
        }
    }

    /**
     * Выполняет взрыв для ракеты типа "USSR" с большой областью и огнём.
     *
     * @param world Мир, в котором происходит взрыв.
     */
    private void performUSSRExplosion(World world) {
        final Location center = this.target.clone();
        final double radius = 512.0; // Радиус взрыва

        // Создаем визуальные эффекты взрыва
        world.spawnParticle(this.type.getExplosionParticle(), center, 100, radius / 100, radius / 100, radius / 100, 0.05);
        world.playSound(center, this.type.getExplosionSound(), 10.0F, 1.0F);

        // Обработка большого количества блоков по частям для оптимизации
        new BukkitRunnable() {
            private int currentX = (int) (center.getX() - radius);
            private final int startX = (int) (center.getX() - radius);
            private final int endX = (int) (center.getX() + radius);
            private final int step = 10; // Количество блоков по X для обработки за тик
            private final Set<Block> affectedBlocks = new HashSet<>();

            @Override
            public void run() {
                for (int x = currentX; x < currentX + step && x <= endX; x++) {
                    for (int y = (int) (center.getY() - radius); y <= (int) (center.getY() + radius); y++) {
                        for (int z = (int) (center.getZ() - radius); z <= (int) (center.getZ() + radius); z++) {
                            Location blockLoc = new Location(world, x, y, z);
                            if (blockLoc.distance(center) <= radius) {
                                Block block = world.getBlockAt(blockLoc);
                                if (!affectedBlocks.contains(block)) {
                                    // Устанавливаем блок в огонь
                                    block.setType(Material.FIRE, false);
                                    affectedBlocks.add(block);
                                }
                            }
                        }
                    }
                }
                currentX += step;
                // Добавляем огненные частицы
                world.spawnParticle(Particle.FLAME, center, 500, radius / 50, radius / 50, radius / 50, 0.01);
                world.spawnParticle(Particle.LAVA, center, 300, radius / 50, radius / 50, radius / 50, 0.005);

                // Проверяем завершение
                if (currentX > endX) {
                    this.cancel();
                    world.playSound(center, Sound.ENTITY_GENERIC_EXPLODE, 10.0F, 1.0F);
                    world.createExplosion(center, 0.0F, false, false); // Визуальный эффект без разрушения
                    Bukkit.broadcastMessage("§cРакета USSR взорвалась, все вокруг в огне!");
                }
            }
        }.runTaskTimer(this.plugin, 0L, 1L); // Запускаем с задержкой 0 тиков и периодом 1 тик
    }
}
// PVOBlock.java
package com.yourname.rocketplugin;

import org.bukkit.Location;
import org.bukkit.Material;

import java.util.Set;
import java.util.UUID;

/**
 * Класс, представляющий ПВО блок.
 */
public class PVOBlock {
    private final Location location;
    private final Set<UUID> excludedPlayers;
    private final PVOTypes type;

    /**
     * Конструктор PVOBlock.
     *
     * @param location         Локация блока.
     * @param excludedPlayers Множество UUID игроков, исключённых из защиты.
     * @param type             Тип ПВО.
     */
    public PVOBlock(Location location, Set<UUID> excludedPlayers, PVOTypes type) {
        this.location = location;
        this.excludedPlayers = excludedPlayers;
        this.type = type;
    }

    public Location getLocation() {
        return location;
    }

    public Set<UUID> getExcludedPlayers() {
        return excludedPlayers;
    }

    public PVOTypes getType() {
        return type;
    }

    /**
     * Возвращает материал блока ПВО в зависимости от типа.
     *
     * @return Материал блока.
     */
    public Material getMaterial() {
        switch (type) {
            case BASIC:
                return Material.BEACON;
            case ADVANCED:
                return Material.END_CRYSTAL;
            case ELITE:
                return Material.LODESTONE;
            case PREMIUM:
                return Material.CRYING_OBSIDIAN;
            case ULTIMATE:
                return Material.NETHER_STAR;
            default:
                return Material.BEACON;
        }
    }

    /**
     * Перечисление типов ПВО.
     */
    public enum PVOTypes {
        BASIC,
        ADVANCED,
        ELITE,
        PREMIUM,
        ULTIMATE
    }
}
// PVOCommand.java
package com.yourname.rocketplugin;

import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;

import java.util.Arrays;

/**
 * Класс обработки команды /pvo.
 */
public class PVOCommand implements CommandExecutor {
    private final RocketManager rocketManager;
    private final RocketPlugin plugin;

    /**
     * Конструктор PVOCommand.
     *
     * @param rocketManager Менеджер ракет и ПВО.
     * @param plugin        Главный плагин.
     */
    public PVOCommand(RocketManager rocketManager, RocketPlugin plugin) {
        this.rocketManager = rocketManager;
        this.plugin = plugin;
    }

    /**
     * Обработка команды /pvo.
     *
     * @param sender  Отправитель команды.
     * @param command Команда.
     * @param label   Ярлык команды.
     * @param args    Аргументы команды.
     * @return Результат выполнения команды.
     */
    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
        // Проверяем наличие разрешения на использование команды
        if (!sender.hasPermission("pvo.use")) {
            sender.sendMessage(ChatColor.RED + "§cУ вас нет разрешения использовать эту команду.");
            return true;
        }

        // Проверяем, что команда выполняется игроком
        if (!(sender instanceof Player)) {
            sender.sendMessage(ChatColor.RED + "§cТолько игроки могут использовать эту команду.");
            return true;
        }

        Player player = (Player) sender;

        // Проверяем наличие подкоманды
        if (args.length == 0) {
            player.sendMessage(ChatColor.RED + "§cИспользование: /pvo <give|exclude|remove>");
            return true;
        }

        String subcommand = args[0].toLowerCase();

        switch (subcommand) {
            case "give":
                handleGive(player, args);
                break;
            case "exclude":
                handleExclude(player, args);
                break;
            case "remove":
                handleRemove(player, args);
                break;
            default:
                player.sendMessage(ChatColor.RED + "§cНеизвестная подкоманда. Используйте /pvo <give|exclude|remove>");
        }

        return true;
    }

    /**
     * Обработка подкоманды give.
     *
     * @param player Игрок, использующий команду.
     * @param args   Аргументы команды.
     */
    private void handleGive(Player player, String[] args) {
        // Проверяем наличие разрешения на выдачу ПВО блоков
        if (!player.hasPermission("pvo.give")) {
            player.sendMessage(ChatColor.RED + "§cУ вас нет разрешения выдавать ПВО блоки.");
            return;
        }

        // Проверяем наличие аргумента типа
        if (args.length < 2) {
            player.sendMessage(ChatColor.RED + "§cИспользование: /pvo give <type>");
            player.sendMessage(ChatColor.YELLOW + "§eДоступные типы ПВО: BASIC, ADVANCED, ELITE, PREMIUM, ULTIMATE");
            return;
        }

        String typeStr = args[1].toUpperCase();
        PVOBlock.PVOTypes type;
        try {
            type = PVOBlock.PVOTypes.valueOf(typeStr);
        } catch (IllegalArgumentException e) {
            player.sendMessage(ChatColor.RED + "§cНеверный тип ПВО. Доступные типы: BASIC, ADVANCED, ELITE, PREMIUM, ULTIMATE");
            return;
        }

        // Определяем материал в зависимости от типа ПВО
        Material material;
        switch (type) {
            case BASIC:
                material = Material.BEACON;
                break;
            case ADVANCED:
                material = Material.END_CRYSTAL;
                break;
            case ELITE:
                material = Material.LODESTONE;
                break;
            case PREMIUM:
                material = Material.CRYING_OBSIDIAN;
                break;
            case ULTIMATE:
                material = Material.NETHER_STAR;
                break;
            default:
                material = Material.BEACON;
        }

        // Создаём ItemStack соответствующего типа ПВО
        ItemStack pvoItem = new ItemStack(material);
        ItemMeta meta = pvoItem.getItemMeta();
        if (meta != null) {
            meta.setDisplayName(ChatColor.GOLD + "§lПВО Блок (" + type.name() + ")");
            meta.setLore(Arrays.asList("§7Тип ПВО: " + type.name()));
            pvoItem.setItemMeta(meta);
        }

        // Добавляем предмет в инвентарь игрока
        player.getInventory().addItem(pvoItem);
        player.sendMessage(ChatColor.GREEN + "§aВы получили ПВО блок (" + type.name() + "). Установите его в мире P_Drilla.");
    }

    /**
     * Обработка подкоманды exclude.
     *
     * @param player Игрок, использующий команду.
     * @param args   Аргументы команды.
     */
    private void handleExclude(Player player, String[] args) {
        if (args.length < 3) {
            player.sendMessage(ChatColor.RED + "§cИспользование: /pvo exclude <add|remove> <player>");
            return;
        }

        String action = args[1].toLowerCase();
        String targetName = args[2];
        Player targetPlayer = plugin.getServer().getPlayerExact(targetName);

        if (targetPlayer == null) {
            player.sendMessage(ChatColor.RED + "§cИгрок не найден или не онлайн.");
            return;
        }

        switch (action) {
            case "add":
                rocketManager.getPvoManager().addExcludedPlayer(player, targetPlayer);
                player.sendMessage(ChatColor.GREEN + "§aИгрок " + targetPlayer.getName() + " успешно добавлен в список исключённых.");
                break;
            case "remove":
                rocketManager.getPvoManager().removeExcludedPlayer(player, targetPlayer);
                player.sendMessage(ChatColor.GREEN + "§aИгрок " + targetPlayer.getName() + " успешно удалён из списка исключённых.");
                break;
            default:
                player.sendMessage(ChatColor.RED + "§cНеизвестное действие. Используйте add или remove.");
        }
    }

    /**
     * Обработка подкоманды remove.
     *
     * @param player Игрок, использующий команду.
     * @param args   Аргументы команды.
     */
    private void handleRemove(Player player, String[] args) {
        // Эта команда не используется напрямую, так как remove покрыто в handleExclude
        player.sendMessage(ChatColor.RED + "§cИспользуйте /pvo exclude <add|remove> <player> для управления исключениями.");
    }
}
// PVOListener.java
package com.yourname.rocketplugin;

import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.ExplosionPrimeEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.BlockBreakEvent;

import java.util.List;

/**
 * Класс слушателя событий, связанных с ПВО.
 */
public class PVOListener implements Listener {
    private final RocketManager rocketManager;
    private final RocketPlugin plugin;

    /**
     * Конструктор PVOListener.
     *
     * @param rocketManager Менеджер ракет и ПВО.
     * @param plugin        Главный плагин.
     */
    public PVOListener(RocketManager rocketManager, RocketPlugin plugin) {
        this.rocketManager = rocketManager;
        this.plugin = plugin;
    }

    /**
     * Событие размещения блока.
     *
     * @param event Событие.
     */
    @EventHandler
    public void onBlockPlace(BlockPlaceEvent event) {
        Player player = event.getPlayer();
        Location loc = event.getBlock().getLocation();

        // Проверяем, является ли размещённый блок типом ПВО
        for (PVOBlock.PVOTypes type : PVOBlock.PVOTypes.values()) {
            Material requiredMaterial;
            switch (type) {
                case BASIC:
                    requiredMaterial = Material.BEACON;
                    break;
                case ADVANCED:
                    requiredMaterial = Material.END_CRYSTAL;
                    break;
                case ELITE:
                    requiredMaterial = Material.LODESTONE;
                    break;
                case PREMIUM:
                    requiredMaterial = Material.CRYING_OBSIDIAN;
                    break;
                case ULTIMATE:
                    requiredMaterial = Material.NETHER_STAR;
                    break;
                default:
                    requiredMaterial = Material.BEACON;
            }

            if (event.getBlock().getType().equals(requiredMaterial)) {
                boolean added = rocketManager.getPvoManager().addPVOBlock(player, loc, type);
                if (!added) {
                    event.setCancelled(true);
                } else {
                    player.sendMessage(ChatColor.GREEN + "§aПВО блок (" + type.name() + ") установлен.");
                }
                return; // Выход после обнаружения нужного типа
            }
        }
    }

    /**
     * Событие разрушения блока.
     *
     * @param event Событие.
     */
    @EventHandler
    public void onBlockBreak(BlockBreakEvent event) {
        Player player = event.getPlayer();
        Location loc = event.getBlock().getLocation();

        // Проверяем, является ли разрушённый блок ПВО блоком
        if (rocketManager.getPvoManager().removePVOBlock(player, loc)) {
            player.sendMessage(ChatColor.GREEN + "§aПВО блок удалён.");
        }
    }

    /**
     * Событие взрыва для обработки ПВО.
     *
     * @param event Событие.
     */
    @EventHandler
    public void onExplosionPrime(ExplosionPrimeEvent event) {
        World world = event.getEntity().getWorld();
        if (!world.getName().equalsIgnoreCase("P_Drilla")) {
            event.setCancelled(true);
            if (event.getEntity() instanceof Player player) {
                player.sendMessage(ChatColor.RED + "§cВзрывы вне мира запрещены!");
            }
            return;
        }

        Location explosionLocation = event.getEntity().getLocation();
        double radius = 10.0; // Радиус взрыва

        // Получаем ПВО блоки в радиусе взрыва
        List<PVOBlock> nearbyPVO = rocketManager.getPvoManager().getPVOBlocksInRadius(explosionLocation, radius);

        if (!nearbyPVO.isEmpty()) {
            // Применяем логику защиты
            for (PVOBlock block : nearbyPVO) {
                Player owner = plugin.getServer().getPlayer(block.getLocation().getWorld().getName()); // Получаем владельца по миру (здесь может потребоваться доработка)
                if (owner != null) {
                    // Проверяем, является ли цель владельцем или исключённым игроком
                    // Точную логику реализуйте по своим требованиям
                }
            }
        }
    }

    /**
     * Событие нанесения вреда игроку.
     *
     * @param event Событие.
     */
    @EventHandler
    public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
        if (!(event.getEntity() instanceof Player damaged)) return;

        Location damageLocation = damaged.getLocation();
        double radius = 10.0; // Радиус действия ПВО

        // Получаем ПВО блоки в радиусе действия от повреждения
        List<PVOBlock> nearbyPVO = rocketManager.getPvoManager().getPVOBlocksInRadius(damageLocation, radius);

        if (!nearbyPVO.isEmpty()) {
            // Проверяем, имеет ли ПВО блока право защищать повреждённого
            for (PVOBlock block : nearbyPVO) {
                Player owner = plugin.getServer().getPlayer(block.getLocation().getWorld().getName()); // Получаем владельца по миру
                if (owner != null) {
                    if (block.getExcludedPlayers().contains(damaged.getUniqueId())) {
                        // Игрок в списке исключений, защита не применяется
                        continue;
                    }

                    if (!damaged.equals(owner)) {
                        // Отменяем урон, если повреждённый не владелец ПВО
                        event.setCancelled(true);
                        damaged.sendMessage(ChatColor.YELLOW + "§eВаш ПВО блок защитил вас от урона!");
                        break;
                    }
                }
            }
        }
    }
}
// PVOManager.java
package com.yourname.rocketplugin;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;

import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * Класс управления ПВО (Противовоздушной Обороны).
 */
public class PVOManager {
    private final RocketPlugin plugin;
    private StatsManager statsManager;
    private final File pvoFile;
    private FileConfiguration pvoConfig;
    public final Map<UUID, List<PVOBlock>> playerPVOBlocks; // Список ПВО блоков для каждого игрока

    /**
     * Конструктор PVOManager.
     *
     * @param plugin Главный плагин.
     */
    public PVOManager(RocketPlugin plugin) {
        this.plugin = plugin;
        this.pvoFile = new File(plugin.getDataFolder(), "pvo.yml");
        if (!this.pvoFile.exists()) {
            try {
                plugin.saveResource("pvo.yml", false);
            } catch (IllegalArgumentException e) {
                // Файл pvo.yml не найден в ресурсах, создаём пустой
                this.pvoConfig = new YamlConfiguration();
                try {
                    this.pvoConfig.save(this.pvoFile);
                } catch (IOException ex) {
                    plugin.getLogger().severe("§cНе удалось создать pvo.yml:");
                    ex.printStackTrace();
                }
            }
        }

        this.pvoConfig = YamlConfiguration.loadConfiguration(this.pvoFile);
        this.playerPVOBlocks = new HashMap<>();
        loadPVOBlocks();
    }

    /**
     * Устанавливает ссылку на StatsManager.
     *
     * @param statsManager Экземпляр StatsManager.
     */
    public void setStatsManager(StatsManager statsManager) {
        this.statsManager = statsManager;
    }

    /**
     * Загружает ПВО блоки из pvo.yml.
     */
    private void loadPVOBlocks() {
        ConfigurationSection pvoSection = pvoConfig.getConfigurationSection("pvo");
        if (pvoSection == null) return;

        for (String playerUUID : pvoSection.getKeys(false)) {
            UUID uuid = UUID.fromString(playerUUID);
            List<PVOBlock> blocks = new ArrayList<>();
            ConfigurationSection playerSection = pvoSection.getConfigurationSection(playerUUID);
            if (playerSection == null) continue;

            for (String blockKey : playerSection.getKeys(false)) {
                ConfigurationSection blockSection = playerSection.getConfigurationSection(blockKey);
                if (blockSection == null) continue;

                String worldName = blockSection.getString("world");
                double x = blockSection.getDouble("x");
                double y = blockSection.getDouble("y");
                double z = blockSection.getDouble("z");
                String typeStr = blockSection.getString("type", "BASIC");
                List<String> excludedList = blockSection.getStringList("excluded");
                Set<UUID> excluded = new HashSet<>();
                for (String excludedUUID : excludedList) {
                    excluded.add(UUID.fromString(excludedUUID));
                }

                Location loc = new Location(Bukkit.getWorld(worldName), x, y, z);
                PVOBlock.PVOTypes type;
                try {
                    type = PVOBlock.PVOTypes.valueOf(typeStr.toUpperCase());
                } catch (IllegalArgumentException e) {
                    type = PVOBlock.PVOTypes.BASIC;
                }
                blocks.add(new PVOBlock(loc, excluded, type));
            }

            playerPVOBlocks.put(uuid, blocks);
        }
    }

    /**
     * Сохраняет ПВО блоки в pvo.yml.
     */
    public void savePVOBlocks() {
        pvoConfig.set("pvo", null); // Очищаем секцию
        for (Map.Entry<UUID, List<PVOBlock>> entry : playerPVOBlocks.entrySet()) {
            UUID owner = entry.getKey();
            List<PVOBlock> blocks = entry.getValue();
            for (int i = 0; i < blocks.size(); i++) {
                PVOBlock block = blocks.get(i);
                String path = "pvo." + owner.toString() + ".block" + i;
                pvoConfig.set(path + ".world", block.getLocation().getWorld().getName());
                pvoConfig.set(path + ".x", block.getLocation().getX());
                pvoConfig.set(path + ".y", block.getLocation().getY());
                pvoConfig.set(path + ".z", block.getLocation().getZ());
                pvoConfig.set(path + ".type", block.getType().name());

                List<String> excludedUUIDs = new ArrayList<>();
                for (UUID excluded : block.getExcludedPlayers()) {
                    excludedUUIDs.add(excluded.toString());
                }
                pvoConfig.set(path + ".excluded", excludedUUIDs);
            }
        }

        try {
            pvoConfig.save(pvoFile);
        } catch (IOException e) {
            plugin.getLogger().severe("§cНе удалось сохранить pvo.yml:");
            e.printStackTrace();
        }
    }

    /**
     * Добавляет ПВО блок для игрока.
     *
     * @param player Игрок.
     * @param block  Блок.
     * @param type   Тип ПВО.
     * @return true, если блок успешно добавлен.
     */
    public boolean addPVOBlock(Player player, Location block, PVOBlock.PVOTypes type) {
        UUID playerUUID = player.getUniqueId();
        List<PVOBlock> blocks = playerPVOBlocks.getOrDefault(playerUUID, new ArrayList<>());

        if (blocks.size() >= 5) {
            player.sendMessage("§cВы достигли максимального количества ПВО блоков (5).");
            return false;
        }

        // Проверяем, что блок имеет нужный тип
        PVOBlock tempBlock = new PVOBlock(block, new HashSet<>(), type);
        if (!block.getBlock().getType().equals(tempBlock.getMaterial())) {
            player.sendMessage("§cЭтот тип ПВО должен быть размещён как " + tempBlock.getMaterial().name() + ".");
            return false;
        }

        // Проверяем, что блок ещё не зарегистрирован
        for (PVOBlock existingBlock : blocks) {
            if (existingBlock.getLocation().equals(block)) {
                player.sendMessage("§cЭтот блок уже зарегистрирован как ПВО.");
                return false;
            }
        }

        PVOBlock pvoBlock = new PVOBlock(block, new HashSet<>(), type);
        blocks.add(pvoBlock);
        playerPVOBlocks.put(playerUUID, blocks);
        savePVOBlocks();
        player.sendMessage("§aПВО блок (" + type.name() + ") успешно добавлен.");
        return true;
    }

    /**
     * Удаляет ПВО блок для игрока.
     *
     * @param player Игрок.
     * @param block  Блок.
     * @return true, если блок успешно удалён.
     */
    public boolean removePVOBlock(Player player, Location block) {
        UUID playerUUID = player.getUniqueId();
        List<PVOBlock> blocks = playerPVOBlocks.getOrDefault(playerUUID, new ArrayList<>());

        PVOBlock target = null;
        for (PVOBlock pvoBlock : blocks) {
            if (pvoBlock.getLocation().equals(block)) {
                target = pvoBlock;
                break;
            }
        }

        if (target != null) {
            blocks.remove(target);
            playerPVOBlocks.put(playerUUID, blocks);
            savePVOBlocks();
            player.sendMessage("§aПВО блок успешно удалён.");
            return true;
        } else {
            player.sendMessage("§cЭтот блок не зарегистрирован как ПВО.");
            return false;
        }
    }

    /**
     * Добавляет игрока в список исключений для ПВО блоков владельца.
     *
     * @param owner    Владелец ПВО.
     * @param excluded Игрок для исключения.
     */
    public void addExcludedPlayer(Player owner, Player excluded) {
        UUID ownerUUID = owner.getUniqueId();
        UUID excludedUUID = excluded.getUniqueId();
        List<PVOBlock> blocks = playerPVOBlocks.getOrDefault(ownerUUID, new ArrayList<>());

        for (PVOBlock block : blocks) {
            block.getExcludedPlayers().add(excludedUUID);
        }

        savePVOBlocks();
        owner.sendMessage("§aИгрок " + excluded.getName() + " добавлен в список исключений ПВО.");
        excluded.sendMessage("§aВас добавили в список исключений ПВО игрока " + owner.getName() + ".");
    }

    /**
     * Удаляет игрока из списка исключений для ПВО блоков владельца.
     *
     * @param owner    Владелец ПВО.
     * @param excluded Игрок для удаления из исключений.
     */
    public void removeExcludedPlayer(Player owner, Player excluded) {
        UUID ownerUUID = owner.getUniqueId();
        UUID excludedUUID = excluded.getUniqueId();
        List<PVOBlock> blocks = playerPVOBlocks.getOrDefault(ownerUUID, new ArrayList<>());

        for (PVOBlock block : blocks) {
            block.getExcludedPlayers().remove(excludedUUID);
        }

        savePVOBlocks();
        owner.sendMessage("§aИгрок " + excluded.getName() + " удалён из списка исключений ПВО.");
        excluded.sendMessage("§aВас удалили из списка исключений ПВО игрока " + owner.getName() + ".");
    }

    /**
     * Получает список ПВО блоков в радиусе действия от локации.
     *
     * @param location Локация взрыва.
     * @param radius   Радиус действия.
     * @return Список ПВО блоков.
     */
    public List<PVOBlock> getPVOBlocksInRadius(Location location, double radius) {
        List<PVOBlock> nearbyBlocks = new ArrayList<>();
        for (List<PVOBlock> blocks : playerPVOBlocks.values()) {
            for (PVOBlock block : blocks) {
                if (block.getLocation().getWorld().equals(location.getWorld()) &&
                        block.getLocation().distance(location) <= radius) {
                    nearbyBlocks.add(block);
                }
            }
        }
        return nearbyBlocks;
    }
}
// Rocket.java
package com.yourname.rocketplugin;

import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;

import java.util.Collection;

/**
 * Класс, представляющий ракету.
 */
public class Rocket {
    protected final Player launcher;
    protected final RocketType type;
    protected final Location target;
    protected final RocketPlugin plugin;
    protected Location currentLocation;
    protected double speed = 1.0;

    /**
     * Конструктор ракеты.
     *
     * @param launcher Игрок, запустивший ракету.
     * @param type     Тип ракеты.
     * @param target   Целевая локация.
     * @param plugin   Главный плагин.
     */
    public Rocket(Player launcher, RocketType type, Location target, RocketPlugin plugin) {
        this.launcher = launcher;
        this.type = type;
        this.target = target;
        this.plugin = plugin;
        this.currentLocation = launcher.getLocation().clone();
    }

    /**
     * Запускает ракету.
     */
    public void launch() {
        final World world = this.launcher.getWorld();
        if (world == null) {
            this.launcher.sendMessage("§cОшибка: Мир не найден.");
            return;
        }

        world.spawnParticle(this.type.getLaunchParticle(), this.currentLocation, 20, 0.5, 0.5, 0.5, 0.05);
        world.playSound(this.currentLocation, this.type.getLaunchSound(), 1.0F, 1.0F);
        new BukkitRunnable() {
            @Override
            public void run() {
                Vector direction = target.clone().subtract(currentLocation).toVector();
                double distance = direction.length();
                if (distance < type.getRange()) {
                    explode();
                    this.cancel();
                } else {
                    direction = direction.normalize().multiply(speed);
                    currentLocation.add(direction);
                    world.spawnParticle(type.getLaunchParticle(), currentLocation, 5, 0.1, 0.1, 0.1, 0.02);
                }
            }
        }.runTaskTimer(this.plugin, 0L, 1L);
    }

    /**
     * Вызывает взрыв ракеты.
     */
    protected void explode() {
        final World world = this.target.getWorld();
        if (world == null) {
            this.launcher.sendMessage("§cОшибка: Целевая локация не найдена.");
            return;
        }

        if (type.isOptimized()) {
            optimizedExplode(world);
        } else {
            standardExplode(world);
        }
    }

    /**
     * Стандартный взрыв ракеты.
     *
     * @param world Мир, в котором происходит взрыв.
     */
    protected void standardExplode(World world) {
        world.createExplosion(this.target, (float) type.getPower(), false, true);
        world.spawnParticle(this.type.getExplosionParticle(), this.target, 100, 1.0, 1.0, 1.0, 0.1);
        world.playSound(this.target, this.type.getExplosionSound(), 1.0F, 1.0F);

        if (type.getName().equalsIgnoreCase("SUPER_NUCLEAR") ||
                type.getName().equalsIgnoreCase("MEGA_NUCLEAR") ||
                type.getName().equalsIgnoreCase("EXTREME_NUCLEAR") ||
                type.getName().equalsIgnoreCase("ULTRA_NUCLEAR") ||
                type.getName().equalsIgnoreCase("USSR")) {

            double effectRadius = 20.0;
            Collection<Entity> entities = world.getNearbyEntities(this.target, effectRadius, effectRadius, effectRadius);

            for (Entity entity : entities) {
                if (entity instanceof Player player) {
                    player.addPotionEffect(new PotionEffect(PotionEffectType.CONFUSION, 200, 1));
                    player.addPotionEffect(new PotionEffect(PotionEffectType.POISON, 200, 1));
                }
            }

            new BukkitRunnable() {
                private int ticks = 0;
                private final int maxTicks = 100;

                @Override
                public void run() {
                    if (ticks >= maxTicks) {
                        this.cancel();
                    } else {
                        world.spawnParticle(Particle.EXPLOSION_HUGE, target, 50, 2.0, 2.0, 2.0, 0.05);
                        world.spawnParticle(Particle.LAVA, target, 100, 3.0, 3.0, 3.0, 0.02);
                        world.spawnParticle(Particle.FIREWORKS_SPARK, target, 100, 4.0, 4.0, 4.0, 0.1);
                        world.spawnParticle(Particle.END_ROD, target, 50, 2.0, 2.0, 2.0, 0.05);
                        world.playSound(target, Sound.ENTITY_GENERIC_EXPLODE, 1.0F, 1.0F);
                        ticks++;
                    }
                }
            }.runTaskTimer(this.plugin, 0L, 1L);
        }
    }

    /**
     * Оптимизированный взрыв ракеты для снижения нагрузки на сервер.
     *
     * @param world Мир, в котором происходит взрыв.
     */
    protected void optimizedExplode(World world) {
        // Минимизация ущерба и нагрузки
        world.createExplosion(this.target, (float) type.getPower(), false, true); // Разрушает блоки
        world.spawnParticle(this.type.getExplosionParticle(), this.target, 50, 0.5, 0.5, 0.5, 0.02);
        world.playSound(this.target, this.type.getExplosionSound(), 1.0F, 1.0F);

        double effectRadius = type.getRange() / 2; // Настройка радиуса воздействия
        Collection<Entity> entities = world.getNearbyEntities(this.target, effectRadius, effectRadius, effectRadius);

        for (Entity entity : entities) {
            if (entity instanceof Player player) {
                player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 100, 1));
            }
        }

        // Дополнительные оптимизированные эффекты
        new BukkitRunnable() {
            private int ticks = 0;
            private final int maxTicks = 50;

            @Override
            public void run() {
                if (ticks >= maxTicks) {
                    this.cancel();
                } else {
                    world.spawnParticle(Particle.SMOKE_NORMAL, target, 30, 1.0, 1.0, 1.0, 0.01);
                    world.spawnParticle(Particle.FLAME, target, 50, 1.0, 1.0, 1.0, 0.02);
                    world.playSound(target, Sound.ENTITY_GENERIC_EXPLODE, 1.0F, 1.0F);
                    ticks++;
                }
            }
        }.runTaskTimer(this.plugin, 0L, 1L);
    }
}
// RocketCommand.java
package com.yourname.rocketplugin;

import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.inventory.ItemStack;

/**
 * Класс обработки команды /rocket.
 */
public class RocketCommand implements CommandExecutor {
    private final RocketManager rocketManager;
    private final StatsManager statsManager;
    private final RocketPlugin plugin;

    /**
     * Конструктор RocketCommand.
     *
     * @param rocketManager Менеджер ракет.
     * @param statsManager  Менеджер статистики.
     * @param plugin        Главный плагин.
     */
    public RocketCommand(RocketManager rocketManager, StatsManager statsManager, RocketPlugin plugin) {
        this.rocketManager = rocketManager;
        this.statsManager = statsManager;
        this.plugin = plugin;
    }

    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
        if (!sender.hasPermission("rocketplugin.use")) {
            sender.sendMessage(ChatColor.RED + "§cУ вас нет разрешения использовать эту команду.");
            return true;
        }

        if (args.length == 0) {
            sender.sendMessage(ChatColor.RED + "§cИспользование: /rocket <launch|give|stats|reload|craft> [параметры]");
            return true;
        }

        String subcommand = args[0].toLowerCase();
        switch (subcommand) {
            case "launch":
                handleLaunch(sender, args);
                break;
            case "give":
                handleGive(sender, args);
                break;
            case "stats":
                handleStats(sender, args);
                break;
            case "reload":
                handleReload(sender, args);
                break;
            case "craft":
                handleCraft(sender, args);
                break;
            default:
                sender.sendMessage(ChatColor.RED + "§cНеизвестная подкоманда. Использование: /rocket <launch|give|stats|reload|craft> [параметры]");
        }

        return true;
    }

    /**
     * Обработка подкоманды launch.
     *
     * @param sender Отправитель команды.
     * @param args   Аргументы команды.
     */
    private void handleLaunch(CommandSender sender, String[] args) {
        if (!(sender instanceof Player)) {
            sender.sendMessage(ChatColor.RED + "§cТолько игроки могут запускать ракеты.");
            return;
        }

        Player player = (Player) sender;

        if (args.length < 5) {
            player.sendMessage(ChatColor.RED + "§cИспользование: /rocket launch <type> <x> <y> <z> [delay]");
            player.sendMessage(ChatColor.YELLOW + "§eПримечание: delay - опциональный параметр (1-30 секунд)");
            return;
        }

        String typeName = args[1].toUpperCase();
        RocketType type = rocketManager.getRocketType(typeName);

        if (type == null) {
            player.sendMessage(ChatColor.RED + "§cНеверный тип ракеты. Используйте /rocket для просмотра доступных типов.");
            return;
        }

        double x, y, z;
        try {
            x = Double.parseDouble(args[2]);
            y = Double.parseDouble(args[3]);
            z = Double.parseDouble(args[4]);
        } catch (NumberFormatException e) {
            player.sendMessage(ChatColor.RED + "§cКоординаты должны быть действительными числами.");
            return;
        }

        Location target = new Location(player.getWorld(), x, y, z);

        int delay = 0;
        if (args.length >= 6) {
            try {
                delay = Integer.parseInt(args[5]);
                if (delay < 1 || delay > 30) {
                    player.sendMessage(ChatColor.RED + "§cЗадержка должна быть между 1 и 30 секундами.");
                    return;
                }
            } catch (NumberFormatException e) {
                player.sendMessage(ChatColor.RED + "§cЗадержка должна быть целым числом.");
                return;
            }
        }

        rocketManager.launchRocket(player, type, target, delay);
    }

    /**
     * Обработка подкоманды give.
     *
     * @param sender Отправитель команды.
     * @param args   Аргументы команды.
     */
    private void handleGive(CommandSender sender, String[] args) {
        if (!sender.hasPermission("rocketplugin.give")) {
            sender.sendMessage(ChatColor.RED + "§cУ вас нет разрешения выдавать ракеты.");
            return;
        }

        if (args.length < 4) {
            sender.sendMessage(ChatColor.RED + "§cИспользование: /rocket give <player> <type> <amount>");
            return;
        }

        String targetName = args[1];
        Player targetPlayer = Bukkit.getPlayerExact(targetName);
        if (targetPlayer == null) {
            sender.sendMessage(ChatColor.RED + "§cИгрок не найден или не онлайн.");
            return;
        }

        String typeName = args[2].toUpperCase();
        RocketType type = rocketManager.getRocketType(typeName);
        if (type == null) {
            sender.sendMessage(ChatColor.RED + "§cНеверный тип ракеты. Используйте /rocket для просмотра доступных типов.");
            return;
        }

        int amount;
        try {
            amount = Integer.parseInt(args[3]);
            if (amount <= 0) {
                throw new NumberFormatException();
            }
        } catch (NumberFormatException e) {
            sender.sendMessage(ChatColor.RED + "§cКоличество должно быть положительным целым числом.");
            return;
        }

        // Добавляем ракеты у получателя
        statsManager.addRockets(targetPlayer, type, amount);
        sender.sendMessage(ChatColor.GREEN + "§aВыдали " + amount + " ракет типа " + type.getName() + " игроку " + targetPlayer.getName() + ".");
        targetPlayer.sendMessage(ChatColor.GREEN + "§aВам выдали " + amount + " ракет типа " + type.getName() + " от " + sender.getName() + ".");
    }

    /**
     * Обработка подкоманды stats.
     *
     * @param sender Отправитель команды.
     * @param args   Аргументы команды.
     */
    private void handleStats(CommandSender sender, String[] args) {
        if (args.length < 2) {
            if (sender instanceof Player player) {
                sender.sendMessage(statsManager.getStats(player));
            } else {
                sender.sendMessage(ChatColor.RED + "§cКонсоль не имеет статистики.");
            }
            return;
        }

        String targetName = args[1];
        Player targetPlayer = Bukkit.getPlayerExact(targetName);
        if (targetPlayer == null) {
            sender.sendMessage(ChatColor.RED + "§cИгрок не найден или не онлайн.");
            return;
        }

        sender.sendMessage(statsManager.getStats(targetPlayer));
    }

    /**
     * Обработка подкоманды reload.
     *
     * @param sender Отправитель команды.
     * @param args   Аргументы команды.
     */
    private void handleReload(CommandSender sender, String[] args) {
        if (!sender.hasPermission("rocketplugin.reload")) {
            sender.sendMessage(ChatColor.RED + "§cУ вас нет разрешения перезагружать конфигурацию.");
            return;
        }

        plugin.reloadConfig();
        rocketManager.loadRocketTypes(); // Перезагружаем типы ракет
        sender.sendMessage(ChatColor.GREEN + "§aКонфигурация плагина успешно перезагружена.");
    }

    /**
     * Обработка подкоманды craft.
     *
     * @param sender Отправитель команды.
     * @param args   Аргументы команды.
     */
    private void handleCraft(CommandSender sender, String[] args) {
        if (!(sender instanceof Player)) {
            sender.sendMessage(ChatColor.RED + "§cТолько игроки могут использовать эту команду.");
            return;
        }

        Player player = (Player) sender;

        if (args.length < 2) {
            player.sendMessage(ChatColor.RED + "§cИспользование: /rocket craft <type>");
            return;
        }

        String typeName = args[1].toUpperCase();
        RocketType type = rocketManager.getRocketType(typeName);

        if (type == null) {
            player.sendMessage(ChatColor.RED + "§cНеверный тип ракеты. Используйте /rocket для просмотра доступных типов.");
            return;
        }

        // Получаем рецепт из конфигурации
        FileConfiguration config = plugin.getConfig();
        ConfigurationSection recipeSection = config.getConfigurationSection("craftingRecipes." + type.getName() + ".ingredients");
        if (recipeSection == null) {
            player.sendMessage(ChatColor.RED + "§cРецепт для этой ракеты не найден.");
            return;
        }

        // Проверяем наличие ингредиентов
        boolean hasAll = true;
        for (String materialStr : recipeSection.getKeys(false)) {
            Material material;
            try {
                material = Material.valueOf(materialStr);
            } catch (IllegalArgumentException e) {
                player.sendMessage(ChatColor.RED + "§cНеверный материал в рецепте: " + materialStr);
                hasAll = false;
                break;
            }
            int required = recipeSection.getInt(materialStr);
            int available = player.getInventory().all(material).values().stream().mapToInt(ItemStack::getAmount).sum();
            if (available < required) {
                player.sendMessage(ChatColor.RED + "§cУ вас недостаточно " + material.name() + " для производства ракеты.");
                hasAll = false;
                break;
            }
        }

        if (!hasAll) return;

        // Списываем ингредиенты
        for (String materialStr : recipeSection.getKeys(false)) {
            Material material = Material.valueOf(materialStr);
            int required = recipeSection.getInt(materialStr);
            int removed = 0;
            for (ItemStack item : player.getInventory().all(material).values()) {
                if (removed >= required) break;
                int toRemove = Math.min(item.getAmount(), required - removed);
                ItemStack toBeRemoved = new ItemStack(material, toRemove);
                player.getInventory().removeItem(toBeRemoved);
                removed += toRemove;
            }
        }

        // Добавляем ракету в инвентарь (увеличиваем статистику)
        statsManager.addRockets(player, type, 1);
        player.sendMessage(ChatColor.GREEN + "§aВы успешно произвели ракету типа " + type.getName() + ".");
    }
}
// RocketCraftListener.java
package com.yourname.rocketplugin;

import org.bukkit.event.Listener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.inventory.Inventory;

/**
 * Класс слушателя для RocketCraft (может быть расширен в будущем).
 */
public class RocketCraftListener implements Listener {
    private final RocketPlugin plugin;

    /**
     * Конструктор RocketCraftListener.
     *
     * @param plugin Главный плагин.
     */
    public RocketCraftListener(RocketPlugin plugin) {
        this.plugin = plugin;
    }

    /**
     * Обработчик закрытия инвентаря.
     *
     * @param event Событие закрытия инвентаря.
     */
    @EventHandler
    public void onInventoryClose(InventoryCloseEvent event) {
        Inventory closed = event.getInventory();
        // Метод getTitle() больше не поддерживается. Нужно использовать getView().getTitle()
        if (event.getView().getTitle().equals("§6§lРынок Ракет")) {
            // Можно добавить дополнительные действия при закрытии рынка, если необходимо
        }
    }
}
// RocketListener.java
package com.yourname.rocketplugin;

import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.Location;

import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * Класс слушателя событий взрыва и ПВО.
 */
public class RocketListener implements Listener {
    private final RocketManager rocketManager;
    private final RocketPlugin plugin;

    /**
     * Конструктор RocketListener.
     *
     * @param rocketManager Менеджер ракет и ПВО.
     * @param plugin        Главный плагин.
     */
    public RocketListener(RocketManager rocketManager, RocketPlugin plugin) {
        this.rocketManager = rocketManager;
        this.plugin = plugin;
    }

    /**
     * Событие взрыва сущности.
     *
     * @param event Событие.
     */
    @EventHandler
    public void onEntityExplode(EntityExplodeEvent event) {
        World world = event.getEntity().getWorld();
        if (!world.getName().equalsIgnoreCase("P_Drilla")) {
            event.setCancelled(true);
            return;
        }

        Location explosionLocation = event.getLocation();
        double radius = 10.0; // Радиус воздействия ПВО

        // Получаем ПВО блоки в радиусе взрыва
        List<PVOBlock> nearbyPVO = rocketManager.getPvoManager().getPVOBlocksInRadius(explosionLocation, radius);

        if (!nearbyPVO.isEmpty()) {
            for (PVOBlock block : nearbyPVO) {
                Player owner = null;
                for (Map.Entry<UUID, List<PVOBlock>> entry : rocketManager.getPvoManager().playerPVOBlocks.entrySet()) {
                    if (entry.getValue().contains(block)) {
                        owner = Bukkit.getPlayer(entry.getKey());
                        break;
                    }
                }

                if (owner != null) {
                    List<Player> affectedPlayers = world.getPlayers();
                    for (Player p : affectedPlayers) {
                        if (!p.equals(owner) && !block.getExcludedPlayers().contains(p.getUniqueId())) {
                            // Не допускаем повреждение игрока, вне исключений
                            event.setCancelled(true);
                            p.sendMessage(ChatColor.RED + "§cВаш ПВО блок предотвратил взрыв!");
                        }
                    }
                }
            }
        }
    }

    /**
     * Событие нанесения урона игроку.
     *
     * @param event Событие.
     */
    @EventHandler
    public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
        if (!(event.getEntity() instanceof Player damaged)) return;

        Location damageLocation = damaged.getLocation();
        double radius = 10.0; // Радиус действия ПВО

        // Получаем ПВО блоки в радиусе действия от повреждения
        List<PVOBlock> nearbyPVO = rocketManager.getPvoManager().getPVOBlocksInRadius(damageLocation, radius);

        if (!nearbyPVO.isEmpty()) {
            for (PVOBlock block : nearbyPVO) {
                Player owner = null;
                for (Map.Entry<UUID, List<PVOBlock>> entry : rocketManager.getPvoManager().playerPVOBlocks.entrySet()) {
                    if (entry.getValue().contains(block)) {
                        owner = Bukkit.getPlayer(entry.getKey());
                        break;
                    }
                }

                if (owner != null) {
                    if (block.getExcludedPlayers().contains(damaged.getUniqueId())) {
                        // Игрок в списке исключений, защита не применяется
                        continue;
                    }

                    if (!damaged.equals(owner)) {
                        // Отменяем урон, если повреждённый не владелец ПВО
                        event.setCancelled(true);
                        damaged.sendMessage(ChatColor.YELLOW + "§eВаш ПВО блок защитил вас от урона!");
                        break;
                    }
                }
            }
        }
    }
}
// RocketManager.java
package com.yourname.rocketplugin;

import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.World;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * Класс управления ракетами и ПВО.
 */
public class RocketManager {
    private final RocketPlugin plugin;
    private StatsManager statsManager;
    private PVOManager pvoManager; // Менеджер ПВО
    private final Random random;
    private final Map<String, RocketType> rocketTypes;

    /**
     * Конструктор RocketManager.
     *
     * @param plugin Главный плагин.
     */
    public RocketManager(RocketPlugin plugin) {
        this.plugin = plugin;
        this.random = new Random();
        this.rocketTypes = new HashMap<>();
        loadRocketTypes();

        // Инициализация PVOManager
        this.pvoManager = new PVOManager(plugin);
    }

    /**
     * Устанавливает ссылку на StatsManager.
     *
     * @param statsManager Экземпляр StatsManager.
     */
    public void setStatsManager(StatsManager statsManager) {
        this.statsManager = statsManager;
        this.pvoManager.setStatsManager(statsManager);
    }

    /**
     * Возвращает экземпляр PVOManager.
     *
     * @return PVOManager.
     */
    public PVOManager getPvoManager() {
        return pvoManager;
    }

    /**
     * Загружает типы ракет из config.yml.
     */
    public void loadRocketTypes() {
        FileConfiguration config = plugin.getConfig();
        ConfigurationSection rocketsSection = config.getConfigurationSection("rockets");
        if (rocketsSection == null) {
            plugin.getLogger().severe("§cРаздел 'rockets' не найден в config.yml! Плагин отключен.");
            plugin.getServer().getPluginManager().disablePlugin(plugin);
            return;
        }

        for (String key : rocketsSection.getKeys(false)) {
            ConfigurationSection rocketSection = rocketsSection.getConfigurationSection(key);
            if (rocketSection == null) continue;

            double power = rocketSection.getDouble("power");
            int range = rocketSection.getInt("range");
            String launchParticleStr = rocketSection.getString("launchParticle", "FLAME");
            String launchSoundStr = rocketSection.getString("launchSound", "ENTITY_FIREWORK_ROCKET_LAUNCH");
            String explosionSoundStr = rocketSection.getString("explosionSound", "ENTITY_FIREWORK_ROCKET_LAUNCH");
            String explosionParticleStr = rocketSection.getString("explosionParticle", "SMOKE_NORMAL");
            int successChance = rocketSection.getInt("successChance", 50);
            boolean optimized = rocketSection.getBoolean("optimized", false);

            Particle launchParticle;
            Sound launchSound;
            Sound explosionSound;
            Particle explosionParticle;

            try {
                launchParticle = Particle.valueOf(launchParticleStr);
            } catch (IllegalArgumentException e) {
                plugin.getLogger().warning("§cНеизвестный тип частицы запуска '" + launchParticleStr + "' для ракеты '" + key + "'. Используется FLAME.");
                launchParticle = Particle.FLAME;
            }

            try {
                launchSound = Sound.valueOf(launchSoundStr);
            } catch (IllegalArgumentException e) {
                plugin.getLogger().warning("§cНеизвестный звук запуска '" + launchSoundStr + "' для ракеты '" + key + "'. Используется ENTITY_FIREWORK_ROCKET_LAUNCH.");
                launchSound = Sound.ENTITY_FIREWORK_ROCKET_LAUNCH;
            }

            try {
                explosionSound = Sound.valueOf(explosionSoundStr);
            } catch (IllegalArgumentException e) {
                plugin.getLogger().warning("§cНеизвестный звук взрыва '" + explosionSoundStr + "' для ракеты '" + key + "'. Используется ENTITY_FIREWORK_ROCKET_LAUNCH.");
                explosionSound = Sound.ENTITY_FIREWORK_ROCKET_LAUNCH;
            }

            try {
                explosionParticle = Particle.valueOf(explosionParticleStr);
            } catch (IllegalArgumentException e) {
                plugin.getLogger().warning("§cНеизвестный тип частицы взрыва '" + explosionParticleStr + "' для ракеты '" + key + "'. Используется SMOKE_NORMAL.");
                explosionParticle = Particle.SMOKE_NORMAL;
            }

            RocketType rocketType = new RocketType(key, power, range, launchParticle, launchSound, explosionSound, explosionParticle, successChance, optimized);
            rocketTypes.put(key.toUpperCase(), rocketType);
        }

        plugin.getLogger().info("§aЗагружено " + rocketTypes.size() + " типов ракет.");
    }

    /**
     * Получает тип ракеты по имени.
     *
     * @param name Имя ракеты.
     * @return RocketType или null, если не найден.
     */
    public RocketType getRocketType(String name) {
        return rocketTypes.get(name.toUpperCase());
    }

    /**
     * Возвращает все загруженные типы ракет.
     *
     * @return Карта типов ракет.
     */
    public Map<String, RocketType> getAllRocketTypes() {
        return rocketTypes;
    }

    /**
     * Запускает ракету.
     *
     * @param player Игрок, запустивший ракету.
     * @param type   Тип ракеты.
     * @param target Целевая локация.
     * @param delay  Задержка запуска в секундах.
     */
    public void launchRocket(final Player player, final RocketType type, final Location target, final int delay) {
        if (!target.getWorld().getName().equalsIgnoreCase("P_Drilla")) {
            player.sendMessage("§cРакеты могут взрываться только в мире P_Drilla.");
            return;
        }

        if (!this.statsManager.hasRockets(player, type)) {
            player.sendMessage("§cУ вас нет ракет типа " + type.getName() + "!");
            return;
        }

        this.statsManager.useRocket(player, type);

        if (delay > 0) {
            player.sendMessage("§eЗапуск ракеты через " + delay + " секунд(ы).");
            new BukkitRunnable() {
                private int secondsLeft = delay;

                @Override
                public void run() {
                    if (secondsLeft <= 0) {
                        this.cancel();
                        boolean success = checkLaunchSuccess(type);
                        if (success) {
                            Rocket rocket = type.isOptimized() ? new OptimizedRocket(player, type, target, plugin) : new Rocket(player, type, target, plugin);
                            rocket.launch();
                            player.sendMessage("§aРакета успешно запущена!");
                        } else {
                            player.sendMessage("§cРакета не смогла достичь цели и не взорвалась.");
                        }
                    } else {
                        player.sendMessage("§eЗапуск ракеты через " + secondsLeft + " секунд(ы).");
                        secondsLeft--;
                    }
                }
            }.runTaskTimer(plugin, 0L, 20L); // Запуск каждую секунду
        } else {
            boolean success = checkLaunchSuccess(type);
            if (success) {
                Rocket rocket = type.isOptimized() ? new OptimizedRocket(player, type, target, plugin) : new Rocket(player, type, target, plugin);
                rocket.launch();
                player.sendMessage("§aРакета успешно запущена!");
            } else {
                player.sendMessage("§cРакета не смогла достичь цели и не взорвалась.");
            }
        }
    }

    /**
     * Проверяет вероятность успешного запуска ракеты.
     *
     * @param type Тип ракеты.
     * @return true, если ракета успешно запущена.
     */
    private boolean checkLaunchSuccess(RocketType type) {
        int chance = type.getSuccessChance();
        int roll = random.nextInt(100) + 1;
        return roll <= chance;
    }
}
// RocketPlugin.java
package com.yourname.rocketplugin;

import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;

/**
 * Главный класс плагина RocketPlugin.
 */
public class RocketPlugin extends JavaPlugin {
    private static RocketPlugin instance;
    private RocketManager rocketManager;
    private StatsManager statsManager;
    private PVOManager pvoManager;

    public RocketPlugin() { }

    /**
     * Возвращает экземпляр плагина.
     *
     * @return Экземпляр RocketPlugin.
     */
    public static RocketPlugin getInstance() {
        return instance;
    }

    public RocketManager getRocketManager() {
        return rocketManager;
    }

    public StatsManager getStatsManager() {
        return statsManager;
    }

    public PVOManager getPvoManager() {
        return pvoManager;
    }

    @Override
    public void onEnable() {
        instance = this;
        this.saveDefaultConfig();

        // Инициализация RocketManager
        this.rocketManager = new RocketManager(this);
        // Инициализация StatsManager с RocketManager
        this.statsManager = new StatsManager(this, this.rocketManager);
        // Установка StatsManager в RocketManager
        this.rocketManager.setStatsManager(this.statsManager);
        // Получение PVOManager из RocketManager
        this.pvoManager = this.rocketManager.getPvoManager();

        this.statsManager.load();

        // Регистрация команд
        PluginCommand rocketCommand = this.getCommand("rocket");
        PluginCommand pvoCommand = this.getCommand("pvo");

        if (rocketCommand != null) {
            rocketCommand.setExecutor(new RocketCommand(this.rocketManager, this.statsManager, this));
            rocketCommand.setTabCompleter(new RocketTabCompleter(this));
        } else {
            this.getLogger().severe("§cНе удалось зарегистрировать команду 'rocket'. Проверьте plugin.yml.");
            this.setEnabled(false);
            return;
        }

        if (pvoCommand != null) {
            pvoCommand.setExecutor(new PVOCommand(this.rocketManager, this));
        } else {
            this.getLogger().severe("§cНе удалось зарегистрировать команду 'pvo'. Проверьте plugin.yml.");
            this.setEnabled(false);
            return;
        }

        // Регистрация событий
        PluginManager pm = this.getServer().getPluginManager();
        pm.registerEvents(new RocketListener(this.rocketManager, this), this);
        pm.registerEvents(new PVOListener(this.rocketManager, this), this);
        pm.registerEvents(new RocketCraftListener(this), this);

        this.getLogger().info("§aRocketPlugin был включен!");
    }

    @Override
    public void onDisable() {
        if (this.statsManager != null) {
            this.statsManager.save();
        }

        if (this.pvoManager != null) {
            this.pvoManager.savePVOBlocks();
        }

        this.getLogger().info("§cRocketPlugin был отключен!");
    }
}
// RocketTabCompleter.java
package com.yourname.rocketplugin;

import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Класс для автодополнения команды /rocket.
 */
public class RocketTabCompleter implements TabCompleter {
    private final RocketPlugin plugin;

    /**
     * Конструктор RocketTabCompleter.
     *
     * @param plugin Главный плагин.
     */
    public RocketTabCompleter(RocketPlugin plugin) {
        this.plugin = plugin;
    }

    @Override
    public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
        if (!command.getName().equalsIgnoreCase("rocket")) {
            return null;
        }

        List<String> completions = new ArrayList<>();

        if (args.length == 1) {
            List<String> subcommands = List.of("launch", "give", "stats", "reload", "craft");
            for (String sub : subcommands) {
                if (sub.startsWith(args[0].toLowerCase())) {
                    completions.add(sub);
                }
            }
            return completions;
        }

        if (args.length == 2) {
            String subcommand = args[0].toLowerCase();
            RocketManager rocketManager = plugin.getRocketManager();
            if (subcommand.equals("launch") || subcommand.equals("give") || subcommand.equals("craft")) {
                Map<String, RocketType> types = rocketManager.getAllRocketTypes();
                for (RocketType type : types.values()) {
                    if (type.getName().toLowerCase().startsWith(args[1].toLowerCase())) {
                        completions.add(type.getName());
                    }
                }
            } else if (subcommand.equals("stats")) {
                for (Player player : Bukkit.getOnlinePlayers()) {
                    if (player.getName().toLowerCase().startsWith(args[1].toLowerCase())) {
                        completions.add(player.getName());
                    }
                }
            } else if (subcommand.equals("reload")) {
                // Нет дополнительных аргументов
            }
            return completions;
        }

        if (args.length == 3 && args[0].equalsIgnoreCase("give")) {
            RocketManager rocketManager = plugin.getRocketManager();
            String typeQuery = args[2].toUpperCase();
            Map<String, RocketType> types = rocketManager.getAllRocketTypes();
            for (RocketType type : types.values()) {
                if (type.getName().toLowerCase().startsWith(typeQuery.toLowerCase())) {
                    completions.add(type.getName());
                }
            }
            return completions;
        }

        if (args.length == 4 && args[0].equalsIgnoreCase("give")) {
            for (int i = 1; i <= 64; i++) { // Максимум 64 ракеты за раз
                String amount = String.valueOf(i);
                if (amount.startsWith(args[3])) {
                    completions.add(amount);
                }
            }
            return completions;
        }

        return completions;
    }
}
// RocketType.java
package com.yourname.rocketplugin;

import org.bukkit.Particle;
import org.bukkit.Sound;

/**
 * Класс, представляющий тип ракеты.
 */
public class RocketType {
    private final String name;
    private final double power;
    private final int range;
    private final Particle launchParticle;
    private final Sound launchSound;
    private final Sound explosionSound;
    private final Particle explosionParticle;
    private final int successChance;
    private final boolean optimized;

    /**
     * Конструктор типа ракеты.
     *
     * @param name              Имя ракеты.
     * @param power             Сила взрыва.
     * @param range             Дальность полета.
     * @param launchParticle    Частица при запуске.
     * @param launchSound       Звук при запуске.
     * @param explosionSound    Звук взрыва.
     * @param explosionParticle Частица при взрыве.
     * @param successChance     Шанс успешного запуска.
     * @param optimized         Флаг оптимизированного взрыва.
     */
    public RocketType(String name, double power, int range, Particle launchParticle,
                      Sound launchSound, Sound explosionSound, Particle explosionParticle, int successChance, boolean optimized) {
        this.name = name;
        this.power = power;
        this.range = range;
        this.launchParticle = launchParticle;
        this.launchSound = launchSound;
        this.explosionSound = explosionSound;
        this.explosionParticle = explosionParticle;
        this.successChance = successChance;
        this.optimized = optimized;
    }

    public String getName() {
        return name;
    }

    public double getPower() {
        return power;
    }

    public int getRange() {
        return range;
    }

    public Particle getLaunchParticle() {
        return launchParticle;
    }

    public Sound getLaunchSound() {
        return launchSound;
    }

    public Sound getExplosionSound() {
        return explosionSound;
    }

    public Particle getExplosionParticle() {
        return explosionParticle;
    }

    public int getSuccessChance() {
        return successChance;
    }

    public boolean isOptimized() {
        return optimized;
    }
}
// StatsManager.java
package com.yourname.rocketplugin;

import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;

import java.io.File;
import java.io.IOException;
import java.util.Map;

/**
 * Класс для управления статистикой игроков по ракетам.
 */
public class StatsManager {
    private final RocketPlugin plugin;
    private final File statsFile;
    private FileConfiguration statsConfig;
    private final RocketManager rocketManager;

    /**
     * Конструктор StatsManager.
     *
     * @param plugin        Главный плагин.
     * @param rocketManager Менеджер ракет.
     */
    public StatsManager(RocketPlugin plugin, RocketManager rocketManager) {
        this.plugin = plugin;
        this.rocketManager = rocketManager;
        this.statsFile = new File(plugin.getDataFolder(), "stats.yml");
        if (!this.statsFile.exists()) {
            try {
                plugin.saveResource("stats.yml", false);
            } catch (IllegalArgumentException e) {
                // Файл stats.yml не найден в ресурсах, создаём пустой
                this.statsConfig = new YamlConfiguration();
                try {
                    this.statsConfig.save(this.statsFile);
                } catch (IOException ex) {
                    plugin.getLogger().severe("§cНе удалось создать stats.yml:");
                    ex.printStackTrace();
                }
            }
        }

        this.statsConfig = YamlConfiguration.loadConfiguration(this.statsFile);
    }

    /**
     * Загружает статистику из файла.
     */
    public void load() {
        try {
            this.statsConfig.load(this.statsFile);
        } catch (Exception e) {
            this.plugin.getLogger().severe("§cНе удалось загрузить stats.yml:");
            e.printStackTrace();
        }
    }

    /**
     * Сохраняет статистику в файл.
     */
    public void save() {
        try {
            this.statsConfig.save(this.statsFile);
        } catch (IOException e) {
            this.plugin.getLogger().severe("§cНе удалось сохранить stats.yml:");
            e.printStackTrace();
        }
    }

    /**
     * Получает количество ракет определенного типа у игрока.
     *
     * @param player Игрок.
     * @param type   Тип ракеты.
     * @return Количество ракет.
     */
    public int getRockets(Player player, RocketType type) {
        String path = player.getUniqueId().toString() + ".rockets." + type.getName();
        return statsConfig.getInt(path, 0);
    }

    /**
     * Добавляет ракеты игроку.
     *
     * @param player Игрок.
     * @param type   Тип ракеты.
     * @param amount Количество.
     */
    public void addRockets(Player player, RocketType type, int amount) {
        String path = player.getUniqueId().toString() + ".rockets." + type.getName();
        int current = getRockets(player, type);
        statsConfig.set(path, current + amount);
        save();
    }

    /**
     * Проверяет, есть ли у игрока ракеты определенного типа.
     *
     * @param player Игрок.
     * @param type   Тип ракеты.
     * @return true, если есть.
     */
    public boolean hasRockets(Player player, RocketType type) {
        return getRockets(player, type) > 0;
    }

    /**
     * Использует одну ракету определенного типа у игрока.
     *
     * @param player Игрок.
     * @param type   Тип ракеты.
     */
    public void useRocket(Player player, RocketType type) {
        String path = player.getUniqueId().toString() + ".rockets." + type.getName();
        int current = getRockets(player, type);
        if (current > 0) {
            this.statsConfig.set(path, current - 1);
            save();
        }
    }

    /**
     * Получает статистику по ракетам игрока.
     *
     * @param player Игрок.
     * @return Строка с статистикой.
     */
    public String getStats(Player player) {
        StringBuilder sb = new StringBuilder("§a§lСтатистика Ракет для " + player.getName() + ":\n");
        Map<String, RocketType> allTypes = rocketManager.getAllRocketTypes();

        for (RocketType type : allTypes.values()) {
            sb.append("§e").append(type.getName()).append(": §b").append(getRockets(player, type)).append("\n");
        }

        return sb.toString();
    }
}
rockets:
  SMALL:
    power: 10.0
    range: 100
    launchParticle: FLAME
    launchSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionParticle: SMOKE_NORMAL
    successChance: 50
    optimized: false
  MEDIUM:
    power: 15.0
    range: 150
    launchParticle: FLAME
    launchSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionParticle: SMOKE_NORMAL
    successChance: 50
    optimized: false
  LARGE:
    power: 20.0
    range: 200
    launchParticle: EXPLOSION_NORMAL
    launchSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionParticle: SMOKE_LARGE
    successChance: 50
    optimized: false
  EXTRA_LARGE:
    power: 25.0
    range: 300
    launchParticle: EXPLOSION_LARGE
    launchSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionParticle: EXPLOSION_HUGE
    successChance: 50
    optimized: false
  NUCLEAR:
    power: 70.0
    range: 500
    launchParticle: EXPLOSION_HUGE
    launchSound: ENTITY_GENERIC_EXPLODE
    explosionSound: ENTITY_GENERIC_EXPLODE
    explosionParticle: EXPLOSION_HUGE
    successChance: 40
    optimized: false
  SUPER_NUCLEAR:
    power: 100.0
    range: 700
    launchParticle: EXPLOSION_HUGE
    launchSound: ENTITY_GENERIC_EXPLODE
    explosionSound: ENTITY_GENERIC_EXPLODE
    explosionParticle: EXPLOSION_HUGE
    successChance: 30
    optimized: false
  MEGA_NUCLEAR:
    power: 150.0
    range: 1000
    launchParticle: EXPLOSION_HUGE
    launchSound: ENTITY_GENERIC_EXPLODE
    explosionSound: ENTITY_GENERIC_EXPLODE
    explosionParticle: EXPLOSION_HUGE
    successChance: 20
    optimized: false
  EXTREME_NUCLEAR:
    power: 250.0
    range: 1500
    launchParticle: SUSPENDED
    launchSound: ENTITY_GENERIC_EXPLODE
    explosionSound: ENTITY_GENERIC_EXPLODE
    explosionParticle: EXPLOSION_HUGE
    successChance: 15
    optimized: true
  ULTRA_NUCLEAR:
    power: 400.0
    range: 2000
    launchParticle: SPELL_INSTANT
    launchSound: ENTITY_GENERIC_EXPLODE
    explosionSound: ENTITY_GENERIC_EXPLODE
    explosionParticle: EXPLOSION_HUGE
    successChance: 10
    optimized: true
  USSR:
    power: 500.0
    range: 2500
    launchParticle: PORTAL
    launchSound: ENTITY_GENERIC_EXPLODE
    explosionSound: ENTITY_GENERIC_EXPLODE
    explosionParticle: EXPLOSION_HUGE
    successChance: 100
    optimized: false
craftingRecipes:
  SMALL:
    ingredients:
      DIAMOND: 2
      FIREWORK_ROCKET: 1
  MEDIUM:
    ingredients:
      DIAMOND: 3
      FIREWORK_ROCKET: 2
  LARGE:
    ingredients:
      DIAMOND: 4
      FIREWORK_ROCKET: 3
  EXTRA_LARGE:
    ingredients:
      DIAMOND: 5
      FIREWORK_ROCKET: 4
  NUCLEAR:
    ingredients:
      DIAMOND: 6
      FIREWORK_ROCKET: 5
  SUPER_NUCLEAR:
    ingredients:
      DIAMOND: 7
      FIREWORK_ROCKET: 6
  MEGA_NUCLEAR:
    ingredients:
      DIAMOND: 8
      FIREWORK_ROCKET: 7
  EXTREME_NUCLEAR:
    ingredients:
      DIAMOND: 10
      FIREWORK_ROCKET: 8
  ULTRA_NUCLEAR:
    ingredients:
      DIAMOND: 12
      FIREWORK_ROCKET: 10
  USSR:
    ingredients:
      DIAMOND: 20
      FIREWORK_ROCKET: 15


1) Сделай, чтобы ракета USSR взрывала всё ввиде сферы 512 в длину 512 в ширину и 128 блоков в высоту блоков, можешь сделать новый класс для этой инициализации
2) Улучши пво, сделай там меню, когда сидишь + пкм, чтобы можно было назначить игроков, на которых пво не будет работать.
3) Сделай, чтобы любое пво можно было поставить
4) Удали сообщение, что вы сломали не пво и тд (для пво)
5) Сделай, чтобы всё работало нормально, улучши плагин и сразу напиши полный код