Запомни код
package ru.dragons;

import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.command.SimpleCommand;
import com.velocitypowered.api.proxy.ConsoleCommandSource;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;

public class BlockCommand implements SimpleCommand {

    private final DragonsBlocker plugin;

    public BlockCommand(DragonsBlocker plugin) {
        this.plugin = plugin;
    }

    @Override
    public void execute(Invocation invocation) {
        CommandSource source = invocation.source();

        if (!(source instanceof ConsoleCommandSource)) {
            source.sendMessage(Component.text("Эту команду можно выполнять только из консоли.")
                    .color(NamedTextColor.RED));
            return;
        }

        String[] args = invocation.arguments();

        if (args.length < 2) {
            source.sendMessage(Component.text("Использование: /block <block/unblock> <player-name>")
                    .color(NamedTextColor.RED));
            return;
        }

        String action = args[0];
        String playerName = args[1];

        if (action.equalsIgnoreCase("block")) {
            plugin.blockPlayer(playerName);
            source.sendMessage(Component.text("Аккаунт " + playerName + " был заблокирован.").color(NamedTextColor.RED));
            plugin.kickPlayer(playerName);

        } else if (action.equalsIgnoreCase("unblock")) {
            plugin.unblockPlayer(playerName);
            source.sendMessage(Component.text("Аккаунт " + playerName + " был разблокирован.").color(NamedTextColor.GREEN));
        } else {
            source.sendMessage(Component.text("Неизвестное действие. Используйте block или unblock.").color(NamedTextColor.RED));
        }
    }
}


Второй класс
package ru.dragons;

import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.command.SimpleCommand;
import com.velocitypowered.api.proxy.ConsoleCommandSource;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;

import java.util.Map;

public class DomainListCommand implements SimpleCommand {

    private final DomainTracker domainTracker;

    public DomainListCommand(DomainTracker domainTracker) {
        this.domainTracker = domainTracker;
    }

    @Override
    public void execute(Invocation invocation) {
        CommandSource source = invocation.source();

        if (!(source instanceof ConsoleCommandSource)) {
            source.sendMessage(Component.text("Эту команду можно выполнять только из консоли.")
                    .color(NamedTextColor.RED));
            return;
        }

        Map<String, Integer> allPlayers = domainTracker.getAllPlayersCountByDomain();
        Map<String, Integer> currentPlayers = domainTracker.getCurrentPlayersCountByDomain();

        if (allPlayers.isEmpty()) {
            System.out.println("Нет данных о доменах.");
        } else {
            allPlayers.forEach((domain, total) -> {
                int current = currentPlayers.getOrDefault(domain, 0);
                System.out.println("Домен: " + domain + " | Всего: " + total + " | Сейчас: " + current);
            });
        }
    }
}


Третий класс
package ru.dragons;

import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class DomainTracker {

    private final Map<String, Integer> allPlayersCountByDomain;
    private final Map<String, Set<String>> currentPlayersByDomain;
    private final Map<String, Set<String>> countedPlayersByDomain;
    private final File domainFile;

    public DomainTracker(File domainFile) {
        this.allPlayersCountByDomain = new HashMap<>();
        this.currentPlayersByDomain = new HashMap<>();
        this.countedPlayersByDomain = new HashMap<>();
        this.domainFile = domainFile;
        loadDomains();
    }

    public void playerJoined(String playerName, String domain) {
        if (!countedPlayersByDomain.computeIfAbsent(domain, k -> new HashSet<>()).contains(playerName)) {
            allPlayersCountByDomain.put(domain, allPlayersCountByDomain.getOrDefault(domain, 0) + 1);
            countedPlayersByDomain.get(domain).add(playerName);
        }
        currentPlayersByDomain.computeIfAbsent(domain, k -> new HashSet<>()).add(playerName);
        saveDomains();
    }

    public void playerLeft(String playerName, String domain) {
        currentPlayersByDomain.computeIfPresent(domain, (k, v) -> {
            v.remove(playerName);
            return v.isEmpty() ? null : v;
        });
    }

    public Map<String, Integer> getAllPlayersCountByDomain() {
        return new HashMap<>(allPlayersCountByDomain);
    }

    public Map<String, Integer> getCurrentPlayersCountByDomain() {
        Map<String, Integer> result = new HashMap<>();
        for (Map.Entry<String, Set<String>> entry : currentPlayersByDomain.entrySet()) {
            result.put(entry.getKey(), entry.getValue().size());
        }
        return result;
    }

    private void saveDomains() {
        try {
            Yaml yaml = new Yaml();
            try (FileWriter writer = new FileWriter(domainFile)) {
                yaml.dump(allPlayersCountByDomain, writer);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void loadDomains() {
        if (!domainFile.exists()) {
            return;
        }

        try {
            Yaml yaml = new Yaml();
            try (FileReader reader = new FileReader(domainFile)) {
                Map<String, Integer> loadedData = yaml.load(reader);
                if (loadedData != null) {
                    allPlayersCountByDomain.putAll(loadedData);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


Четвертый класс
package ru.dragons;

import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.DisconnectEvent;
import com.velocitypowered.api.event.connection.PreLoginEvent;
import com.velocitypowered.api.event.player.ServerConnectedEvent;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.velocitypowered.api.proxy.ProxyServer;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.yaml.snakeyaml.Yaml;

import javax.inject.Inject;
import java.io.*;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

@Plugin(id = "dragonsblocker", name = "DragonsBlocker", version = "1.0", authors = {"BOBOLI"})
public class DragonsBlocker {

    private final ProxyServer server;
    private final Logger logger;
    private final Set<String> blockedPlayers;
    private final File configFile;
    private final File blockedPlayersFile;
    private Map<String, Object> config;
    private final DomainTracker domainTracker;

    @Inject
    public DragonsBlocker(ProxyServer server, Logger logger, @DataDirectory Path dataDirectory) {
        this.server = server;
        this.logger = logger;
        this.blockedPlayers = new HashSet<>();
        this.configFile = dataDirectory.resolve("config.yml").toFile();
        this.blockedPlayersFile = dataDirectory.resolve("blocked.yml").toFile();
        this.domainTracker = new DomainTracker(dataDirectory.resolve("domains.yml").toFile());

        loadConfig();
        loadBlockedPlayers();

        server.getCommandManager().register("block", new BlockCommand(this));
        server.getCommandManager().register("domen-list", new DomainListCommand(domainTracker));
    }

    private void loadConfig() {
        try {
            if (!configFile.exists()) {
                configFile.getParentFile().mkdirs();
                configFile.createNewFile();
                saveDefaultConfig();
            }
            Yaml yaml = new Yaml();
            try (FileReader reader = new FileReader(configFile)) {
                config = yaml.load(reader);
                if (config == null) {
                    config = new HashMap<>();
                }
            }
        } catch (IOException e) {
            logger.severe("Could not create or load the configuration file!");
            e.printStackTrace();
        }
    }

    private void saveDefaultConfig() throws IOException {
        Yaml yaml = new Yaml();
        config = new HashMap<>();
        config.put("block-message", "&cВаш аккаунт отключен администрацией.");
        try (FileWriter writer = new FileWriter(configFile)) {
            yaml.dump(config, writer);
        }
    }

    private void loadBlockedPlayers() {
        try {
            if (blockedPlayersFile.exists()) {
                Yaml yaml = new Yaml();
                try (FileReader reader = new FileReader(blockedPlayersFile)) {
                    Set<String> loadedPlayers = yaml.load(reader);
                    if (loadedPlayers != null) {
                        blockedPlayers.addAll(loadedPlayers);
                    }
                }
            }
        } catch (IOException e) {
            logger.severe("Could not load the blocked players file!");
            e.printStackTrace();
        }
    }

    private void saveBlockedPlayers() {
        try {
            Yaml yaml = new Yaml();
            try (FileWriter writer = new FileWriter(blockedPlayersFile)) {
                yaml.dump(blockedPlayers, writer);
            }
        } catch (IOException e) {
            logger.severe("Could not save the blocked players file!");
            e.printStackTrace();
        }
    }

    @Subscribe
    public void onPreLogin(PreLoginEvent event) {
        String playerName = event.getUsername().toLowerCase();

        if (blockedPlayers.contains(playerName)) {
            String message = (String) config.getOrDefault("block-message", "&cВаш аккаунт отключен администрацией.");
            Component component = LegacyComponentSerializer.legacyAmpersand().deserialize(message);
            event.setResult(PreLoginEvent.PreLoginComponentResult.denied(component));
        }
    }

    @Subscribe
    public void onPlayerJoin(ServerConnectedEvent event) {
        String playerName = event.getPlayer().getUsername();
        String domain = event.getPlayer().getVirtualHost().map(host -> host.getHostString()).orElse("unknown");

        domainTracker.playerJoined(playerName, domain);
    }

    @Subscribe
    public void onPlayerDisconnect(DisconnectEvent event) {
        String playerName = event.getPlayer().getUsername();
        String domain = event.getPlayer().getVirtualHost().map(host -> host.getHostString()).orElse("unknown");

        domainTracker.playerLeft(playerName, domain);
    }

    public void blockPlayer(String playerName) {
        if (blockedPlayers.add(playerName.toLowerCase())) {
            logger.info("Аккаунт " + playerName + " был заблокирован.");
            saveBlockedPlayers(); // Сохраняем после добавления
        } else {
            logger.info("Аккаунт " + playerName + " уже заблокирован.");
        }
    }

    public void unblockPlayer(String playerName) {
        if (blockedPlayers.remove(playerName.toLowerCase())) {
            logger.info("Аккаунт " + playerName + " был разблокирован.");
            saveBlockedPlayers(); // Сохраняем после удаления
        } else {
            logger.info("Аккаунт " + playerName + " не был заблокирован.");
        }
    }

    public void kickPlayer(String playerName) {
        logger.info("Попытка кика игрока: " + playerName);
        server.getPlayer(playerName).ifPresent(player -> {
            logger.info("Игрок " + playerName + " найден, производится отключение.");
            String message = (String) config.getOrDefault("block-message", "&cВаш аккаунт отключен администрацией.");
            Component component = LegacyComponentSerializer.legacyAmpersand().deserialize(message);
            player.disconnect(component);
        });
    }
}


config.yml
block-message: "&cВаш аккаунт был отключен администрацией."