Инструмент для создания зеркал (фейковых серверов) CS2-CSGO в Steam Game Server Browser на основе Fess23/Mirrors.
- Go 1.22+
- Токены игровых серверов Steam (из https://steamcommunity.com/dev/managegameservers, AppID = 730(CS2))
Каждый токен с новой строки. Каждый токен = одно зеркало.
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
{
"start_port": 27016,
"csgo_mod": false,
"servers": [
{
"count": 10,
"server_address": "1.2.3.4:27015",
"players": 1,
"max_players": 32,
"bots": 0,
"hostname": "My Server",
"map": "de_dust2",
"region": "3",
"secure": true,
"tags": "",
"use_abuse": false,
"description": ""
}
]
}go mod vendor
build_linux.batИли вручную:
set GOOS=linux
set GOARCH=amd64
set CGO_ENABLED=0
go build -mod=vendor -a -o mirrors .pkill -9 mirrors
./mirrors# Запуск (Windows)
mirrors.exe
# Запуск (Linux)
./mirrors
# С кастомными путями
./mirrors -config config.json -accounts accounts.txt -tokens tokens.txtВсе изменения относительно оригинального репозитория Fess23/Mirrors.
Файл: main.go
В оригинале break внутри switch прерывал только switch, но не внешний for range. Из-за этого после получения ConnectedEvent цикл немедленно выходил через следующий break внизу, не дожидаясь LoggedOnEvent. Зеркала никогда не завершали логин.
// Было (сломано):
for event := range s.Events() {
switch e := event.(type) {
case *steam.ConnectedEvent:
s.Logon(token)
continue // продолжает цикл — OK
case *server.LoggedOnEvent:
// ...
break // прерывает switch, НЕ for — баг
}
break // всегда выполняется после первого события
}
// Стало (исправлено):
// используется goto doneLogin для выхода из циклаФайлы: protocol/gamecoordinator/msg.go, protocol/gamecoordinator/packet.go
Файлы импортировали github.com/WirStaff/go-steam/protocol напрямую вместо wirstaff.com/mirrors/protocol, что вызывало ошибку сборки после удаления внешней зависимости.
Добавлен семафор (5 одновременных подключений) для избежания rate-limit от Steam при массовом запуске.
Улучшены сообщения для диагностики. Введите любой текст в консоли для отображения количества активных зеркал и игроков.
Файл: a2s/a2s.go — новый файл
В оригинале не было никакого A2S ответчика. Без него Steam Server Browser не мог получить информацию о сервере при клике — поля "Игра", "Название", "Карта", "Задержка" оставались пустыми, кнопки "Обновить" и "Присоединиться" не работали.
Добавлен полноценный A2S UDP сервер:
- A2S_INFO (
0x54) — двухэтапный challenge протокол (CS2 требует challenge перед INFO) - A2S_PLAYER (
0x55) — возвращает пустой список игроков - A2S_RULES (
0x56) — возвращает пустой список правил - Challenge (
0x57) — генерирует случайный challenge, хранит сессии по IP
Клиент → TSource Engine Query (25 байт, без challenge)
Сервер → 0xFF 0xFF 0xFF 0xFF 0x41 + 4 байта challenge
Клиент → TSource Engine Query + те же 4 байта (29 байт)
Сервер → 0xFF 0xFF 0xFF 0xFF 0x49 + полный INFO ответ
0xB0 = 0x80 (port) | 0x10 (SteamID) | 0x20 (tags)
Поля передаются в строгом порядке: port (uint16 LE) → SteamID (uint64 LE) → tags (string).
Файл: a2s/a2s.go
A2S запросы обрабатываются локально зеркалом. Все остальные UDP пакеты (игровой трафик, подключение игроков) проксируются на server_address из конфига. Это позволяет подключаться к зеркалу как к обычному серверу — реальное соединение идёт на основной сервер.
Файлы: server/listeners.go, server/server.go, a2s/a2s.go
После логина Steam присваивает зеркалу SteamID. Этот SteamID теперь сохраняется и передаётся в A2S_INFO ответ через EDF поле 0x10. Без реального SteamID CS2 Browser считал ответ невалидным и не отображал информацию.
Файл: server/server.go, a2s/a2s.go
CS2 Browser фильтрует серверы по полю Folder в A2S_INFO. Если Folder = "csgo" — сервер не отображается в браузере CS2. Исправлено: Folder всегда "cs2".
Оригинально стояло EDF = 0x20 (только tags). Исправлено на 0xB0:
0x80— порт сервера (uint16)0x10— SteamID (uint64)0x20— теги (строка)
Файл: main.go
Поля hostname, map, tags, description теперь поддерживают как строку так и массив строк. При запуске каждое зеркало выбирает случайное значение независимо:
"hostname": ["сервер #1", "сервер #2", "сервер #3"],
"map": ["de_dust2", "de_mirage", "de_inferno"]Файлы: server/server.go, main.go
При use_abuse: true сервер отображает количество игроков равное полю players — как в Steam API так и в A2S ответе. Заполняется массив фейковых SteamID уникальных для каждого зеркала.
"players": 20,
"max_players": 32,
"use_abuse": trueБудет показывать 20/32 в браузере серверов.
Файл: main.go
Добавлена автоматическая конвертация Windows-1251 → UTF-8 при чтении config.json. Если файл сохранён в Windows-1251 (стандартная кодировка Windows) — программа автоматически конвертирует его. Если уже UTF-8 — оставляет как есть.
Теперь можно использовать кириллицу в hostname, map, tags, description без дополнительных настроек.
Добавлены опциональные поля:
{
"version": "1.41.3.8",
"game_dir": "csgo"
}version— версия сервера для Steam API (если не указана, используется13992)game_dir— gamedir для регистрации в Steam (если не указан,cs2приcsgo_mod: false,csgoприcsgo_mod: true)