package com.yourname.rocketplugin;

import org.bukkit.*;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.block.Block;
import org.bukkit.entity.EnderCrystal;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;

import java.util.Random;
import java.util.Set;

/**
 * Класс, представляющий ракету.
 */
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.5; // Скорость полета ракеты
    private final Random random = new Random();

    /**
     * Конструктор ракеты.
     *
     * @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.getEyeLocation().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;
        }

        // Определяем, является ли ракета суперновой
        boolean isSupernova = this.type.getPower() >= plugin.getConfig().getDouble("supernova.explosion_size", 100.0);

        if (isSupernova) {
            performSupernova(world, target);
        } else {
            performNormalExplosion(world, target);
        }
    }

    /**
     * Выполняет обычный взрыв ракеты.
     *
     * @param world             Мир, в котором происходит взрыв.
     * @param explosionLocation Локация взрыва.
     */
    private void performNormalExplosion(World world, Location explosionLocation) {
        // Визуальные эффекты взрыва
        world.spawnParticle(this.type.getExplosionParticle(), explosionLocation, 200, this.type.getPower(), this.type.getPower(), this.type.getPower(), 0.1);
        world.playSound(explosionLocation, this.type.getExplosionSound(), 2.0F, 1.0F);

        // Создание анимации расширяющегося взрыва
        new BukkitRunnable() {
            private double currentRadius = 0.0;
            private final double maxRadius = type.getPower();
            private final double step = 2.0;

            @Override
            public void run() {
                if (currentRadius > maxRadius) {
                    this.cancel();
                    return;
                }

                // Спавн частиц по кругу взрыва
                for (double angle = 0; angle < 360; angle += 10) {
                    double rad = Math.toRadians(angle);
                    double x = explosionLocation.getX() + currentRadius * Math.cos(rad);
                    double z = explosionLocation.getZ() + currentRadius * Math.sin(rad);
                    Location particleLoc = new Location(world, x, explosionLocation.getY(), z);
                    world.spawnParticle(Particle.EXPLOSION_NORMAL, particleLoc, 1);
                }

                currentRadius += step * type.getParticleMultiplier();
            }
        }.runTaskTimer(this.plugin, 0L, 2L); // Выполняется каждые 2 тика
    }

    /**
     * Выполняет взрыв ракеты с эффектами суперновы.
     *
     * @param world             Мир, в котором происходит взрыв.
     * @param explosionLocation Локация взрыва.
     */
    private void performSupernova(World world, Location explosionLocation) {
        // Извлекаем Supernova-параметры из типа ракеты
        double explosionSize = this.type.getExplosionSize();
        double particleMultiplier = this.type.getParticleMultiplier();
        double fallSpeedMultiplier = this.type.getFallSpeedMultiplier();
        boolean flash = this.type.isFlash();
        Particle supernovaParticle = this.type.getSupernovaParticle();
        Material[] explosionMaterials = this.type.getExplosionMaterials();

        // Визуальные эффекты суперновы
        world.spawnParticle(supernovaParticle, explosionLocation, 500, explosionSize, explosionSize, explosionSize, 0.1);
        world.playSound(explosionLocation, this.type.getExplosionSound(), 3.0F, 1.0F);

        // Создание EnderCrystal для анимации падения (имитация суперновы)
        EnderCrystal crystal = (EnderCrystal) world.spawn(explosionLocation, EnderCrystal.class);
        try {
            crystal.setShowingBottom(false);
        } catch (NoSuchMethodError e) {
            // Метод не поддерживается, пропускаем
            plugin.getLogger().warning("§cМетод setShowBottom не поддерживается в текущей версии сервера.");
        }
        crystal.setBeamTarget(explosionLocation.clone().add(0, 50, 0)); // Направляем луч вверх

        Vector fallVector = new Vector(0.0, -2.0 * fallSpeedMultiplier, 0.0); // Скорость падения
        final double fallSpeedDecrease = 0.05; // Замедление падения

        // Используем массив для хранения кристалла, чтобы изменять его внутри Runnable
        final EnderCrystal[] crystalHolder = new EnderCrystal[]{crystal};

        new BukkitRunnable() {
            Location crystalLoc = explosionLocation.clone();

            @Override
            public void run() {
                // Обновление позиции кристалла
                crystalLoc.add(fallVector);
                if (fallVector.getY() < -0.5) {
                    fallVector.setY(fallVector.getY() + fallSpeedDecrease);
                }

                // Переспавн кристалла
                crystalHolder[0].remove();
                if (crystalLoc.getWorld() == null) {
                    this.cancel();
                    return;
                }
                crystalHolder[0] = (EnderCrystal) world.spawn(crystalLoc, EnderCrystal.class);
                try {
                    crystalHolder[0].setShowingBottom(false);
                } catch (NoSuchMethodError e) {
                    // Метод не поддерживается, пропускаем
                    plugin.getLogger().warning("§cМетод setShowBottom не поддерживается в текущей версии сервера.");
                }
                crystalHolder[0].setBeamTarget(explosionLocation.clone().add(0, 50, 0));

                // Спавн частиц для анимации
                world.spawnParticle(Particle.CLOUD, crystalLoc, 20, 0.5, 0.5, 0.5, 0.01);
                world.spawnParticle(Particle.FLAME, crystalLoc, 20, 0.5, 0.5, 0.5, 0.01);

                // Разрушение блока под кристаллом
                Block blockBelow = crystalLoc.clone().subtract(0, 1, 0).getBlock();
                if (blockBelow.getType() != Material.AIR && !Utils.isBlockImmune(blockBelow.getType()) && !Utils.isZoneProtected(blockBelow.getLocation())) {
                    blockBelow.setType(Material.AIR);
                }

                // Проверка близости к исходной локации для взрыва
                if (crystalLoc.distance(explosionLocation) < 3.0) {
                    crystalHolder[0].remove();
                    this.cancel();
                    performSupernovaEffects(world, explosionLocation, explosionSize, particleMultiplier, explosionMaterials, flash);
                }
            }
        }.runTaskTimer(this.plugin, 0L, 1L);
    }

    /**
     * Создает эффекты суперновы после завершения анимации падения кристалла.
     *
     * @param world             Мир, в котором происходит взрыв.
     * @param explosionLocation Локация взрыва.
     * @param explosionSize     Размер суперновы.
     * @param particleMultiplier Множитель для частиц.
     * @param explosionMaterials Материалы для разрушения.
     * @param flash             Включение вспышки.
     */
    private void performSupernovaEffects(World world, Location explosionLocation,
                                         double explosionSize, double particleMultiplier,
                                         Material[] explosionMaterials, boolean flash) {
        Random random = new Random();

        // Расширяющийся взрыв суперновы
        new BukkitRunnable() {
            private double currentRadius = 0.0;
            private final double maxRadius = explosionSize;
            private final double step = 5.0;

            @Override
            public void run() {
                if (currentRadius > maxRadius) {
                    this.cancel();
                    return;
                }

                // Спавн частиц по кругу суперновы
                for (double angle = 0; angle < 360; angle += 10) {
                    double rad = Math.toRadians(angle);
                    double x = explosionLocation.getX() + currentRadius * Math.cos(rad);
                    double z = explosionLocation.getZ() + currentRadius * Math.sin(rad);
                    Location particleLoc = new Location(world, x, explosionLocation.getY(), z);
                    world.spawnParticle(Rocket.this.type.getSupernovaParticle(), particleLoc, 1);
                }

                // Разрушение блоков в радиусе
                for (Block block : Utils.getBlocksInRadius(explosionLocation, currentRadius)) {
                    if (block.getType() != Material.AIR && !Utils.isBlockImmune(block.getType()) && !Utils.isZoneProtected(block.getLocation())) {
                        block.setType(explosionMaterials[random.nextInt(explosionMaterials.length)]);
                    }
                }

                // Влияние на сущности в радиусе
                for (Entity entity : world.getNearbyEntities(explosionLocation, currentRadius, currentRadius, currentRadius)) {
                    if (entity instanceof Player) {
                        Player player = (Player) entity;
                        player.playSound(player.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 1.0F, 1.0F);
                        player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 60, 1, false, false));
                    }
                    if (entity instanceof LivingEntity) {
                        Utils.pureDamageEntity((LivingEntity) entity, 20.0, "RocketPlugin-supernova", true, EntityDamageEvent.DamageCause.BLOCK_EXPLOSION);
                    }
                }

                currentRadius += step * particleMultiplier;
            }
        }.runTaskTimer(this.plugin, 0L, 2L); // Выполняется каждые 2 тика
    }
}
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.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
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.toUpperCase());
            } 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.toUpperCase());
            int required = recipeSection.getInt(materialStr);
            int removed = 0;
            for (ItemStack item : player.getInventory().all(material).keySet()) {
                int slot = player.getInventory().all(material).keySet().iterator().next().getSlot();
                ItemStack stack = player.getInventory().getItem(slot);
                if (stack == null || stack.getType() != material) continue;
                if (removed >= required) break;
                int toRemove = Math.min(stack.getAmount(), required - removed);
                stack.setAmount(stack.getAmount() - toRemove);
                if (stack.getAmount() <= 0) {
                    player.getInventory().setItem(slot, null);
                }
                removed += toRemove;
                // Если все требуемые предметы удалены, выходим из цикла
                if (removed >= required) break;
            }
        }

        // Добавляем ракету в статистику
        statsManager.addRockets(player, type, 1);
        player.sendMessage(ChatColor.GREEN + "§aВы успешно произвели ракету типа " + type.getName() + ".");
    }
}
(Incompatible types. Found: 'org.bukkit.inventory.ItemStack', required: 'java.lang.Integer'
Cannot resolve method 'getSlot' in 'Integer')
package com.yourname.rocketplugin;

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;

/**
 * Класс слушателя событий взрыва и ПВО.
 */
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;
        }

        // Если взрыв вызван ракетою, разрешаем, иначе отменяем
        // В текущей реализации класс Rocket сам управляет взрывами, поэтому дополнительная проверка не требуется
        // Можно оставить как есть или добавить дополнительные проверки при необходимости
    }
}
package com.yourname.rocketplugin;

import org.bukkit.Material;
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 java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * Класс управления ракетами и ПВО.
 */
public class RocketManager {
    private final RocketPlugin plugin;
    private StatsManager statsManager;
    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();
    }

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

    /**
     * Загружает типы ракет из 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_GENERIC_EXPLODE");
            String explosionParticleStr = rocketSection.getString("explosionParticle", "SMOKE_NORMAL");
            int successChance = rocketSection.getInt("successChance", 50);
            boolean optimized = rocketSection.getBoolean("optimized", false);

            // Параметры Supernova
            double explosionSize = rocketSection.getDouble("explosionSize", config.getDouble("supernova.explosion_size", 200.0));
            double particleMultiplier = rocketSection.getDouble("particleMultiplier", config.getDouble("supernova.particle_multiplier", 2.5));
            double fallSpeedMultiplier = rocketSection.getDouble("fallSpeedMultiplier", config.getDouble("supernova.fall_speed_multiplier", 1.5));
            boolean flash = rocketSection.getBoolean("flash", config.getBoolean("supernova.flash", true));
            String supernovaParticleStr = rocketSection.getString("supernovaParticle", "EXPLOSION_NORMAL");
            ConfigurationSection materialsSection = rocketSection.getConfigurationSection("explosionMaterials");
            Material[] explosionMaterials = new Material[]{Material.OBSIDIAN, Material.BLACK_CONCRETE, Material.FIRE}; // По умолчанию
            if (materialsSection != null) {
                explosionMaterials = materialsSection.getKeys(false).stream()
                        .map(matName -> {
                            try {
                                return Material.valueOf(matName.toUpperCase());
                            } catch (IllegalArgumentException e) {
                                plugin.getLogger().warning("§cНеизвестный материал '" + matName + "' в настройках суперновы для ракеты '" + key + "'.");
                                return null;
                            }
                        })
                        .filter(mat -> mat != null)
                        .toArray(Material[]::new);
            }

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

            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_GENERIC_EXPLODE.");
                explosionSound = Sound.ENTITY_GENERIC_EXPLODE;
            }

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

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

            RocketType rocketType = new RocketType(
                    key,
                    power,
                    range,
                    launchParticle,
                    launchSound,
                    explosionSound,
                    explosionParticle,
                    successChance,
                    optimized,
                    explosionSize,
                    particleMultiplier,
                    fallSpeedMultiplier,
                    flash,
                    supernovaParticle,
                    explosionMaterials
            );
            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 = 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 = 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;
    }
}
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;

    public RocketPlugin() { }

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

    public RocketManager getRocketManager() {
        return rocketManager;
    }

    public StatsManager getStatsManager() {
        return statsManager;
    }

    @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);
        // Загрузка статистики
        this.statsManager.load();

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

        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;
        }

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

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

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

        this.getLogger().info("§cRocketPlugin был отключен!");
    }
}
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());
                    }
                }
            }
            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;
    }
}
package com.yourname.rocketplugin;

import org.bukkit.Material;
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;

    // Параметры Supernova
    private final double explosionSize;
    private final double particleMultiplier;
    private final double fallSpeedMultiplier;
    private final boolean flash;
    private final Particle supernovaParticle;
    private final Material[] explosionMaterials;

    /**
     * Конструктор типа ракеты.
     *
     * @param name                  Имя ракеты.
     * @param power                 Сила взрыва.
     * @param range                 Дальность полета.
     * @param launchParticle        Частица при запуске.
     * @param launchSound           Звук при запуске.
     * @param explosionSound        Звук взрыва.
     * @param explosionParticle     Частица при взрыве.
     * @param successChance         Шанс успешного запуска.
     * @param optimized             Флаг оптимизированного взрыва.
     * @param explosionSize         Размер взрыва суперновы.
     * @param particleMultiplier    Множитель для частиц суперновы.
     * @param fallSpeedMultiplier   Множитель скорости падения кристалла.
     * @param flash                 Включение/отключение вспышки.
     * @param supernovaParticle     Тип частицы для суперновы.
     * @param explosionMaterials    Материалы для разрушения при супернове.
     */
    public RocketType(String name, double power, int range, Particle launchParticle,
                      Sound launchSound, Sound explosionSound, Particle explosionParticle,
                      int successChance, boolean optimized,
                      double explosionSize, double particleMultiplier, double fallSpeedMultiplier,
                      boolean flash, Particle supernovaParticle, Material[] explosionMaterials) {
        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;
        this.explosionSize = explosionSize;
        this.particleMultiplier = particleMultiplier;
        this.fallSpeedMultiplier = fallSpeedMultiplier;
        this.flash = flash;
        this.supernovaParticle = supernovaParticle;
        this.explosionMaterials = explosionMaterials;
    }

    // Геттеры для всех полей

    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;
    }

    public double getExplosionSize() {
        return explosionSize;
    }

    public double getParticleMultiplier() {
        return particleMultiplier;
    }

    public double getFallSpeedMultiplier() {
        return fallSpeedMultiplier;
    }

    public boolean isFlash() {
        return flash;
    }

    public Particle getSupernovaParticle() {
        return supernovaParticle;
    }

    public Material[] getExplosionMaterials() {
        return explosionMaterials;
    }
}
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();
    }
}
package com.yourname.rocketplugin;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.EntityDamageEvent;

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

/**
 * Вспомогательный класс с утилитными методами.
 */
public class Utils {

    /**
     * Проверяет, является ли блок устойчивым к взрыву.
     *
     * @param material Тип материала.
     * @return true, если блок устойчив.
     */
    public static boolean isBlockImmune(Material material) {
        // Добавьте здесь логику для блоков, устойчивых к взрывам
        Set<Material> immuneMaterials = new HashSet<>();
        immuneMaterials.add(Material.BEDROCK);
        immuneMaterials.add(Material.ENDER_CHEST);
        immuneMaterials.add(Material.ANVIL);
        immuneMaterials.add(Material.GOLD_BLOCK);
        immuneMaterials.add(Material.DIAMOND_BLOCK);
        immuneMaterials.add(Material.EMERALD_BLOCK);
        // Добавьте другие материалы по необходимости
        return immuneMaterials.contains(material);
    }

    /**
     * Проверяет, защищена ли зона для данного местоположения.
     *
     * @param location Локация.
     * @return true, если зона защищена.
     */
    public static boolean isZoneProtected(Location location) {
        // Реализуйте проверку защищенных зон
        // Без сторонних зависимостей всегда возвращаем false
        return false;
    }

    /**
     * Получает все блоки в заданном радиусе.
     *
     * @param center Локация центра.
     * @param radius Радиус.
     * @return Set блоков.
     */
    public static Set<Block> getBlocksInRadius(Location center, double radius) {
        Set<Block> blocks = new HashSet<>();
        int r = (int) Math.ceil(radius);
        for (int x = center.getBlockX() - r; x <= center.getBlockX() + r; x++) {
            for (int y = center.getBlockY() - r; y <= center.getBlockY() + r; y++) {
                for (int z = center.getBlockZ() - r; z <= center.getBlockZ() + r; z++) {
                    Block block = center.getWorld().getBlockAt(x, y, z);
                    double distance = center.distance(block.getLocation().add(0.5, 0.5, 0.5));
                    if (distance <= radius) {
                        blocks.add(block);
                    }
                }
            }
        }
        return blocks;
    }

    /**
     * Наносит чистый урон сущности без отскока.
     *
     * @param entity        Сущность, получающая урон.
     * @param damage        Урон.
     * @param damageType    Тип урона (строка для логирования или других целей).
     * @param ignoreArmor   Игнорировать броню.
     * @param damageCause   Тип причины урона.
     */
    public static void pureDamageEntity(LivingEntity entity, double damage, String damageType, boolean ignoreArmor, EntityDamageEvent.DamageCause damageCause) {
        // Создаем кастомное событие для урона, если необходимо
        EntityDamageEvent event = new EntityDamageEvent(entity, damageCause, damage);
        Bukkit.getPluginManager().callEvent(event);
        if (!event.isCancelled()) {
            entity.damage(damage, null); // null означает, что урон приходит не от какого-либо источника
        }
    }
}
# RocketPlugin Configuration

# Настройки суперновы
supernova:
  # Размер взрыва суперновы по умолчанию
  explosion_size: 200.0

  # Множитель для количества частиц при расширении взрыва
  particle_multiplier: 2.5

  # Множитель скорости падения кристалла
  fall_speed_multiplier: 1.5

  # Включение/отключение вспышки
  flash: true

  # Тип частицы при взрыве суперновы
  supernova_particle: EXPLOSION_NORMAL

  # Материалы, используемые при разрушении блоков взрывом
  explosion_materials:
    OBSIDIAN: true
    BLACK_CONCRETE: true
    FIRE: true
    END_STONE: true

# Настройки ракет
rockets:
  SMALL_SUPERNOVA:
    power: 50.0
    range: 150
    launchParticle: FLAME
    launchSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionSound: ENTITY_GENERIC_EXPLODE
    explosionParticle: SMOKE_NORMAL
    successChance: 90
    optimized: false
    # Параметры Supernova
    explosionSize: 100.0
    particleMultiplier: 1.5
    fallSpeedMultiplier: 1.2
    flash: true
    supernovaParticle: CLOUD
    explosionMaterials:
      OBSIDIAN: true
      BLACK_CONCRETE: true
      FIRE: true

  MEDIUM_SUPERNOVA:
    power: 100.0
    range: 300
    launchParticle: EXPLOSION_NORMAL
    launchSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionSound: ENTITY_GENERIC_EXPLODE
    explosionParticle: SMOKE_LARGE
    successChance: 75
    optimized: false
    # Параметры Supernova
    explosionSize: 200.0
    particleMultiplier: 2.0
    fallSpeedMultiplier: 1.5
    flash: true
    supernovaParticle: EXPLOSION_NORMAL
    explosionMaterials:
      OBSIDIAN: true
      BLACK_CONCRETE: true
      FIRE: true
      END_STONE: true

  LARGE_SUPERNOVA:
    power: 200.0
    range: 500
    launchParticle: EXPLOSION_HUGE
    launchSound: ENTITY_GENERIC_EXPLODE
    explosionSound: ENTITY_GENERIC_EXPLODE
    explosionParticle: EXPLOSION_HUGE
    successChance: 60
    optimized: false
    # Параметры Supernova
    explosionSize: 300.0
    particleMultiplier: 3.0
    fallSpeedMultiplier: 2.0
    flash: true
    supernovaParticle: EXPLOSION_HUGE
    explosionMaterials:
      OBSIDIAN: true
      BLACK_CONCRETE: true
      FIRE: true
      END_STONE: true
      DIAMOND_BLOCK: true

name: RocketPlugin
version: 1.0
main: com.yourname.rocketplugin.RocketPlugin
api-version: 1.16
commands:
  rocket:
    description: Управление ракетами.
    usage: /rocket <launch|give|stats|reload|craft>
    aliases: [rk]
permissions:
  rocketplugin.use:
    description: Разрешение на использование команд RocketPlugin.
    default: true
  rocketplugin.give:
    description: Разрешение на выдачу ракет другим игрокам.
    default: op
  rocketplugin.reload:
    description: Разрешение на перезагрузку конфигурации плагина.
    default: op


1) Исправь баги и ошибки
2) Добавь команду для трейда ракет
3) Сделай команду для отнимания ракет
4) Улучши всё и напиши полный код