Система отправки игровых событий SCP:SL в Discord/Telegram/WebHook с максимальной кастомизацией через Lua скрипты.
Основные фичи:
- 🔥 Каждое событие — отдельный
.luaфайл - ⚡ Автоматическая регистрация всех событий LabAPI
- 🌐 4 протокола связи: HTTP, TCP, UDP, WebSocket
- 🔄 Авто-реконнект при обрыве
- 🎯 Discord, Telegram, WebHook
- 🐳 Docker образы для клиента
Plugin (C# + LabAPI) ←→ Client (Deno + TypeScript) ←→ Discord/Telegram/WebHook
[Events] [Socket Server] [Bot API]
- Фреймворк: LabAPI
- Язык: C# (.NET Standard 2.1)
- Задачи: Собирает события игры, выполняет Lua скрипты, отправляет через сокеты
- Runtime: Deno 2.x
- Язык: TypeScript
- Задачи: Принимает события от плагина, отправляет в Discord/Telegram
# Скачать из релизов
wget https://github.com/Qurre-sl/SCPLogs/releases/latest/download/SCPLogs.dll
# Или скомпилировать
cd plugin
dotnet build -c ReleaseПоместить SCPLogs.dll в AppData/SCP Secret Laboratory/LabAPI/plugins/
После первого запуска создастся LabAPI/configs/scplogs.yml:
ip: 127.0.0.1
port: 8080
protocol: udp # http | tcp | udp | websocket
clientToken: СМЕНИ_МЕНЯ_НА_РАНДОМНЫЙ_ТОКЕН
badgeOnline: "reply = string.format(\"%s/%s players\", Count, Slots)"
dontSendEvents: []
luaConfig:
declareTypes:
- typeName: System.DateTime
luaName: System_DateTimeСоздать папку LabAPI/configs/SCPLogs/ и добавить .lua файлы для нужных событий.
Формат имени: {ClassName}.{EventName}.lua
Примеры в /plugin/ExampleConfigs/ — скопировать оттуда и настроить.
# Установить Deno (если нет)
curl -fsSL https://deno.land/install.sh | sh
cd client
cp env.example .env
nano .env # настроить токены и каналыНастройка .env:
# === Sender (куда отправлять) ===
SENDER_TYPE=discord # discord | telegram | webhook
SENDER_TIMEOUT_SECONDS=60
# Discord
DISCORD_TOKEN=твой_токен_бота
DISCORD_COMMAND_GUILDS=123456789,987654321
DISCORD_ALLOWED_CHANNELS=123456789,987654321
# === Socket (откуда принимать) ===
SOCKET_TYPE=udp # http | tcp | udp | websocket
SOCKET_HOST=127.0.0.1
SOCKET_PORT=8080
SOCKET_TOKEN=ТАКОЙ_ЖЕ_КАК_В_scplogs.ymlЗапуск:
deno run --allow-all src/main.tsPull & Run:
docker pull ghcr.io/qurre-sl/scplogs:latest
docker run -d \
--name scplogs \
--restart unless-stopped \
-p 8080:8080 \
-e SENDER_TYPE=discord \
-e SENDER_TIMEOUT_SECONDS=60 \
-e DISCORD_TOKEN=your_token \
-e DISCORD_COMMAND_GUILDS=123,456 \
-e DISCORD_ALLOWED_CHANNELS=789,012 \
-e SOCKET_TYPE=udp \
-e SOCKET_HOST=0.0.0.0 \
-e SOCKET_PORT=8080 \
-e SOCKET_TOKEN=your_token \
ghcr.io/qurre-sl/scplogs:latestDocker Compose (inline):
version: '3.8'
services:
scplogs:
image: ghcr.io/qurre-sl/scplogs:latest
restart: unless-stopped
ports:
- "8080:8080"
environment:
SENDER_TYPE: discord
SENDER_TIMEOUT_SECONDS: 60
DISCORD_TOKEN: your_token
DISCORD_COMMAND_GUILDS: "123,456"
DISCORD_ALLOWED_CHANNELS: "789,012"
SOCKET_TYPE: udp
SOCKET_HOST: 0.0.0.0
SOCKET_PORT: 8080
SOCKET_TOKEN: your_tokenDocker Compose (env_file):
version: '3.8'
services:
scplogs:
image: ghcr.io/qurre-sl/scplogs:latest
restart: unless-stopped
ports:
- "8080:8080"
env_file:
- .envТеги:
latest— stable релизv3-preview,main,dev— ветки разработки1.2.3,1.2,1— версии
Файл: LabAPI/configs/SCPLogs/PlayerEvents.Joined.lua
-- @enabled true
-- @channels 123456789,987654321
--
-- Доступные значения:
-- Player - игрок (LabApi.Features.Wrappers.Players.Player)
-- Player.DisplayName - никнейм
-- Player.UserId - Steam ID
-- Player.Role - текущая роль (RoleTypeId)
--
-- Функции:
-- SendLog(message, channels?) - отправить лог
-- PrintTime() - Discord timestamp
-- PrintPlayer(player, printRole?) - форматированная инфа об игроке
-- IsOneFraction(player1, player2) - одна ли фракция
reply = string.format("%s Игрок **%s** подключился к серверу",
PrintTime(),
Player.DisplayName)Все события из LabApi.Events.Handlers.*:
PlayerEvents.Joined/PlayerEvents.LeftPlayerEvents.Death/PlayerEvents.DyingPlayerEvents.Escaping/PlayerEvents.EscapedServerEvents.RoundStarted/ServerEvents.RoundEndedWarheadEvents.Starting/WarheadEvents.Detonated- И т.д. — полный список в исходниках LabAPI
AppData/SCP Secret Laboratory/LabAPI/configs/SCPLogs/
├── PlayerEvents.Joined.lua
├── PlayerEvents.Death.lua
├── ServerEvents.RoundStarted.lua
└── ...
| Протокол | Описание | Рекомендация |
|---|---|---|
| UDP | Датаграммы, быстро | ✅ Рекомендуется |
| TCP | Потоковое соединение | Стабильное |
| HTTP | REST API через Deno.serve | Для дебага |
| WebSocket | Двустороннее | Оверкилл |
Все поддерживают авто-реконнект при обрыве связи.
| Параметр | Тип | Описание |
|---|---|---|
ip |
string | IP клиента (127.0.0.1 если на том же хосте) |
port |
uint | Порт клиента (должен совпадать с .env) |
protocol |
enum | http / tcp / udp / websocket |
clientToken |
string | Токен авторизации (должен совпадать с .env) |
badgeOnline |
string | Lua для статуса бота (переменные: Count, Slots) |
dontSendEvents |
string[] | Список событий которые НЕ отправлять |
luaConfig.declareTypes |
array | Дополнительные типы для Lua |
Специальные комментарии в начале файла:
-- @enabled true|false - включить/выключить событие
-- @channels 123,456 - ID каналов Discord/Telegram (через запятую)Плагин автоматически подхватывает все события из LabAPI. Не нужно ждать обновления плагина при добавлении новых событий в LabAPI.
Типы регистрируются один раз при загрузке → производительность.
Client использует dynamic imports — если выбран UDP, не загружаются зависимости для HTTP/TCP/WebSocket.
Через dontSendEvents можно исключить события из отправки (например, спам-события).
Вместо одного огромного конфига — каждое событие в отдельном файле. Легко управлять и шарить между серверами.
-- @enabled true
-- @channels 123456789
reply = PrintTime() .. " Раунд начался!"-- @enabled true
-- @channels 123456789
if Attacker ~= nil then
reply = string.format("%s %s убил %s",
PrintTime(),
PrintPlayer(Attacker),
PrintPlayer(Player))
else
reply = string.format("%s %s умер",
PrintTime(),
PrintPlayer(Player))
end-- @enabled true
-- @channels 123456789
if Player.Role == RoleTypeId.Scp096 then
SendLog("SCP-096 сбежал!", {"111111111"})
end
reply = PrintTime() .. " Игрок сбежал: " .. PrintPlayer(Player)- Проверить что LabAPI установлен и работает
- Проверить что нет конфликтов версий .NET
- Посмотреть логи в
AppData/SCP Secret Laboratory/LabAPI/logs/
- Проверить совпадение
clientTokenв.ymlи.env - Проверить совпадение портов
- Проверить что выбран одинаковый протокол
- Убедиться что файрволл не блокирует порт
- Проверить что
.luaфайлы в правильной папке - Проверить что
@enabled true - Проверить что
@channelsуказаны правильные ID - Проверить что событие не в списке
dontSendEvents
- Создать
LabAPI/configs/SCPLogs/{EventClass}.{EventName}.lua - Настроить
@enabledи@channels - Написать логику в Lua
- Перезагрузить плагин (
reload pluginsв RA)
SCPLogs/
├── plugin/ # C# плагин
│ ├── Main.cs # Точка входа
│ ├── Events.cs # Система событий
│ ├── Configs/ # Классы конфигов
│ ├── Sockets/ # HTTP/TCP/UDP/WebSocket клиенты
│ ├── Lua/ # Lua интеграция (MoonSharp)
│ └── Extensions/ # Хелперы
├── client/ # Deno клиент
│ └── src/
│ ├── main.ts # Точка входа
│ ├── sockets/ # Серверы протоколов
│ └── senders/ # Discord/Telegram/WebHook
└── LabAPI/ # Исходники LabAPI (submodule)
Q: Чем отличается от v2? A: v3 использует LabAPI вместо Qurre, отдельные Lua файлы вместо монолитного конфига, Deno вместо Node.js
Q: Поддерживается ли Qurre? A: Нет, только LabAPI. Для Qurre используй v2.
Q: Можно ли использовать несколько клиентов на один плагин?
A: Нет, one-to-one. Но можно отправлять в разные каналы через SendLog().
Q: Как обновить плагин?
A: Заменить .dll, конфиги сохранятся. Lua файлы — ручная миграция.
MIT License - делай че хочешь.