# Плагины

На серверах есть разные плагины. Каждый плагин - независимая сущность. Плагин может отслеживать разные события сервера, а еще и как-то реагировать на них с помощью определенного сервером списком команд.

## Как установить плагин

1. Первый способ. Через редактирование таблицы plugins\_list внутри plugins\_manager.lua
2. Такой же, как и первый, но можно там же не указывать поле data, а только order, а сам плагин с расширением .lua закинуть в папку plugins
3. Второй способ и самый удобный. Просто закинуть нужный плагин в папку plugins с расширением .lua, и он автоматически подхватится. Больше не нужно руками их добавлять в текстовом редакторе, просто переместить в папку. Если нужно настроить порядок вызова плагинов (вначале один, потом другой), то смотрите второй способ применения. Все варианты использования есть в плагин менеджере

## Список команд

* call\_function - вызвать какую-то функцию. Это может быть как серверная функция, так и зарегистрированная в общем пространстве функция другого плагина
* register\_function - зарегистрировать функцию, ее можно будет потом вызывать с помощью call\_function. Полезно, чтобы дать возможность другим плагинам получать какую-то инфу. Например, плагин system определяет функцию кика с соответствующим сообщением. И эту готовую функцию может использовать любой другой плагин
* register\_command - зарегистрировать команду. Например, мы хотим, чтобы при вводе команды /test игроку присылалось сообщение abrakadabra
* set\_data - установить данные (нужно для взаимодействия между плагинами)
* get\_data - получить данные (нужно для взаимодействия между плагинами). Например, нужно узнать ник игрока
* remove\_data - удалить данные
* send\_data - отправить данные. Можно отправлять данные клиенту. Правда, клиент будет реагировать только на те данные, список которых определен на его стороне. Например, можно с помощью этого плагина заставить игрока обновить данные карты
* set\_server\_state - установить состояние сервера (готов к взаимодействию, выключен, запускается)
* start - запустить сервер

### Какие события плагин отслеживает?

* init - запуск сервера
* verify\_registration - верификацию игрока (сервер проверяет, пускать ли игрока в игру или нет)
* on\_player\_registered - регистрацию игрока на сервере (когда игрок заходит, то ему выдается страна, он добавляется в список игроков)
* on\_player\_joined - момент, когда у игрока прогрузилась карта (например, отправлять ему просьбу отобразить правила раньше этого момента не имеет смысла, т.к. игрок в меню)
* on\_player\_disconnected - отключение игрока от сервера
* on\_data - данные, которые пришли от клиента
* before\_next - событие перед началом след. хода
* game\_over - завершение игры
* attribute\_message - оформление сообщения

## Разбор стандартного плагина afk

```
-- это нужно для работы модуля
local M = {}

-- подключаем модуль таймера
local timer_module = require "core.timer"

-- переменные для работы с функциями других плагинов или сервера: отправить данные, вызвать функцию, получить данные
local send_data
local call_function
local get_data

-- таблица с данными последней синхронизации с клиентами, хранят таймер и последнее время
local last_sync = {
    -- client = {
    --     timer_id,
    --     last_time
    -- }
}

-- ждем столько сек, если нет ответа, то кик
local afk_sec = 30

-- проверяем клиента
local function check_client(client)
    -- если текущее время минус время последней синхронизации больше 30 сек, то кикаем
    if socket.gettime() - last_sync[client].last_time > afk_sec then
        call_function("kick", client, { "", get_data("clients_data")[client].name, "lost connection"})
    end
    -- шлем сообщение клиенту, на которое он должен ответить
    local t = {
        type = "ping",
        data = {}
    }
    send_data(to_json(t), client)
end
-- вызывается один раз вначале. Тут мы определяем нужные нам функции
function M.init(api)
    send_data = api.send_data
    call_function = api.call_function
    get_data = api.get_data
end

-- вызывается в случае регистрации игрока
function M.on_player_registered(client)
    -- заполняем данные синхронизации нового клиента
    last_sync[client] = {
        -- создаем таймер, который каждые 30 сек проверяет наличие соединения
        timer_id = timer_module.every(afk_sec, function()
            check_client(client)
        end),
        last_time = socket.gettime()
    }
end

-- если клиент отключился, то удаляем данные
function M.on_player_disconnected(client)
    last_sync[client].timer_id:remove()
    last_sync[client] = nil
end

-- если игрок прислал ответ, то обновляем данные синхронизации
function M.on_data(data, ip, port, client)
    if data.type == "pong" then
        last_sync[client].last_time = socket.gettime()
    end
end

return M
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.denismakhortov.com/ru/server/plugins.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
