Запомни код
package xyz.dragonsfixer;

import com.google.inject.Inject;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.command.CommandExecuteEvent;
import com.velocitypowered.api.event.command.CommandExecuteEvent.CommandResult;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.CopyOption;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.slf4j.Logger;
import org.yaml.snakeyaml.Yaml;

@Plugin(
        id = "dragonsfixer",
        name = "DragonsFixer",
        version = "1.2",
        description = "Антиспам плагин для Velocity",
        authors = {"boboliii"}
)
public class DragonsFixer {
    private final ProxyServer server;
    private final Path dataDirectory;
    private final Map<UUID, Long> cooldowns = new ConcurrentHashMap<>();
    private final Map<UUID, List<Long>> commandTimestamps = new ConcurrentHashMap<>();
    private int cooldownTime = 500;
    private Component spamMessage;
    private int kickAfterWarnings;
    private Component kickMessage;
    @Inject
    private Logger logger;

    @Inject
    public DragonsFixer(ProxyServer server, @DataDirectory Path dataDirectory) {
        this.server = server;
        this.dataDirectory = dataDirectory;
        this.spamMessage = Component.text("DragonsGrief » Не спамь!").color(NamedTextColor.RED);
        this.kickAfterWarnings = 35;
        this.kickMessage = Component.text("DragonsGrief » Вы были кикнуты за спам командами").color(NamedTextColor.RED);
    }

    @Subscribe
    public void onProxyInitialization(ProxyInitializeEvent event) {
        try {
            this.initializeConfiguration();
        } catch (Exception var3) {
            this.logger.error("Ошибка инициализации конфигурации", var3);
        }
    }

    private void initializeConfiguration() throws IOException {
        Files.createDirectories(this.dataDirectory);
        Path configPath = this.dataDirectory.resolve("config.yml");
        if (Files.notExists(configPath, new LinkOption[]{LinkOption.NOFOLLOW_LINKS})) {
            InputStream inputStream = this.getClass().getResourceAsStream("/config.yml");

            try {
                if (inputStream != null) {
                    Files.copy(inputStream, configPath, new CopyOption[0]);
                } else {
                    this.createDefaultConfig(configPath);
                }
            } catch (Throwable var6) {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (Throwable var5) {
                        var6.addSuppressed(var5);
                    }
                }

                throw var6;
            }

            if (inputStream != null) {
                inputStream.close();
            }
        }

        this.loadConfiguration(configPath);
    }

    private void createDefaultConfig(Path configPath) throws IOException {
        String defaultConfigContent = "cooldown: 500\nkick-after-warnings: 25\nspam-message: \"§6DragonsGrief §7» §c§lНе спамь!\"\nkick-message: \"§cВы были кикнуты за спам командами\"\n";
        Files.write(configPath, defaultConfigContent.getBytes(), new OpenOption[0]);
    }

    private void loadConfiguration(Path configPath) throws IOException {
        InputStream input = Files.newInputStream(configPath);

        try {
            Yaml yaml = new Yaml();
            Map<String, Object> config = (Map<String, Object>) yaml.load(input);
            this.cooldownTime = (Integer) config.getOrDefault("cooldown", 500);
            this.kickAfterWarnings = (Integer) config.getOrDefault("kick-after-warnings", 25);
            this.spamMessage = LegacyComponentSerializer.legacyAmpersand().deserialize((String) config.getOrDefault("spam-message", "§6DragonsGrief §7» §c§lНе спамь!"));
            this.kickMessage = LegacyComponentSerializer.legacyAmpersand().deserialize((String) config.getOrDefault("kick-message", "§cВы были кикнуты за спам командами"));
        } catch (Throwable var6) {
            if (input != null) {
                try {
                    input.close();
                } catch (Throwable var5) {
                    var6.addSuppressed(var5);
                }
            }

            throw var6;
        }

        if (input != null) {
            input.close();
        }
    }

    @Subscribe
    public void onCommand(CommandExecuteEvent event) {
        CommandSource source = event.getCommandSource();
        if (source instanceof Player) {
            Player player = (Player) source;
            UUID playerId = player.getUniqueId();
            long currentTime = System.currentTimeMillis();
            if (playerId == null || this.cooldowns == null || this.commandTimestamps == null) {
                this.logger.error("Player ID, cooldowns or commandTimestamps is null");
                return;
            }

            if (this.isInCooldown(playerId, currentTime)) {
                event.setResult(CommandResult.denied());
                player.sendMessage(this.spamMessage);
                return;
            }

            this.cooldowns.put(playerId, currentTime + (long) this.cooldownTime);
            List<Long> timestamps = this.commandTimestamps.computeIfAbsent(playerId, k -> new ArrayList<>());

            if (timestamps == null) {
                this.logger.error("Timestamps is null for player ID: " + playerId);
                return;
            }

            timestamps.removeIf(timestamp -> currentTime - timestamp > 1500L);
            timestamps.add(currentTime);
            if (timestamps.size() >= this.kickAfterWarnings) {
                player.disconnect(this.kickMessage);
                this.commandTimestamps.remove(playerId);
                return;
            }
        }
    }

    private boolean isInCooldown(UUID playerId, long currentTime) {
        return currentTime < (Long) this.cooldowns.getOrDefault(playerId, 0L);
    }
}