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

        // Логирование взрыва
        plugin.getRocketLogger().info("Normal explosion at " + explosionLocation.toString());

        // Создание анимации расширяющегося взрыва
        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);

        // Логирование взрыва суперновы
        plugin.getRocketLogger().info("Supernova explosion at " + explosionLocation.toString());

        // Создание EnderCrystal для анимации падения (имитация суперновы)
        EnderCrystal crystal = (EnderCrystal) world.spawn(explosionLocation, EnderCrystal.class);
        try {
            crystal.setShowingBottom(false);
        } catch (NoSuchMethodError e) {
            // Метод не поддерживается, пропускаем
            plugin.getRocketLogger().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.getRocketLogger().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.Sound;
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;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.ItemMeta;

import java.util.Map;

/**
 * Класс обработки команды /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|trade|remove|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 "trade":
                handleTrade(sender, args);
                break;
            case "remove":
                handleRemove(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|trade|remove|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() + ".");
        plugin.getRocketLogger().info("Gave " + amount + " rockets of type " + type.getName() + " to " + targetPlayer.getName() + " by " + sender.getName());
    }

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

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

        String fromName = args[1];
        String toName = args[2];
        Player fromPlayer = Bukkit.getPlayerExact(fromName);
        Player toPlayer = Bukkit.getPlayerExact(toName);

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

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

        String typeName = args[3].toUpperCase();
        RocketType type = rocketManager.getRocketType(typeName);
        if (type == null) {
            sender.sendMessage(ChatColor.RED + "§cНеверный тип ракеты.");
            return;
        }

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

        if (!statsManager.hasRockets(fromPlayer, type)) {
            sender.sendMessage(ChatColor.RED + "§cУ игрока " + fromPlayer.getName() + " недостаточно ракет типа " + type.getName() + ".");
            return;
        }

        int available = statsManager.getRockets(fromPlayer, type);
        if (available < amount) {
            sender.sendMessage(ChatColor.RED + "§cУ игрока " + fromPlayer.getName() + " недостаточно ракет. Имеется: " + available);
            return;
        }

        // Перевод ракет
        statsManager.useRocket(fromPlayer, type);
        statsManager.addRockets(toPlayer, type, amount);
        sender.sendMessage(ChatColor.GREEN + "§aПереведено " + amount + " ракет типа " + type.getName() + " от " + fromPlayer.getName() + " к " + toPlayer.getName() + ".");
        fromPlayer.sendMessage(ChatColor.GREEN + "§aВам перевели " + amount + " ракет типа " + type.getName() + ".");
        toPlayer.sendMessage(ChatColor.GREEN + "§aВам перевели " + amount + " ракет типа " + type.getName() + " от " + fromPlayer.getName() + ".");
        plugin.getRocketLogger().info("Traded " + amount + " rockets of type " + type.getName() + " from " + fromPlayer.getName() + " to " + toPlayer.getName());
    }

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

        if (args.length < 4) {
            sender.sendMessage(ChatColor.RED + "§cИспользование: /rocket remove <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Неверный тип ракеты.");
            return;
        }

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

        if (!statsManager.hasRockets(targetPlayer, type)) {
            sender.sendMessage(ChatColor.RED + "§cУ игрока " + targetPlayer.getName() + " нет ракет типа " + type.getName() + ".");
            return;
        }

        int available = statsManager.getRockets(targetPlayer, type);
        if (available < amount) {
            sender.sendMessage(ChatColor.RED + "§cУ игрока " + targetPlayer.getName() + " недостаточно ракет. Имеется: " + available);
            return;
        }

        // Удаление ракет
        for (int i = 0; i < amount; i++) {
            statsManager.useRocket(targetPlayer, type);
        }
        sender.sendMessage(ChatColor.GREEN + "§aУдалено " + amount + " ракет типа " + type.getName() + " у игрока " + targetPlayer.getName() + ".");
        targetPlayer.sendMessage(ChatColor.YELLOW + "§eУ вас удалено " + amount + " ракет типа " + type.getName() + ".");
        plugin.getRocketLogger().info("Removed " + amount + " rockets of type " + type.getName() + " from " + targetPlayer.getName() + " by " + 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(); // Перезагружаем типы ракет

        // Перезагрузка StatsManager (если необходимо)
        // statsManager.reload(); // Реализуйте метод reload() в StatsManager, если требуется

        sender.sendMessage(ChatColor.GREEN + "§aКонфигурация плагина успешно перезагружена.");
        plugin.getRocketLogger().info(sender.getName() + " reloaded the plugin configuration.");
    }

    /**
     * Обработка подкоманды 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;
        }

        // Проверка дневного лимита
        if (!statsManager.canCraft(player)) {
            player.sendMessage(ChatColor.RED + "§cВы достигли дневного лимита крафта ракет. Попробуйте завтра.");
            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;
        PlayerInventory inventory = player.getInventory();
        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 = inventory.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;

            // Iterate over a copy to avoid concurrent modification
            for (Map.Entry<Integer, ? extends ItemStack> entry : inventory.all(material).entrySet()) {
                if (removed >= required) break;
                int slot = entry.getKey();
                ItemStack stack = entry.getValue();
                if (stack == null || stack.getType() != material) continue;
                int toRemove = Math.min(stack.getAmount(), required - removed);
                stack.setAmount(stack.getAmount() - toRemove);
                removed += toRemove;
                if (stack.getAmount() <= 0) {
                    inventory.setItem(slot, null);
                }
            }
        }

        // Добавляем ракету в статистику
        statsManager.addRockets(player, type, 1);
        statsManager.incrementCraftCount(player);
        player.sendMessage(ChatColor.GREEN + "§aВы успешно произвели ракету типа " + type.getName() + ".");
        plugin.getRocketLogger().info(player.getName() + " crafted a rocket of type " + type.getName() + " at " + player.getLocation().toString());
    }
}
package com.yourname.rocketplugin;

import org.bukkit.World;
import org.bukkit.entity.Entity;
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) {
        Entity entity = event.getEntity();
        if (entity == null) return;

        World world = entity.getWorld();
        if (!world.getName().equalsIgnoreCase("P_Drilla")) { // Измените на нужное название мира
            event.setCancelled(true);
            return;
        }

        // Логирование взрыва
        plugin.getRocketLogger().info("Explosion occurred at " + event.getLocation().toString() + " in world " + world.getName());
    }
}
package com.yourname.rocketplugin;

import org.bukkit.World;
import org.bukkit.Location;
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.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 + " секунда(ы).");
            plugin.getRocketLogger().info("Rocket launch scheduled by " + player.getName() + " with delay " + delay + " seconds for type " + type.getName());
            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Ракета успешно запущена!");
                            plugin.getRocketLogger().info("Rocket launched by " + player.getName() + " of type " + type.getName() + " towards " + target.toString());
                        } else {
                            player.sendMessage("§cРакета не смогла достичь цели и не взорвалась.");
                            plugin.getRocketLogger().warning("Rocket launch failed for " + player.getName() + " of type " + type.getName() + " towards " + target.toString());
                        }
                    } 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Ракета успешно запущена!");
                plugin.getRocketLogger().info("Rocket launched by " + player.getName() + " of type " + type.getName() + " towards " + target.toString());
            } else {
                player.sendMessage("§cРакета не смогла достичь цели и не взорвалась.");
                plugin.getRocketLogger().warning("Rocket launch failed for " + player.getName() + " of type " + type.getName() + " towards " + target.toString());
            }
        }
    }

    /**
     * Проверяет вероятность успешного запуска ракеты.
     *
     * @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;

import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

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

    public RocketPlugin() { }

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

    public RocketManager getRocketManager() {
        return rocketManager;
    }

    public StatsManager getStatsManager() {
        return statsManager;
    }

    public Logger getRocketLogger() {
        return rocketLogger;
    }

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

        // Инициализация логгера
        setupLogger();

        // Инициализация 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();
        }

        if (this.rocketLogger != null) {
            for (Handler handler : this.rocketLogger.getHandlers()) {
                handler.close();
            }
        }

        this.getLogger().info("§cRocketPlugin был отключен!");
    }

    /**
     * Настраивает отдельный логгер для RocketPlugin.
     */
    private void setupLogger() {
        rocketLogger = Logger.getLogger("RocketPluginLogger");
        rocketLogger.setUseParentHandlers(false); // Отключаем вывод в консоль

        try {
            FileHandler fh = new FileHandler(getDataFolder() + "/rocketplugin.log", true);
            fh.setFormatter(new SimpleFormatter());
            rocketLogger.addHandler(fh);
        } catch (IOException e) {
            this.getLogger().severe("§cНе удалось настроить логгер RocketPlugin: " + e.getMessage());
        }
    }
}
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", "trade", "remove", "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") || subcommand.equals("remove") || subcommand.equals("trade")) {
                Map<String, RocketType> types = rocketManager.getAllRocketTypes();
                for (RocketType type : types.values()) {
                    if (type.getName().toLowerCase().startsWith(args[1].toLowerCase())) {
                        completions.add(type.getName());
                    }
                }
            } else if (subcommand.equals("stats")) {
                for (Player player : Bukkit.getOnlinePlayers()) {
                    if (player.getName().toLowerCase().startsWith(args[1].toLowerCase())) {
                        completions.add(player.getName());
                    }
                }
            } else if (subcommand.equals("trade")) {
                for (Player player : Bukkit.getOnlinePlayers()) {
                    if (player.getName().toLowerCase().startsWith(args[1].toLowerCase())) {
                        completions.add(player.getName());
                    }
                }
            }
            return completions;
        }

        if (args.length == 3) {
            String subcommand = args[0].toLowerCase();
            if (subcommand.equals("trade")) {
                for (Player player : Bukkit.getOnlinePlayers()) {
                    if (player.getName().toLowerCase().startsWith(args[2].toLowerCase())) {
                        completions.add(player.getName());
                    }
                }
            } else if (subcommand.equals("give") || subcommand.equals("remove") || subcommand.equals("craft")) {
                RocketManager rocketManager = plugin.getRocketManager();
                Map<String, RocketType> types = rocketManager.getAllRocketTypes();
                for (RocketType type : types.values()) {
                    if (type.getName().toLowerCase().startsWith(args[2].toLowerCase())) {
                        completions.add(type.getName());
                    }
                }
            }
            return completions;
        }

        if (args.length == 4) {
            String subcommand = args[0].toLowerCase();
            if (subcommand.equals("trade") || subcommand.equals("give") || subcommand.equals("remove")) {
                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 org.bukkit.scheduler.BukkitRunnable;

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

/**
 * Класс для управления статистикой игроков по ракетам и крафту.
 */
public class StatsManager {
    private final RocketPlugin plugin;
    private final File statsFile;
    private FileConfiguration statsConfig;
    private final RocketManager rocketManager;
    private final Map<String, Integer> dailyCraftCounts; // Индекс по UUID игрока

    /**
     * Конструктор 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);
        this.dailyCraftCounts = new HashMap<>();

        // Запуск задачи для сброса ежедневных крафтов
        resetDailyCraftCounts();
    }

    /**
     * Загружает статистику из файла.
     */
    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");
        }

        sb.append("§aРакет произведено сегодня: §b").append(getDailyCraftCount(player)).append("\n");
        return sb.toString();
    }

    /**
     * Проверяет, может ли игрок крафтить ракету (лимит не превышен).
     *
     * @param player Игрок.
     * @return true, если можно.
     */
    public boolean canCraft(Player player) {
        int dailyLimit = plugin.getConfig().getInt("craftingLimits.dailyLimit", 10);
        String uuid = player.getUniqueId().toString();
        return getDailyCraftCount(player) < dailyLimit;
    }

    /**
     * Увеличивает счётчик крафтов для игрока.
     *
     * @param player Игрок.
     */
    public void incrementCraftCount(Player player) {
        String uuid = player.getUniqueId().toString();
        int current = getDailyCraftCount(player);
        dailyCraftCounts.put(uuid, current + 1);
    }

    /**
     * Получает текущее количество крафтов, выполненных игроком сегодня.
     *
     * @param player Игрок.
     * @return Количество крафтов.
     */
    public int getDailyCraftCount(Player player) {
        String uuid = player.getUniqueId().toString();
        return dailyCraftCounts.getOrDefault(uuid, 0);
    }

    /**
     * Сброс ежедневных счётчиков крафтов.
     */
    private void resetDailyCraftCounts() {
        // Запланировать запуск сброса в полночь каждую ночь
        // Для упрощения сброс будет выполнен через 1 минуту после запуска плагина и повторяться каждые 24 часа
        new BukkitRunnable() {
            @Override
            public void run() {
                dailyCraftCounts.clear();
                plugin.getRocketLogger().info("Daily crafting counts have been reset.");
            }
        }.runTaskTimer(plugin, 1200L, 1728000L); // Запуск через 1 мин и повтор каждые 24 часа
    }
}
package com.yourname.rocketplugin;

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

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

# Рецепты крафта ракет
craftingRecipes:
  SMALL_SUPERNOVA:
    ingredients:
      GRAY_WOOL: 5
      FIRE_CHARGE: 2
      LETTER_L: 1
      NETHER_BRICK: 3
      GLOWSTONE_DUST: 2

  MEDIUM_SUPERNOVA:
    ingredients:
      BLACK_WOOL: 10
      FIRE_CHARGE: 5
      LETTER_M: 1
      NETHER_STAR: 1
      REDSTONE: 4

  LARGE_SUPERNOVA:
    ingredients:
      RED_WOOL: 15
      FIRE_CHARGE: 10
      LETTER_LARGE: 1
      BEACON: 1
      EMERALD: 5

# Лимиты крафта
craftingLimits:
  dailyLimit: 1

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

Сделай 1) По русски
2) Сделай, чтобы супернова взрывала область
3) Усложни крафт (и скажи, что нужно для него)
4) Улучши и напиши полный код