Более Сложные Визуальные Эффекты: Использовать разнообразные типы частиц или добавлять анимацию для более реалистичного отображения радиационных зон.
Поддержка Разных Миров: Позволить создавать радиационные зоны в разных мирах сервера, добавив параметр мира в конфигурацию зон.
Настраиваемые Сообщения: Сделать сообщения для игроков и логов настраиваемыми через config.yml для большей гибкости.
Также у каждого противогаза, в лоре, было написано, сколько там осталось прочности

Cannot resolve method 'getMatrix' in 'Inventory'

package com.yourpackage;

import org.bukkit.*;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.CraftItemEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.inventory.*;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;

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

public class RadiationPlugin extends JavaPlugin implements CommandExecutor, TabCompleter, Listener {

    // Хранение активных радиационных зон по имени
    private final Map<String, RadiationZone> zones = new HashMap<>();

    // Хранение маппинга уровней радиации и соответствующих эффектов, отсортированных по убыванию
    private final TreeMap<Integer, EffectMapping> effectMappings = new TreeMap<>(Collections.reverseOrder());

    // Отслеживание зон, в которых находится каждый игрок
    private final Map<UUID, Set<String>> playerZones = new HashMap<>();

    // Хранение уровней радиации для каждого игрока
    private final Map<UUID, Integer> playerRadiationLevels = new HashMap<>();

    // Хранение уровней противогаза для каждого игрока
    private final Map<UUID, Integer> playerGasMaskLevels = new HashMap<>();

    // Файлы для хранения данных игроков
    private File playerDataFile;
    private FileConfiguration playerDataConfig;

    private FileConfiguration config;

    @Override
    public void onEnable() {
        // Сохранение и загрузка стандартного конфигурационного файла, если он отсутствует
        saveDefaultConfig();
        config = getConfig();

        // Загрузка маппинга эффектов
        loadEffectMappings();

        // Загрузка радиационных зон из конфигурации
        loadRadiationZones();

        // Инициализация файла данных игроков
        initPlayerData();

        // Регистрация команд и обработчиков событий
        getCommand("radiationzone").setExecutor(this);
        getCommand("radiationzone").setTabCompleter(this);
        getCommand("radiationcheck").setExecutor(this);
        Bukkit.getPluginManager().registerEvents(this, this);

        // Регистрация рецептов крафта
        registerRecipes();

        // Запуск задачи для проверки игроков в радиационных зонах
        startRadiationCheckerTask();

        getLogger().info("RadiationPlugin включен!");
    }

    @Override
    public void onDisable() {
        // Сохранение радиационных зон в конфигурации при отключении плагина
        saveRadiationZones();

        // Сохранение данных игроков
        savePlayerData();

        getLogger().info("RadiationPlugin выключен!");
    }

    /**
     * Инициализация файла данных игроков.
     */
    private void initPlayerData() {
        playerDataFile = new File(getDataFolder(), "playerData.yml");
        if (!playerDataFile.exists()) {
            playerDataFile.getParentFile().mkdirs();
            saveResource("playerData.yml", false);
        }

        playerDataConfig = new YamlConfiguration();
        try {
            playerDataConfig.load(playerDataFile);
        } catch (IOException | InvalidConfigurationException e) {
            getLogger().severe("Не удалось загрузить playerData.yml");
            e.printStackTrace();
        }

        // Загрузка данных из файла
        for (String uuidString : playerDataConfig.getKeys(false)) {
            UUID uuid = UUID.fromString(uuidString);
            ConfigurationSection section = playerDataConfig.getConfigurationSection(uuidString);
            if (section != null) {
                int radiation = section.getInt("radiation", 0);
                int gasMask = section.getInt("gasMaskLevel", 0);
                playerRadiationLevels.put(uuid, radiation);
                playerGasMaskLevels.put(uuid, gasMask);
            }
        }
    }

    /**
     * Сохранение данных игроков в файл.
     */
    private void savePlayerData() {
        for (Map.Entry<UUID, Integer> entry : playerRadiationLevels.entrySet()) {
            UUID uuid = entry.getKey();
            int radiation = entry.getValue();
            int gasMask = playerGasMaskLevels.getOrDefault(uuid, 0);

            ConfigurationSection section = playerDataConfig.createSection(uuid.toString());
            section.set("radiation", radiation);
            section.set("gasMaskLevel", gasMask);
        }

        try {
            playerDataConfig.save(playerDataFile);
        } catch (IOException e) {
            getLogger().severe("Не удалось сохранить playerData.yml");
            e.printStackTrace();
        }
    }

    /**
     * Загрузка маппинга эффектов из конфигурации.
     */
    private void loadEffectMappings() {
        ConfigurationSection section = config.getConfigurationSection("effect_mappings");
        if (section != null) {
            for (String key : section.getKeys(false)) {
                try {
                    int threshold = Integer.parseInt(key);
                    ConfigurationSection mappingSection = section.getConfigurationSection(key);
                    if (mappingSection != null) {
                        int duration = mappingSection.getInt("duration", 40);
                        int amplifier = mappingSection.getInt("amplifier", 1);
                        List<String> effects = mappingSection.getStringList("effects");
                        effectMappings.put(threshold, new EffectMapping(duration, amplifier, effects));
                    } else {
                        getLogger().warning("Отсутствует секция для порога радиации: " + key);
                    }
                } catch (NumberFormatException e) {
                    getLogger().warning("Неверный порог уровня радиации: " + key);
                }
            }
        } else {
            getLogger().warning("Отсутствует секция effect_mappings в config.yml!");
        }
    }

    /**
     * Загрузка радиационных зон из конфигурации.
     */
    private void loadRadiationZones() {
        ConfigurationSection zonesSection = config.getConfigurationSection("radiation_zones");
        if (zonesSection != null) {
            for (String zoneName : zonesSection.getKeys(false)) {
                ConfigurationSection zoneConfig = zonesSection.getConfigurationSection(zoneName);
                if (zoneConfig != null) {
                    double minX = zoneConfig.getDouble("min_x");
                    double minY = zoneConfig.getDouble("min_y");
                    double minZ = zoneConfig.getDouble("min_z");
                    double maxX = zoneConfig.getDouble("max_x");
                    double maxY = zoneConfig.getDouble("max_y");
                    double maxZ = zoneConfig.getDouble("max_z");
                    int radiation = zoneConfig.getInt("radiation", 100);
                    int duration = zoneConfig.getInt("duration", 600); // Продолжительность в секундах

                    // Проверка корректности координат
                    if (minX >= maxX || minY >= maxY || minZ >= maxZ) {
                        getLogger().warning("Некорректные координаты для зоны: " + zoneName + ". Зона будет пропущена.");
                        continue;
                    }

                    // Проверка на перекрытие с существующими зонами
                    boolean overlaps = false;
                    for (RadiationZone existingZone : zones.values()) {
                        if (existingZone.overlapsWith(minX, minY, minZ, maxX, maxY, maxZ)) {
                            getLogger().warning("Зона " + zoneName + " перекрывается с зоной " + existingZone.getName() + ". Зона будет пропущена.");
                            overlaps = true;
                            break;
                        }
                    }
                    if (overlaps) continue;

                    RadiationZone zone = new RadiationZone(zoneName, minX, minY, minZ, maxX, maxY, maxZ, radiation, duration);
                    zones.put(zoneName, zone);
                }
            }
        }
    }

    /**
     * Сохранение радиационных зон в конфигурацию.
     */
    private void saveRadiationZones() {
        ConfigurationSection zonesSection = config.getConfigurationSection("radiation_zones");
        if (zonesSection == null) {
            zonesSection = config.createSection("radiation_zones");
        } else {
            // Очистить существующие зоны
            for (String zoneName : zonesSection.getKeys(false)) {
                zonesSection.set(zoneName, null);
            }
        }

        for (RadiationZone zone : zones.values()) {
            ConfigurationSection zoneConfig = zonesSection.createSection(zone.getName());
            zoneConfig.set("min_x", zone.minX);
            zoneConfig.set("min_y", zone.minY);
            zoneConfig.set("min_z", zone.minZ);
            zoneConfig.set("max_x", zone.maxX);
            zoneConfig.set("max_y", zone.maxY);
            zoneConfig.set("max_z", zone.maxZ);
            zoneConfig.set("radiation", zone.radiation);
            zoneConfig.set("duration", zone.duration);
        }

        saveConfig();
    }

    /**
     * Регистрация рецептов крафта для противогаза.
     */
    private void registerRecipes() {
        // Создание противогаза I
        ItemStack gasMask1 = createCustomItem(Material.LEATHER_HELMET, ChatColor.AQUA + "Противогаз I",
                Arrays.asList(ChatColor.GRAY + "Защищает от радиации (800 радиации)"));
        NamespacedKey gasMaskKey1 = new NamespacedKey(this, "gas_mask_level_1");
        ShapedRecipe gasMaskRecipe1 = new ShapedRecipe(gasMaskKey1, gasMask1);
        gasMaskRecipe1.shape(" I ", "IRI", "RIR");
        gasMaskRecipe1.setIngredient('I', Material.IRON_INGOT);
        gasMaskRecipe1.setIngredient('R', Material.REDSTONE);
        Bukkit.addRecipe(gasMaskRecipe1);

        // Создание противогаза II
        ItemStack gasMask2 = createCustomItem(Material.LEATHER_HELMET, ChatColor.DARK_AQUA + "Противогаз II",
                Arrays.asList(ChatColor.GRAY + "Защищает от радиации (2400 радиации)"));
        NamespacedKey gasMaskKey2 = new NamespacedKey(this, "gas_mask_level_2");
        ShapedRecipe gasMaskRecipe2 = new ShapedRecipe(gasMaskKey2, gasMask2);
        gasMaskRecipe2.shape(" I ", "IDI", "RIR");
        gasMaskRecipe2.setIngredient('I', Material.DIAMOND);
        gasMaskRecipe2.setIngredient('D', Material.DIAMOND);
        gasMaskRecipe2.setIngredient('R', Material.REDSTONE);
        Bukkit.addRecipe(gasMaskRecipe2);

        // Создание противогаза III
        ItemStack gasMask3 = createCustomItem(Material.LEATHER_HELMET, ChatColor.BLUE + "Противогаз III",
                Arrays.asList(ChatColor.GRAY + "Защищает от радиации (4800 радиации)"));
        NamespacedKey gasMaskKey3 = new NamespacedKey(this, "gas_mask_level_3");
        ShapedRecipe gasMaskRecipe3 = new ShapedRecipe(gasMaskKey3, gasMask3);
        gasMaskRecipe3.shape(" I ", "INI", "RIR");
        gasMaskRecipe3.setIngredient('I', Material.NETHERITE_INGOT);
        gasMaskRecipe3.setIngredient('N', Material.NETHER_STAR);
        gasMaskRecipe3.setIngredient('R', Material.REDSTONE);
        Bukkit.addRecipe(gasMaskRecipe3);

        getLogger().info("Рецепты противогазов зарегистрированы.");
    }

    /**
     * Вспомогательный метод для создания настраиваемого предмета с именем и лором.
     *
     * @param material Материал предмета
     * @param name     Отображаемое имя предмета
     * @param lore     Лор предмета (может быть null)
     * @return Настроенный ItemStack
     */
    private ItemStack createCustomItem(Material material, String name, List<String> lore) {
        ItemStack item = new ItemStack(material);
        if (name != null || lore != null) {
            ItemMeta meta = item.getItemMeta();
            if (meta != null) {
                if (name != null) {
                    meta.setDisplayName(name);
                }
                if (lore != null) {
                    meta.setLore(lore);
                }
                meta.setUnbreakable(true); // Сделаем противогаз неразрушимым
                item.setItemMeta(meta);
            }
        }
        return item;
    }

    /**
     * Обработка команд плагина.
     */
    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {

        // Обработка команды /radiationcheck
        if (command.getName().equalsIgnoreCase("radiationcheck")) {
            if (!sender.hasPermission("radiationplugin.radiationcheck")) {
                sender.sendMessage(ChatColor.RED + "У вас нет прав для выполнения этой команды.");
                return true;
            }

            if (!(sender instanceof Player)) {
                sender.sendMessage("Эта команда может использоваться только игроками.");
                return true;
            }

            Player player = (Player) sender;
            int totalRadiation = getPlayerTotalRadiation(player);
            player.sendMessage(ChatColor.YELLOW + "Ваш суммарный уровень радиации: " + totalRadiation);
            return true;
        }

        // Обработка команды /radiationzone
        if (command.getName().equalsIgnoreCase("radiationzone")) {
            if (!sender.hasPermission("radiationplugin.radiationzone")) {
                sender.sendMessage(ChatColor.RED + "У вас нет прав для выполнения этой команды.");
                return true;
            }

            if (!(sender instanceof Player)) {
                sender.sendMessage("Эта команда может использоваться только игроками.");
                return true;
            }

            Player player = (Player) sender;

            if (args.length == 0) {
                player.sendMessage(ChatColor.RED + "Использование: /radiationzone <create|delete|list|info>");
                return true;
            }

            switch (args[0].toLowerCase()) {
                case "create":
                    return handleCreateZone(player, args);
                case "delete":
                    return handleDeleteZone(player, args);
                case "list":
                    return handleListZones(player);
                case "info":
                    return handleInfoZone(player, args);
                default:
                    player.sendMessage(ChatColor.RED + "Неверная подкоманда. Используйте: create, delete, list, info");
                    return true;
            }
        }

        // Необработанная команда
        return false;
    }

    /**
     * Обработка создания радиационной зоны.
     *
     * @param player Игрок, выполняющий команду
     * @param args   Аргументы команды
     * @return true
     */
    private boolean handleCreateZone(Player player, String[] args) {
        if (args.length != 10) { // /radiationzone create <name> <min.x> <min.y> <min.z> <max.x> <max.y> <max.z> <duration_sec> <radiation>
            player.sendMessage(ChatColor.RED + "Использование: /radiationzone create <название> <min.x> <min.y> <min.z> <max.x> <max.y> <max.z> <duration_sec> <radiation>");
            return true;
        }

        try {
            String name = args[1];
            double minX = Double.parseDouble(args[2]);
            double minY = Double.parseDouble(args[3]);
            double minZ = Double.parseDouble(args[4]);
            double maxX = Double.parseDouble(args[5]);
            double maxY = Double.parseDouble(args[6]);
            double maxZ = Double.parseDouble(args[7]);
            int duration = Integer.parseInt(args[8]); // Продолжительность в секундах
            int radiation = Integer.parseInt(args[9]); // Уровень радиации

            // Проверка продолжительности радиации
            if (duration <= 0) {
                player.sendMessage(ChatColor.RED + "Продолжительность должна быть положительным числом секунд.");
                return true;
            }

            // Проверка радиации
            if (radiation <= 0) {
                player.sendMessage(ChatColor.RED + "Уровень радиации должен быть положительным числом.");
                return true;
            }

            // Проверка на существование зоны с таким именем
            if (zones.containsKey(name)) {
                player.sendMessage(ChatColor.RED + "Радиационная зона с таким названием уже существует.");
                return true;
            }

            // Проверка корректности координат
            if (minX >= maxX || minY >= maxY || minZ >= maxZ) {
                player.sendMessage(ChatColor.RED + "Некорректные координаты. min_* должны быть меньше max_*.");
                return true;
            }

            // Проверка на перекрытие с существующими зонами
            for (RadiationZone existingZone : zones.values()) {
                if (existingZone.overlapsWith(minX, minY, minZ, maxX, maxY, maxZ)) {
                    player.sendMessage(ChatColor.RED + "Зона перекрывается с существующей зоной: " + existingZone.getName());
                    return true;
                }
            }

            // Создание и добавление зоны
            RadiationZone zone = new RadiationZone(name, minX, minY, minZ, maxX, maxY, maxZ, radiation, duration);
            zones.put(name, zone);
            saveRadiationZones();

            player.sendMessage(ChatColor.GREEN + "Радиационная зона '" + name + "' успешно создана.");
            Bukkit.broadcastMessage(ChatColor.GOLD + "Создана новая радиационная зона: " + ChatColor.YELLOW + name);
            visualizeZone(zone.getName());

        } catch (NumberFormatException e) {
            player.sendMessage(ChatColor.RED + "Ошибка: убедитесь, что координаты, продолжительность и уровень радиации указаны числами.");
            getLogger().warning("NumberFormatException при создании зоны: " + Arrays.toString(args));
            return true;
        } catch (ArrayIndexOutOfBoundsException e) {
            player.sendMessage(ChatColor.RED + "Недостаточно аргументов. Используйте: /radiationzone create <название> <min.x> <min.y> <min.z> <max.x> <max.y> <max.z> <duration_sec> <radiation>");
            return true;
        } catch (Exception e) {
            player.sendMessage(ChatColor.RED + "Произошла непредвиденная ошибка при создании зоны.");
            e.printStackTrace();
            return true;
        }

        return true;
    }

    /**
     * Обработка удаления радиационной зоны.
     *
     * @param player Игрок, выполняющий команду
     * @param args   Аргументы команды
     * @return true
     */
    private boolean handleDeleteZone(Player player, String[] args) {
        if (args.length != 2) { // /radiationzone delete <name>
            player.sendMessage(ChatColor.RED + "Использование: /radiationzone delete <имя>");
            return true;
        }

        String name = args[1];
        RadiationZone zone = zones.get(name);
        if (zone == null) {
            player.sendMessage(ChatColor.RED + "Радиационная зона с названием '" + name + "' не найдена.");
            return true;
        }

        zones.remove(name);
        saveRadiationZones();
        player.sendMessage(ChatColor.GREEN + "Радиационная зона '" + name + "' успешно удалена.");
        Bukkit.broadcastMessage(ChatColor.GOLD + "Радиационная зона была удалена: " + ChatColor.YELLOW + name);
        return true;
    }

    /**
     * Обработка отображения списка радиационных зон.
     *
     * @param player Игрок, выполняющий команду
     * @return true
     */
    private boolean handleListZones(Player player) {
        if (zones.isEmpty()) {
            player.sendMessage(ChatColor.YELLOW + "Нет активных радиационных зон.");
            return true;
        }

        player.sendMessage(ChatColor.GOLD + "Список активных радиационных зон:");
        for (RadiationZone zone : zones.values()) {
            player.sendMessage(ChatColor.GRAY + "- " + zone.getName() + " (Радиация: " + zone.radiation + ", Осталось: " + zone.getRemainingTime() + " сек)");
        }
        return true;
    }

    /**
     * Обработка отображения информации о конкретной радиационной зоне.
     *
     * @param player Игрок, выполняющий команду
     * @param args   Аргументы команды
     * @return true
     */
    private boolean handleInfoZone(Player player, String[] args) {
        if (args.length != 2) { // /radiationzone info <name>
            player.sendMessage(ChatColor.RED + "Использование: /radiationzone info <имя>");
            return true;
        }

        String name = args[1];
        RadiationZone zone = zones.get(name);
        if (zone == null) {
            player.sendMessage(ChatColor.RED + "Радиационная зона с названием '" + name + "' не найдена.");
            return true;
        }

        player.sendMessage(ChatColor.GOLD + "Информация о радиационной зоне '" + name + "':");
        player.sendMessage(ChatColor.WHITE + "Координаты: [" + zone.minX + ", " + zone.minY + ", " + zone.minZ + "] до [" + zone.maxX + ", " + zone.maxY + ", " + zone.maxZ + "]");
        player.sendMessage(ChatColor.WHITE + "Уровень радиации: " + zone.radiation);
        player.sendMessage(ChatColor.WHITE + "Осталось времени: " + zone.getRemainingTime() + " сек");
        return true;
    }

    /**
     * Запуск периодической задачи для проверки игроков в радиационных зонах.
     */
    private void startRadiationCheckerTask() {
        // Запуск задачи каждую секунду (20 тиков)
        new BukkitRunnable() {
            @Override
            public void run() {
                long currentTime = System.currentTimeMillis() / 1000; // Текущее время в секундах

                // Создание копии ключей для безопасного удаления во время итерации
                Set<String> zoneNames = new HashSet<>(zones.keySet());

                for (String zoneName : zoneNames) {
                    RadiationZone zone = zones.get(zoneName);
                    if (zone == null) continue;

                    // Проверка, истёкло ли время действия зоны
                    if (currentTime >= zone.endTime) {
                        zones.remove(zoneName);
                        saveRadiationZones();
                        Bukkit.broadcastMessage(ChatColor.GOLD + "Радиационная зона '" + zoneName + "' истекла и была удалена.");
                        continue;
                    }

                    // Визуализация зоны
                    // Визуализация оптимизирована для уменьшения количества частиц
                    // visualizeZone(zoneName); // Можно отключить, если это влияет на производительность
                }

                // Проверка каждого игрока на нахождение в радиационных зонах
                for (Player player : Bukkit.getOnlinePlayers()) {
                    Location loc = player.getLocation();
                    UUID playerId = player.getUniqueId();
                    Set<String> currentZones = new HashSet<>();

                    // Определение зон, в которых находится игрок
                    for (RadiationZone zone : zones.values()) {
                        if (zone.isInZone(loc)) {
                            currentZones.add(zone.getName());
                        }
                    }

                    Set<String> previousZones = playerZones.getOrDefault(playerId, new HashSet<>());

                    // Определение вошел/вышел из зон
                    Set<String> enteredZones = new HashSet<>(currentZones);
                    enteredZones.removeAll(previousZones);

                    Set<String> exitedZones = new HashSet<>(previousZones);
                    exitedZones.removeAll(currentZones);

                    // Обновление текущих зон
                    playerZones.put(playerId, currentZones);

                    // Уведомление о входе в новые зоны
                    for (String zoneName : enteredZones) {
                        player.sendMessage(ChatColor.GREEN + "Вы вошли в радиационную зону: " + ChatColor.YELLOW + zoneName);
                        // Визуализация частиц при входе
                        visualizeZone(zoneName);
                    }

                    // Уведомление о выходе из зон
                    for (String zoneName : exitedZones) {
                        player.sendMessage(ChatColor.RED + "Вы покинули радиационную зону: " + ChatColor.YELLOW + zoneName);
                    }

                    // Расчёт суммарной радиации
                    int totalRadiation = 0;
                    for (String zoneName : currentZones) {
                        RadiationZone zone = zones.get(zoneName);
                        if (zone != null) {
                            totalRadiation += zone.radiation;
                        }
                    }

                    // Обработка радиации
                    if (totalRadiation > 0) {
                        if (isWearingGasMask(player)) {
                            int maskLevel = getPlayerGasMaskLevel(player);
                            // Абсорбация радиации
                            int absorbedRadiation = maskLevel;
                            totalRadiation -= absorbedRadiation;
                            if (totalRadiation < 0) totalRadiation = 0;
                            addPlayerRadiation(player, absorbedRadiation);
                            player.sendMessage(ChatColor.AQUA + "Ваш противогаз абсорбировал " + absorbedRadiation + " ед. радиации.");
                        } else {
                            // Увеличение радиации без противогаза
                            int radiationIncrease = getRadiationChange();
                            addPlayerRadiation(player, radiationIncrease);
                            player.sendMessage(ChatColor.YELLOW + "На вас накладывается " + radiationIncrease + " ед. радиации.");
                        }
                    } else {
                        // Постепенное снижение радиации, если игрок не в зоне
                        int currentRadiation = getPlayerTotalRadiation(player);
                        if (currentRadiation > 0) {
                            int radiationDecrease = getRadiationChange();
                            removePlayerRadiation(player, radiationDecrease);
                            player.sendMessage(ChatColor.GREEN + "Ваша радиация уменьшилась на " + radiationDecrease + " ед.");
                        }
                    }

                    // Применение эффектов радиации
                    int playerRadiation = getPlayerTotalRadiation(player);
                    applyRadiationEffects(player, playerRadiation);
                }
            }
        }.runTaskTimer(this, 0L, 20L); // Каждую секунду (20 тиков)
    }

    /**
     * Визуализация радиационной зоны с помощью частиц.
     *
     * @param zoneName Имя радиационной зоны
     */
    private void visualizeZone(String zoneName) {
        RadiationZone zone = zones.get(zoneName);
        if (zone == null) return;

        Bukkit.getScheduler().runTaskLater(this, () -> {
            World world = zone.getWorld();
            if (world == null) return;

            // Оптимизированная визуализация с уменьшенным количеством частиц
            double step = 5.0; // Увеличен шаг для уменьшения количества частиц
            Particle particleType = Particle.REDSTONE;
            Particle.DustOptions dustOptions = new Particle.DustOptions(Color.fromRGB(128, 0, 128), 0.5F);

            // Передняя и задняя стенки
            for (double y = zone.minY; y <= zone.maxY; y += step) {
                Location locFront = new Location(world, zone.minX, y, zone.minZ);
                Location locBack = new Location(world, zone.maxX, y, zone.maxZ);
                world.spawnParticle(particleType, locFront, 1, dustOptions);
                world.spawnParticle(particleType, locBack, 1, dustOptions);
            }

            // Левая и правая стенки
            for (double z = zone.minZ; z <= zone.maxZ; z += step) {
                Location locLeft = new Location(world, zone.minX, zone.minY, z);
                Location locRight = new Location(world, zone.maxX, zone.maxY, z);
                world.spawnParticle(particleType, locLeft, 1, dustOptions);
                world.spawnParticle(particleType, locRight, 1, dustOptions);
            }

            // Верхняя и нижняя стенки
            for (double x = zone.minX; x <= zone.maxX; x += step) {
                Location locBottom = new Location(world, x, zone.minY, zone.minZ);
                Location locTop = new Location(world, x, zone.maxY, zone.maxZ);
                world.spawnParticle(particleType, locBottom, 1, dustOptions);
                world.spawnParticle(particleType, locTop, 1, dustOptions);
            }

            // Центральная область с частицами для дополнительного эффекта
            int particleDensity = 5; // Уменьшено количество частиц
            for (int i = 0; i < particleDensity; i++) {
                double x = zone.minX + Math.random() * (zone.maxX - zone.minX);
                double y = zone.minY + Math.random() * (zone.maxY - zone.minY);
                double z = zone.minZ + Math.random() * (zone.maxZ - zone.minZ);
                Location loc = new Location(world, x, y, z);
                world.spawnParticle(Particle.CRIT, loc, 0, 0, 0, 0, 1);
            }
        }, 0L); // Запускается сразу
    }

    /**
     * Обработка событий крафта для проверки наличия предыдущих уровней противогаза.
     *
     * @param event Событие крафта предмета
     */
    @EventHandler
    public void onCraftItem(CraftItemEvent event) {
        if (event.getRecipe() instanceof ShapedRecipe) {
            ShapedRecipe recipe = (ShapedRecipe) event.getRecipe();
            ItemStack result = recipe.getResult();
            if (result.hasItemMeta() && result.getItemMeta().hasDisplayName()) {
                String name = ChatColor.stripColor(result.getItemMeta().getDisplayName());
                if (name.equalsIgnoreCase("Противогаз II")) {
                    if (!containsItemInCraftingGrid(event.getInventory(), ChatColor.AQUA + "Противогаз I")) {
                        event.getWhoClicked().sendMessage(ChatColor.RED + "Для крафта Противогаза II требуется Противогаз I в сетке.");
                        event.setCancelled(true);
                        return;
                    }
                } else if (name.equalsIgnoreCase("Противогаз III")) {
                    if (!containsItemInCraftingGrid(event.getInventory(), ChatColor.DARK_AQUA + "Противогаз II")) {
                        event.getWhoClicked().sendMessage(ChatColor.RED + "Для крафта Противогаза III требуется Противогаз II в сетке.");
                        event.setCancelled(true);
                        return;
                    }
                }
            }
        }
    }

    /**
     * Проверка наличия конкретного предмета в сетке крафта.
     *
     * @param inventory Инвентарь крафта
     * @param itemName  Отображаемое имя искомого предмета
     * @return true, если предмет найден, иначе false
     */
    private boolean containsItemInCraftingGrid(Inventory inventory, String itemName) {
        for (ItemStack item : inventory.getMatrix()) {
            if (item != null && item.hasItemMeta() && item.getItemMeta().hasDisplayName()) {
                String name = ChatColor.stripColor(item.getItemMeta().getDisplayName());
                if (name.equalsIgnoreCase(itemName)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Получение уровня радиации игрока.
     *
     * @param player Игрок
     * @return Текущий уровень радиации
     */
    private int getPlayerTotalRadiation(Player player) {
        UUID playerId = player.getUniqueId();
        return playerRadiationLevels.getOrDefault(playerId, 0);
    }

    /**
     * Увеличение уровня радиации игрока.
     *
     * @param player Игрок
     * @param amount Количество радиации для добавления
     */
    private void addPlayerRadiation(Player player, int amount) {
        UUID playerId = player.getUniqueId();
        int currentRadiation = playerRadiationLevels.getOrDefault(playerId, 0);
        currentRadiation += amount;
        playerRadiationLevels.put(playerId, currentRadiation);
        getLogger().info("Игрок " + player.getName() + " получил радиацию: +" + amount + " (Всего: " + currentRadiation + ")");
    }

    /**
     * Уменьшение уровня радиации игрока.
     *
     * @param player Игрок
     * @param amount Количество радиации для уменьшения
     */
    private void removePlayerRadiation(Player player, int amount) {
        UUID playerId = player.getUniqueId();
        int currentRadiation = playerRadiationLevels.getOrDefault(playerId, 0);
        currentRadiation -= amount;
        if (currentRadiation < 0) currentRadiation = 0;
        playerRadiationLevels.put(playerId, currentRadiation);
        getLogger().info("У игрока " + player.getName() + " снизилась радиация: -" + amount + " (Всего: " + currentRadiation + ")");
    }

    /**
     * Постепенное изменение радиации (увеличение или уменьшение).
     *
     * @return Значение радиации для изменения (1 или 2)
     */
    private int getRadiationChange() {
        Random rand = new Random();
        return rand.nextInt(2) + 1; // 1 или 2
    }

    /**
     * Получение уровня противогаза игрока.
     *
     * @param player Игрок
     * @return Уровень противогаза (800, 2400, 4800), или 0 если противогаза нет
     */
    private int getPlayerGasMaskLevel(Player player) {
        ItemStack helmet = player.getInventory().getHelmet();
        if (helmet == null || !helmet.hasItemMeta() || !helmet.getItemMeta().hasDisplayName()) {
            return 0;
        }

        String name = ChatColor.stripColor(helmet.getItemMeta().getDisplayName());
        if (name.equalsIgnoreCase("Противогаз I")) {
            return 800;
        } else if (name.equalsIgnoreCase("Противогаз II")) {
            return 2400;
        } else if (name.equalsIgnoreCase("Противогаз III")) {
            return 4800;
        } else {
            return 0;
        }
    }

    /**
     * Проверка, носит ли игрок противогаз.
     *
     * @param player Игрок
     * @return true, если носит противогаз, иначе false
     */
    private boolean isWearingGasMask(Player player) {
        return getPlayerGasMaskLevel(player) > 0;
    }

    /**
     * Применение эффектов радиации к игроку на основе уровня радиации.
     *
     * @param player         Игрок, к которому применяются эффекты
     * @param totalRadiation Суммарный уровень радиации
     */
    private void applyRadiationEffects(Player player, int totalRadiation) {
        // Удаление всех предыдущих радиационных эффектов
        removeRadiationEffects(player);

        // Применение новых эффектов на основе текущего уровня радиации
        for (Map.Entry<Integer, EffectMapping> entry : effectMappings.entrySet()) {
            if (totalRadiation >= entry.getKey()) {
                EffectMapping mapping = entry.getValue();
                for (String effectName : mapping.effects) {
                    PotionEffectType effectType = PotionEffectType.getByName(effectName);
                    if (effectType != null) {
                        // Создание эффекта радиации
                        PotionEffect effect = new PotionEffect(effectType, mapping.duration * 20, mapping.amplifier - 1, false, false);
                        player.addPotionEffect(effect, true);
                        getLogger().info("Применён эффект " + effectName + " к игроку " + player.getName());
                    } else {
                        getLogger().warning("PotionEffectType '" + effectName + "' не найден.");
                    }
                }
                break; // Применяем только самое высокое соответствие
            }
        }
    }

    /**
     * Удаление эффектов радиации из игрока.
     *
     * @param player Игрок, у которого удаляются эффекты
     */
    private void removeRadiationEffects(Player player) {
        for (EffectMapping mapping : effectMappings.values()) {
            for (String effectName : mapping.effects) {
                PotionEffectType effectType = PotionEffectType.getByName(effectName);
                if (effectType != null) {
                    player.removePotionEffect(effectType);
                    getLogger().info("Удалён эффект " + effectName + " у игрока " + player.getName());
                }
            }
        }
    }

    /**
     * Класс, представляющий радиационную зону.
     */
    private static class RadiationZone {
        private final String name;
        private final double minX, minY, minZ, maxX, maxY, maxZ;
        private final int radiation;
        private final int duration; // Продолжительность в секундах
        private final long endTime; // Время окончания в секундах

        public RadiationZone(String name, double minX, double minY, double minZ,
                             double maxX, double maxY, double maxZ,
                             int radiation, int duration) {
            this.name = name;
            this.minX = Math.min(minX, maxX);
            this.minY = Math.min(minY, maxY);
            this.minZ = Math.min(minZ, maxZ);
            this.maxX = Math.max(minX, maxX);
            this.maxY = Math.max(minY, maxY);
            this.maxZ = Math.max(minZ, maxZ);
            this.radiation = radiation;
            this.duration = duration;
            this.endTime = (System.currentTimeMillis() / 1000) + duration;
        }

        public String getName() {
            return name;
        }

        public World getWorld() {
            // Предполагается, что зоны создаются в текущем мире плагина
            // Если нужно, можно добавить параметр мира в радиационную зону
            return Bukkit.getWorlds().get(0); // Использовать первый мир. Измените при необходимости.
        }

        /**
         * Проверка, находится ли локация внутри радиационной зоны.
         *
         * @param loc Локация для проверки
         * @return true, если внутри зоны, иначе false
         */
        public boolean isInZone(Location loc) {
            return loc.getX() >= minX && loc.getX() <= maxX &&
                    loc.getY() >= minY && loc.getY() <= maxY &&
                    loc.getZ() >= minZ && loc.getZ() <= maxZ;
        }

        /**
         * Проверка перекрытия с другими зонами.
         *
         * @param otherMinX Другой minX
         * @param otherMinY Другой minY
         * @param otherMinZ Другой minZ
         * @param otherMaxX Другой maxX
         * @param otherMaxY Другой maxY
         * @param otherMaxZ Другой maxZ
         * @return true, если зоны перекрываются, иначе false
         */
        public boolean overlapsWith(double otherMinX, double otherMinY, double otherMinZ,
                                    double otherMaxX, double otherMaxY, double otherMaxZ) {
            return !(otherMinX > maxX || otherMaxX < minX ||
                    otherMinY > maxY || otherMaxY < minY ||
                    otherMinZ > maxZ || otherMaxZ < minZ);
        }

        /**
         * Получение оставшегося времени действия зоны в секундах.
         *
         * @return Оставшееся время в секундах
         */
        public int getRemainingTime() {
            long currentTime = System.currentTimeMillis() / 1000;
            long remaining = endTime - currentTime;
            return (int) Math.max(remaining, 0);
        }
    }

    /**
     * Класс, представляющий маппинг эффекта радиации.
     */
    private static class EffectMapping {
        private final int duration; // Продолжительность в тиках (секунды * 20)
        private final int amplifier;
        private final List<String> effects;

        public EffectMapping(int duration, int amplifier, List<String> effects) {
            this.duration = duration;
            this.amplifier = amplifier;
            this.effects = effects;
        }
    }

    /**
     * Обработка автодополнения для команды /radiationzone.
     *
     * @param sender  Отправитель команды
     * @param command Команда
     * @param alias   Псевдоним команды
     * @param args    Аргументы команды
     * @return Список вариантов автодополнения
     */
    @Override
    public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
        if (command.getName().equalsIgnoreCase("radiationzone")) {
            if (args.length == 1) {
                return Arrays.asList("create", "delete", "list", "info");
            } else if (args.length == 2) {
                String subCommand = args[0].toLowerCase();
                if (subCommand.equals("delete") || subCommand.equals("info")) {
                    List<String> zoneNames = new ArrayList<>(zones.keySet());
                    return zoneNames;
                }
            }
        }
        return Collections.emptyList();
    }
}

effect_mappings:
  100:
    duration: 90
    amplifier: 2
    effects:
      - POISON
  400:
    duration: 90
    amplifier: 4
    effects:
      - POISON
      - CONFUSION
  800:
    duration: 90
    amplifier: 6
    effects:
      - POISON
      - CONFUSION
      - BLINDNESS
  1600:
    duration: 90
    amplifier: 7
    effects:
      - POISON
      - CONFUSION
      - BLINDNESS
      - WEAKNESS
  3200:
    duration: 90
    amplifier: 10
    effects:
      - POISON
      - CONFUSION
      - BLINDNESS
      - WEAKNESS
      - WITHER

# Радиоактивные зоны будут храниться в секции radiation_zones
radiation_zones:


name: RadiationPlugin
version: 1.1
main: com.yourpackage.RadiationPlugin
api-version: 1.20
commands:
  radiationzone:
    description: Управление радиационными зонами
    usage: /radiationzone <create|delete|list|info>
    permission: radiationplugin.radiationzone
  radiationcheck:
    description: Проверить уровень радиации
    usage: /radiationcheck
    permission: radiationplugin.radiationcheck
permissions:
  radiationplugin.radiationzone:
    description: Позволяет управлять радиационными зонами
    default: op
  radiationplugin.radiationcheck:
    description: Позволяет проверять уровень радиации
    default: true