// Rocket.java
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.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
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;

/**
 * Класс, представляющий ракету.
 */
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 double explosionSize;
    private double particleMultiplier;
    private double fallSpeedMultiplier;
    private boolean flash;
    private Particle explosionParticle;
    private Material[] explosionMaterials;

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

        // Загрузка параметров суперновы из config.yml
        FileConfiguration config = plugin.getConfig();
        this.explosionSize = config.getDouble("supernova.explosion_size", 100.0);
        this.particleMultiplier = config.getDouble("supernova.particle_multiplier", 1.0);
        this.fallSpeedMultiplier = config.getDouble("supernova.fall_speed_multiplier", 1.0);
        this.flash = config.getBoolean("supernova.flash", true);
        String explosionParticleStr = config.getString("supernova.explosion_particle", "SMOKE_LARGE");
        try {
            this.explosionParticle = Particle.valueOf(explosionParticleStr);
        } catch (IllegalArgumentException e) {
            plugin.getLogger().warning("§cНеизвестный тип частицы взрыва '" + explosionParticleStr + "'. Используется SMOKE_LARGE.");
            this.explosionParticle = Particle.SMOKE_LARGE;
        }

        // Загрузка материалов для взрыва
        ConfigurationSection materialsSection = config.getConfigurationSection("supernova.explosion_materials");
        if (materialsSection != null) {
            this.explosionMaterials = new Material[materialsSection.getKeys(false).size()];
            int index = 0;
            for (String matName : materialsSection.getKeys(false)) {
                try {
                    this.explosionMaterials[index++] = Material.valueOf(matName.toUpperCase());
                } catch (IllegalArgumentException e) {
                    plugin.getLogger().warning("§cНеизвестный материал '" + matName + "' в настройках суперновы.");
                }
            }
        } else {
            // Стандартные материалы, если в конфиге не указано
            this.explosionMaterials = new Material[]{Material.OBSIDIAN, Material.BLACK_CONCRETE, Material.FIRE};
        }
    }

    /**
     * Запускает ракету.
     */
    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 * particleMultiplier;
            }
        }.runTaskTimer(this.plugin, 0L, 2L); // Выполняется каждые 2 тика
    }

    /**
     * Выполняет взрыв ракеты с эффектами суперновы.
     *
     * @param world             Мир, в котором происходит взрыв.
     * @param explosionLocation Локация взрыва.
     */
    private void performSupernova(World world, Location explosionLocation) {
        // Визуальные эффекты суперновы
        world.spawnParticle(this.explosionParticle, 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);
        // Проверяем наличие метода setShowBottom
        try {
            crystal.setShowingBottom(false);
        } catch (NoSuchMethodError e) {
            // Метод не поддерживается, пропускаем
            plugin.getLogger().warning("Метод 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();
                crystalHolder[0] = (EnderCrystal) world.spawn(crystalLoc, EnderCrystal.class);
                try {
                    crystalHolder[0].setShowingBottom(false);
                } catch (NoSuchMethodError e) {
                    // Метод не поддерживается, пропускаем
                    plugin.getLogger().warning("Метод 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);
                }
            }
        }.runTaskTimer(this.plugin, 0L, 1L);
    }

    /**
     * Создает эффекты суперновы после завершения анимации падения кристалла.
     *
     * @param world             Мир, в котором происходит взрыв.
     * @param explosionLocation Локация взрыва.
     */
    private void performSupernovaEffects(World world, Location explosionLocation) {
        // Расширяющийся взрыв суперновы
        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.explosionParticle, 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));
                    }
                    if (entity instanceof LivingEntity) {
                        Utils.pureDamageEntity((LivingEntity) entity, 20.0, "RocketPlugin-supernova", true, EntityDamageEvent.DamageCause.EXPLOSION);
                    }
                }

                currentRadius += step * particleMultiplier;
            }
        }.runTaskTimer(this.plugin, 0L, 2L); // Выполняется каждые 2 тика
    }
}
// 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.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);
            } 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).keySet()) {
                ItemStack stack = player.getInventory().getItem(item.getSlot());
                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(item.getSlot(), null);
                }
                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.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;
        }

        // Если взрыв вызван ракетою, разрешаем, иначе отменяем
        if (!(event.getEntity() instanceof Rocket)) {
            event.setCancelled(true);
        }
    }

    // Методы для обработки повреждений от ракет можно добавить по необходимости
}
// 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 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_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 = 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;
    }
}
// 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;

    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 был отключен!");
    }
}
// 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());
                    }
                }
            }
            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();
    }
}
// Utils.java
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 cause          Причина урона.
     * @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);
        }
    }
}
# RocketPlugin Configuration

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

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

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

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

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

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

# Настройки ракет
rockets:
  SMALL:
    power: 15.0          # Изменено с 10.0 до 15.0
    range: 120            # Изменено с 100 до 120
    launchParticle: FLAME
    launchSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionParticle: SMOKE_NORMAL
    successChance: 80    # Изменено с 70 до 80 для большей надежности
    optimized: false

  MEDIUM:
    power: 25.0          # Изменено с 15.0 до 25.0
    range: 180            # Изменено с 150 до 180
    launchParticle: FLAME
    launchSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionParticle: SMOKE_NORMAL
    successChance: 70    # Изменено с 65 до 70 для баланса
    optimized: false

  LARGE:
    power: 40.0          # Изменено с 20.0 до 40.0
    range: 250            # Изменено с 200 до 250
    launchParticle: EXPLOSION_NORMAL
    launchSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionParticle: SMOKE_LARGE
    successChance: 60    # Изменено с 55 до 60
    optimized: false

  EXTRA_LARGE:
    power: 60.0          # Изменено с 25.0 до 60.0
    range: 350            # Изменено с 300 до 350
    launchParticle: EXPLOSION_LARGE
    launchSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionSound: ENTITY_FIREWORK_ROCKET_LAUNCH
    explosionParticle: EXPLOSION_HUGE
    successChance: 55    # Изменено с 50 до 55
    optimized: false

  NUCLEAR:
    power: 100.0         # Изменено с 70.0 до 100.0
    range: 600            # Изменено с 500 до 600
    launchParticle: EXPLOSION_HUGE
    launchSound: ENTITY_GENERIC_EXPLODE
    explosionSound: ENTITY_GENERIC_EXPLODE
    explosionParticle: EXPLOSION_HUGE
    successChance: 50    # Изменено с 40 до 50
    optimized: false

  SUPER_NUCLEAR:
    power: 140.0         # Изменено с 100.0 до 140.0
    range: 850            # Изменено с 700 до 850
    launchParticle: EXPLOSION_HUGE
    launchSound: ENTITY_GENERIC_EXPLODE
    explosionSound: ENTITY_GENERIC_EXPLODE
    explosionParticle: EXPLOSION_HUGE
    successChance: 40    # Изменено с 35 до 40
    optimized: false

  MEGA_NUCLEAR:
    power: 200.0         # Изменено с 150.0 до 200.0
    range: 1200           # Изменено с 1000 до 1200
    launchParticle: EXPLOSION_HUGE
    launchSound: ENTITY_GENERIC_EXPLODE
    explosionSound: ENTITY_GENERIC_EXPLODE
    explosionParticle: EXPLOSION_HUGE
    successChance: 30    # Изменено с 25 до 30
    optimized: false

  EXTREME_NUCLEAR:
    power: 300.0         # Изменено с 250.0 до 300.0
    range: 1800           # Изменено с 1500 до 1800
    launchParticle: SUSPENDED
    launchSound: ENTITY_GENERIC_EXPLODE
    explosionSound: ENTITY_GENERIC_EXPLODE
    explosionParticle: EXPLOSION_HUGE
    successChance: 20    # Изменено с 15 до 20
    optimized: true

  ULTRA_NUCLEAR:
    power: 450.0         # Изменено с 400.0 до 450.0
    range: 2500           # Изменено с 2000 до 2500
    launchParticle: SPELL_INSTANT
    launchSound: ENTITY_GENERIC_EXPLODE
    explosionSound: ENTITY_GENERIC_EXPLODE
    explosionParticle: EXPLOSION_HUGE
    successChance: 10    # Без изменений
    optimized: true

# Рецепты крафта ракет
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
  # USSRRocket и OptimizedRocket были удалены
# plugin.yml
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








//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.github.jewishbanana.deadlydisasters.events.disasters;

import com.github.jewishbanana.deadlydisasters.events.DestructionDisaster;
import com.github.jewishbanana.deadlydisasters.events.DestructionDisasterEvent;
import com.github.jewishbanana.deadlydisasters.events.Disaster;
import com.github.jewishbanana.deadlydisasters.listeners.DeathMessages;
import com.github.jewishbanana.deadlydisasters.utils.Metrics;
import com.github.jewishbanana.deadlydisasters.utils.RepeatingTask;
import com.github.jewishbanana.deadlydisasters.utils.Utils;
import com.github.jewishbanana.deadlydisasters.utils.VersionUtils;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Random;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.block.Block;
import org.bukkit.entity.EnderCrystal;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.util.BlockVector;
import org.bukkit.util.Vector;

public class Supernova extends DestructionDisaster {
    private double size;
    private double sizeMultiplier;
    private double particleMultiplier;
    private double fallSpeedMultiplier;
    private int tick = 1;
    private EnderCrystal crystal;
    private Particle particle;
    private Material[] materials;
    private boolean flash;
    private boolean farParticles;
    private int blocksDestroyed;

    public Supernova(int level, World world) {
        super(level, world);
        switch (level) {
            case 1:
            default:
                this.size = 35.0;
                break;
            case 2:
                this.size = 45.0;
                break;
            case 3:
                this.size = 57.0;
                break;
            case 4:
                this.size = 70.0;
                break;
            case 5:
                this.size = 85.0;
                break;
            case 6:
                this.size = 100.0;
        }

        this.volume = this.configFile.getDouble("supernova.volume");
        this.particleMultiplier = this.configFile.getDouble("supernova.particle_multiplier");
        this.flash = this.configFile.getBoolean("supernova.flash");
        this.sizeMultiplier = this.configFile.getDouble("supernova.size");
        this.particle = VersionUtils.getLargeExplosion();
        this.materials = new Material[]{Material.OBSIDIAN, Material.BLACK_CONCRETE, Material.FIRE};
        if (!this.configFile.getBoolean("supernova.place_fire")) {
            this.materials = new Material[]{Material.OBSIDIAN, Material.BLACK_CONCRETE};
        }

        this.farParticles = this.configFile.getBoolean("supernova.far_particles");
        this.fallSpeedMultiplier = this.configFile.getDouble("supernova.fall_speed_multiplier");
        this.type = Disaster.SUPERNOVA;
    }

    public void start(final Location loc, Player p) {
        DestructionDisasterEvent event = new DestructionDisasterEvent(this, loc, this.level, p);
        Bukkit.getPluginManager().callEvent(event);
        if (!event.isCancelled()) {
            this.loc = loc;
            ongoingDisasters.add(this);
            DeathMessages.supernovas.add(this);
            this.size *= this.sizeMultiplier;
            final World world = loc.getWorld();
            final Location top = loc.clone();
            top.setY(320.0);
            final Location crystalLoc = top.clone();
            this.crystal = (EnderCrystal)world.spawn(crystalLoc, EnderCrystal.class);
            this.crystal.setShowingBottom(false);
            this.crystal.setBeamTarget(top);
            final Vector vec = new Vector(0.0, -2.0 * this.fallSpeedMultiplier, 0.0);
            RepeatingTask var10000 = new RepeatingTask(this.plugin, 0, 1) {
                public void run() {
                    crystalLoc.add(vec);
                    if (vec.getY() < -0.5) {
                        vec.setY(vec.getY() + 0.01);
                    }

                    Supernova.this.crystal.remove();
                    Supernova.this.crystal = (EnderCrystal)world.spawn(crystalLoc, EnderCrystal.class);
                    Supernova.this.crystal.setShowingBottom(false);
                    Supernova.this.crystal.setBeamTarget(top);
                    world.spawnParticle(Particle.CLOUD, crystalLoc, 10, 0.5, 0.5, 0.5, 0.01, (Object)null, true);
                    world.spawnParticle(Particle.FLAME, crystalLoc, 10, 0.5, 0.5, 0.5, 0.01, (Object)null, true);
                    Block b = crystalLoc.clone().subtract(0.0, 1.0, 0.0).getBlock();
                    if (b.getType() != Material.AIR && !Utils.isBlockImmune(b.getType()) && !Utils.isZoneProtected(b.getLocation())) {
                        if (Supernova.this.plugin.CProtect) {
                            Utils.getCoreProtect().logRemoval("Deadly-Disasters", b.getLocation(), b.getType(), b.getBlockData());
                        }

                        b.setType(Material.AIR);
                        ++Supernova.this.blocksDestroyed;
                    }

                    if (crystalLoc.distance(loc) < 3.0) {
                        Supernova.this.crystal.remove();
                        this.cancel();
                        Supernova.this.explode(world);
                    }

                    if (Supernova.this.flash) {
                        Iterator var3 = world.getNearbyEntities(loc, 140.0, 100.0, 140.0).iterator();

                        while(var3.hasNext()) {
                            Entity e = (Entity)var3.next();
                            if (e instanceof Player) {
                                Location temp = e.getLocation();
                                ((Player)e).spawnParticle(Particle.FLASH, temp.clone().add((new Vector(temp.getX() - crystalLoc.getX(), temp.getY() - crystalLoc.getY(), temp.getZ() - crystalLoc.getZ())).normalize().multiply(-3)), 1, 1.0, 1.0, 1.0, 0.001);
                            }
                        }
                    }

                }
            };
            var10000 = new RepeatingTask(this.plugin, 0, 10) {
                public void run() {
                    if (Supernova.this.tick > 1) {
                        this.cancel();
                    }

                    if (Supernova.this.plugin.mcVersion >= 1.16) {
                        Iterator var2 = world.getNearbyEntities(loc, 140.0, 140.0, 140.0).iterator();

                        while(var2.hasNext()) {
                            Entity e = (Entity)var2.next();
                            if (e instanceof Player) {
                                Location temp = e.getLocation();
                                ((Player)e).playSound(temp.clone().add((new Vector(temp.getX() - crystalLoc.getX(), temp.getY() - crystalLoc.getY(), temp.getZ() - crystalLoc.getZ())).normalize().multiply(-4)), Sound.AMBIENT_NETHER_WASTES_MOOD, (float)((2.0 - 0.002 * crystalLoc.distance(e.getLocation())) * Supernova.this.volume), 0.5F);
                            }
                        }
                    }

                }
            };
        }
    }

    private void explode(final World world) {
        final BlockVector block = new BlockVector(this.loc.getX(), this.loc.getY(), this.loc.getZ());
        final Random rand = new Random();
        final boolean CP = this.plugin.CProtect;
        final Supernova instance = this;
        RepeatingTask var10000 = new RepeatingTask(this.plugin, 0, 1) {
            public void run() {
                if ((double)Supernova.this.tick > Supernova.this.size) {
                    this.cancel();
                    Supernova.ongoingDisasters.remove(instance);
                    DeathMessages.supernovas.remove(instance);
                    Metrics.incrementValue(Metrics.disasterDestroyedMap, Supernova.this.type.getMetricsLabel(), Supernova.this.blocksDestroyed);
                } else {
                    final Set<Block> blocks = new LinkedHashSet(Supernova.this.tick * Supernova.this.tick * Supernova.this.tick);

                    for(int x = -Supernova.this.tick; x < Supernova.this.tick; ++x) {
                        for(int y = -Supernova.this.tick; y < Supernova.this.tick; ++y) {
                            for(int z = -Supernova.this.tick; z < Supernova.this.tick; ++z) {
                                Vector position = block.clone().add(new Vector(x, y, z));
                                if (block.distance(position) >= (double)(Supernova.this.tick - 1) && block.distance(position) <= (double)Supernova.this.tick) {
                                    Block b = world.getBlockAt(position.toLocation(world));
                                    blocks.add(b);
                                    if (b.getType() != Material.AIR && !Utils.isBlockImmune(b.getType()) && !Utils.isZoneProtected(b.getLocation())) {
                                        if (CP) {
                                            Utils.getCoreProtect().logRemoval("Deadly-Disasters", b.getLocation(), b.getType(), b.getBlockData());
                                        }

                                        if ((double)Supernova.this.tick > Supernova.this.size - 2.0 && rand.nextInt(8) == 0) {
                                            Material mat = Supernova.this.materials[rand.nextInt(Supernova.this.materials.length)];
                                            if (CP) {
                                                Utils.getCoreProtect().logPlacement("Deadly-Disasters", b.getLocation(), mat, mat.createBlockData());
                                            }

                                            b.setType(mat);
                                            ++Supernova.this.blocksDestroyed;
                                        } else {
                                            b.setType(Material.AIR);
                                            ++Supernova.this.blocksDestroyed;
                                        }
                                    }
                                }
                            }
                        }
                    }

                    ++Supernova.this.tick;
                    Supernova.this.plugin.getServer().getScheduler().runTaskAsynchronously(Supernova.this.plugin, new Runnable() {
                        public void run() {
                            int chance = (int)Math.ceil((double)(1 + blocks.size() / 1000) * Supernova.this.particleMultiplier);
                            Iterator var3 = blocks.iterator();

                            while(var3.hasNext()) {
                                Block b = (Block)var3.next();
                                if (rand.nextInt(chance) == 0) {
                                    world.spawnParticle(Supernova.this.particle, b.getLocation(), 1, 0.0, 0.0, 0.0, 1.0, (Object)null, Supernova.this.farParticles);
                                }
                            }

                        }
                    });
                }
            }
        };
        var10000 = new RepeatingTask(this.plugin, 0, 10) {
            public void run() {
                if ((double)Supernova.this.tick > Supernova.this.size) {
                    this.cancel();
                } else {
                    Iterator var2 = world.getNearbyEntities(Supernova.this.loc, (double)(Supernova.this.tick + 100), (double)(Supernova.this.tick + 100), (double)(Supernova.this.tick + 100)).iterator();

                    while(true) {
                        Entity e;
                        do {
                            do {
                                do {
                                    while(true) {
                                        do {
                                            do {
                                                if (!var2.hasNext()) {
                                                    return;
                                                }

                                                e = (Entity)var2.next();
                                            } while(!(e instanceof LivingEntity));
                                        } while(e.isDead());

                                        if (Supernova.this.loc.distance(e.getLocation()) < (double)Supernova.this.tick) {
                                            break;
                                        }

                                        if (e instanceof Player) {
                                            Location temp = e.getLocation().clone().add((new Vector(e.getLocation().getX() - Supernova.this.loc.getX(), e.getLocation().getY() - Supernova.this.loc.getY(), e.getLocation().getZ() - Supernova.this.loc.getZ())).normalize().multiply(-4));
                                            float vol = (float)((2.0 - (5.0E-4 * Supernova.this.loc.distance(e.getLocation()) - (double)Supernova.this.tick)) * Supernova.this.volume);
                                            if (Supernova.this.plugin.mcVersion >= 1.16) {
                                                ((Player)e).playSound(temp, Sound.AMBIENT_WARPED_FOREST_MOOD, vol, 0.5F);
                                            }

                                            ((Player)e).playSound(temp, Sound.ENTITY_LIGHTNING_BOLT_THUNDER, vol, 0.5F);
                                            ((Player)e).playSound(temp, Sound.ENTITY_DRAGON_FIREBALL_EXPLODE, vol / 30.0F, 0.5F);
                                        }
                                    }
                                } while(Supernova.this.isEntityTypeProtected(e));
                            } while(Utils.isZoneProtected(e.getLocation()));
                        } while(e instanceof Player && Utils.isPlayerImmune((Player)e));

                        Utils.pureDamageEntity((LivingEntity)e, 20.0, "dd-supernova", true, DamageCause.BLOCK_EXPLOSION);
                    }
                }
            }
        };
    }

    public void removeCrystal() {
        if (this.crystal != null) {
            this.crystal.remove();
        }

    }

    public Location findApplicableLocation(Location temp, Player p) {
        temp = Utils.getBlockBelow(temp).getLocation();
        return temp.getBlockY() >= this.type.getMinHeight() && temp.getWorld().getEnvironment() != Environment.NETHER ? temp : null;
    }

    public void startAdjustment(Location loc, Player p) {
        this.start(Utils.getBlockBelow(loc).getLocation(), p);
    }

    public double getSizeMultiplier() {
        return this.sizeMultiplier;
    }

    public void setSizeMultiplier(double sizeMultiplier) {
        this.sizeMultiplier = sizeMultiplier;
    }

    public Particle getParticle() {
        return this.particle;
    }

    public void setParticle(Particle particle) {
        this.particle = particle;
    }

    public Material[] getMaterials() {
        return this.materials;
    }

    public void setMaterials(Material[] materials) {
        this.materials = materials;
    }

    public boolean isFlash() {
        return this.flash;
    }

    public void setFlash(boolean flash) {
        this.flash = flash;
    }

    public double getParticles() {
        return this.particleMultiplier;
    }

    public void setParticles(double particles) {
        this.particleMultiplier = particles;
    }
}


Так, тут supernova есть, но посмотри, как там инициализируется падение (анимация перед взрывом), и собственно сам взрыв. Я хочу, чтобы в rocketplugin, ты заменил мой взрыв, на взрыв, который делает супернова (то есть супернова=ракета)