Настройка выделенного сервера Source под Linux, часть 3

в 16:12, , рубрики: srcds, метки:
  • Установка MetaMod и SourceMod
    • Установка MetaMod:Source
    • Установка SourceMod
  • Автозапуск игровых серверов
  • Логи
    • Логи cron
    • Логи клиента Steam
    • Логи веб-сервера
    • Логи SourceMod
    • Логи игровых серверов
    • Логи сервера статистики
  • Привязка к Steam и QuickPlay
    • Серверная учётная запись
    • QuickPlay

Установка MetaMod и SourceMod

Пришла пора внести свежую струю в процесс настройки совместного сосуществования наших серверов, а именно — добавить MetaMod и SourceMod.

Установка MetaMod:Source

Сначала установим плагин MetaMod:Source, который никаких игровых функций не добавляет, а лишь обеспечивает интерфейс между движком Source, игрой и другими плагинами.

Домашняя страница — http://www.metamodsource.net/

Скачиваем последнюю версию и распаковываем архив.

   $ wget http://cdn.probablyaserver.com/sourcemod/mmsource-1.10.6-linux.tar.gz
   $ tar -xvzf mmsource-1.10.6-linux.tar.gz -C ~/tf2/tf

В каталоге ~/tf2/tf будет создан подкаталог addons (в него мы будем устанавливать и другие моды), а в нём каталог metamod с рядом файлов для различных Source игр, в том числе и для Team Fortress 2:

   addons/
   addons/metamod.vdf
   ...
   addons/metamod/bin/metamod.2.tf2.so
   addons/metamod/bin/server.so
   ...
   addons/metamod/metaplugins.ini

Игровой сервер srcds при запуске проверяет наличие каталога ~/tf2/tf/addons, ищёт в нём *.vdf файлы, в которых в параметре "file" должны быть указаны пути к библиотекам плагинов. В нашем случае, как раз в таком файле ~/tf2/tf/addons/metamod.vdf подключен плагин MetaMod:Source как "addons/metamod/bin/server" (путь указывается относительно ~/tf2/tf/).

Теперь мы установим SourceMod и подключим его к MetaMod.

Установка SourceMod

Домашняя страница — http://www.sourcemod.net/

Переходим на http://www.sourcemod.net/downloads.php?branch=stable, скачиваем последнюю версию под Linux и распаковываем архив

   $ wget https://sm.alliedmods.net/smdrop/1.8/sourcemod-1.8.0-git5947-linux.tar.gz
   $ tar -xvzf sourcemod-1.8.0-git5947-linux.tar.gz -C ~/tf2/tf

В ~/tf2/tf/addons появился каталог sourcemod, в ~/tf2/tf/cfg/ — каталог sourcemod с файлами конфигурации, а в
~/tf2/tf/addons/metamod — файлик sourcemod.vdf.

   addons/metamod/sourcemod.vdf
   addons/sourcemod/
   addons/sourcemod/scripting/
   addons/sourcemod/configs/core.cfg
   ...
   cfg/sourcemod/sm_warmode_off.cfg
   cfg/sourcemod/sm_warmode_on.cfg
   cfg/sourcemod/sourcemod.cfg

Так как одна инсталляция SourceMod не может одновременно обслуживать несколько серверов, то нам необходимо растиражировать по количеству серверов. В каталоге addons переименовываем sourcemod в sourcemod1 и копируем со всем содержимым в sourcemod2, предварительно для удобства выполнив dos2unix для файлов настроек:

   $ mv ~/tf2/tf/addons/sourcemod ~/tf2/tf/addons/sourcemod1
   $ cd ~/tf2/tf/addons/sourcemod1/configs
   $ dos2unix *.cfg *.ini *.txt
   $ cp -r ~/tf2/tf/addons/sourcemod1 ~/tf2/tf/addons/sourcemod2

MetaMod находит и подключает SourceMod благодаря файлу addons/metamod/sourcemod.vdf. Но этот файл один, а нам надо два разных, для каждого сервера. У MetaMod есть параметр, указывающий на каталог (не файл!) с конфигурацией, поэтому создадим два каталога cfg1 и cfg2 и поместим туда sourcemod.vdf, который и будем править.

   $ mkdir ~/tf2/tf/addons/metamod/cfg{1,2}
   $ dos2unix ~/tf2/tf/addons/metamod/sourcemod.vdf
   $ mv ~/tf2/tf/addons/metamod/sourcemod.vdf ~/tf2/tf/addons/metamod/cfg1/sourcemod.vdf
   $ cp ~/tf2/tf/addons/metamod/cfg1/sourcemod.vdf ~/tf2/tf/addons/metamod/cfg2/sourcemod.vdf

Редактируем эти файлы, исправляя пути к инсталляциям SourceMod (так же, относительно ~/tf2/tf):

~/tf2/tf/addons/metamod/cfg1/sourcemod.vdf:

cfg1/sourcemod.vdf
"Metamod Plugin"
{
    "alias"     "sourcemod"
    "file"      "addons/sourcemod1/bin/sourcemod_mm"
}

~/tf2/tf/addons/metamod/cfg2/sourcemod.vdf (исправляем 1 -> 2):

cfg2/sourcemod.vdf
"Metamod Plugin"
{
    "alias"     "sourcemod"
    "file"      "addons/sourcemod2/bin/sourcemod_mm"
}

Для удобства делаем символьные ссылки на каталоги с настройками и логами:

   $ ln -s ~/tf2/tf/addons/metamod/cfg1 ~/cfg/mm1
   $ ln -s ~/tf2/tf/addons/metamod/cfg2 ~/cfg/mm2
   $ ln -s ~/tf2/tf/addons/sourcemod1/configs ~/cfg/sm1
   $ ln -s ~/tf2/tf/addons/sourcemod2/configs ~/cfg/sm2
   $ ln -s ~/tf2/tf/addons/sourcemod1/logs ~/log/sm1
   $ ln -s ~/tf2/tf/addons/sourcemod2/logs ~/log/sm2

Каких-то отдельных команд для запуска MetaMod прописывать не надо — игровой сервер запустит его автоматически, но нам надо указать различные каталоги для загрузки SourceMod.

В файле ~/cfg/autoexec1.cfg для первого сервера дописываем в конец:

autoexec1.cfg
//...

// Load SourceMod instance No 1
mm_basedir addons/metamod/cfg1

Для второго сервера в ~/cfg/autoexec2.cfg аналогично, только вместо "cfg1" -> "cfg2":

autoexec2.cfg
//...

// Load SourceMod instance No 2
mm_basedir addons/metamod/cfg2

Теперь MetaMod знает откуда загружать SourceMod, но последний не знает откуда ему брать свои настройки. Пропишем пути для каждого SourceMod. В отличие от MetaMod, параметры нам придётся указывать аж в командной строке запуска сервера. Ни в autoexec.cfg, ни в server.cfg они не срабатывают.

В скриптах запусках start1.sh и start2.sh, в CMDLINE дописываем:

start1.sh
CMDLINE="...
    +sm_basepath addons/sourcemod1 +sm_corecfgfile addons/sourcemod1/configs/core.cfg 
    ...

Это для первого сервера. Для второго сервера аналогично, только вместо "sourcemod1" -> "sourcemod2":

start2.sh
CMDLINE="...
    +sm_basepath addons/sourcemod2 +sm_corecfgfile addons/sourcemod2/configs/core.cfg 
    ...

Параметр sm_corecfgfile необходим, так как путь к core.cfg не берётся из sm_basepath, что логично было бы предположить.

Для проверки можно запустить первый игровой сервер и когда он полностью запустится, в его консоли ввести (команды выделены угловыми скобками):

   >>> meta version
   Metamod:Source version 1.10.6
   Built from: https://github.com/alliedmodders/metamod-source/commit/9fed12f
   Build ID: 946:9fed12f
   Loaded As: Valve Server Plugin
   Compiled on: Sep 12 2015
   Plugin interface version: 15:14
   SourceHook version: 5:5
   http://www.metamodsource.net/
   >>> mm_basedir
   "mm_basedir" = "addons/metamod/cfg1" ( def. "addons/metamod" )
    singleplayer
    - Metamod:Source Base Folder
   >>> meta list
   Listing 4 plugins:
   [01] SourceMod (1.8.0.5907) by AlliedModders LLC
   [02] TF2 Tools (1.8.0.5907) by AlliedModders LLC
   [03] SDK Hooks (1.8.0.5907) by AlliedModders LLC
   [04] SDK Tools (1.8.0.5907) by AlliedModders LLC
   >>> meta info 1
   Plugin 1 is running.
   Name: "SourceMod" by AlliedModders LLC
   Version: 1.8.0.5907
   Description: Extensible administration and scripting system
   License: See LICENSE.txt
   URL: http://www.sourcemod.net/
   Details: API 015, Date: Apr 26 2016
   File: /home/game/tf2/tf/addons/sourcemod1/bin/sourcemod_mm_i486.so

   >>> sm_basepath
   "sm_basepath" = "addons/sourcemod1" ( def. "addons/sourcemod" )
    - SourceMod base path (set via command line)
   >>> sm_corecfgfile
   "sm_corecfgfile" = "addons/sourcemod1/configs/core.cfg" ( def. "addons/sourcemod/configs/core.cfg" )
    - SourceMod core configuration file
   >>> sm plugins list
   [SM] Listing 17 plugins:
   01 "Admin Menu" (1.8.0.5907) by AlliedModders LLC
   ...
   17 "Player Commands" (1.8.0.5907) by AlliedModders LLC
   >>> sm exts list
   [SM] Displaying 9 extensions:
   [01] Automatic Updater (1.8.0.5907): Updates SourceMod gamedata files
   ...
   [09] SQLite (1.8.0.5907): SQLite Driver

Ну что же, все пути к каталогам и файлам верны, семнадцать стандартных плагинов и девять расширений запущены. Позже мы разберём кто что делает, а пока продолжим.

Если же при вводе команд выдаются ошибки вида:

   >>> meta list
   Listing 1 plugin:
     [01] <FAILED>
   >>> sm_basepath
   Unknown command "sm_basepath"

То значит MetaMod не смог загрузить SourceMod. Надо искать в чём дело.

Перечень консольных команд MetaMod:Source — Console Commands (SourceMM)

Расширения находятся в каталоге ~/tf2/tf/addons/sourcemod{1,2}/extensions — для всех поддерживаемых игр на движке Source, не только TF2.

Скомпилированные плагины находятся в каталоге ~/tf2/tf/addons/sourcemod{1,2}/plugins. Если требуется отключить какой-нибудь плагин, то его можно просто перенести в подкаталог disabled. Сами исходные тексты плагинов находятся каталоге ~/tf2/tf/addons/sourcemod{1,2}/scripting. Там же есть компилятор и скрипт compile.sh, который компилирует исходники и помещает скомпилированные плагины в подкаталог compiled, откуда их можно перенести в ~/tf2/tf/addons/sourcemod{1.2}/plugins — и они станут доступны для использования SourceMod.

Теперь можно настроить SourceMod для каждого сервера, редактируя файлы core.cfg в ~/tf2/tf/addons/sourcemod{1,2}/configs. В нашем случае удовлетворимся параметрами по умолчанию. Обратите внимание, что при этом параметром "DisableAutoUpdate No" включено автообновление игровых данных SourceMod в каталогах ~/tf2/tf/addons/sourcemod{1,2}/gamedata.

Так же можно в core.cfg установить параметру "LogMode" значени "game" — тогда логи станут записываться не в отдельные файлы, а в логи игрового сервера. Подробнее в разделе "Логи"

Прочие файлы конфигурации разберём позже.

Однако есть ещё один файл конфигурации — ~/tf2/tf/cfg/sourcemod/sourcemod.cfg — он выполняется при каждой смене карт следом за server.cfg и является общим для всех инсталляций SourceMod. Поэтому оставляем в sourcemod.cfg лишь команды, общие для обоих серверов, а индивидуальные переносим в отдельные файлы для каждого сервера.

   $ dos2unix ~/tf2/tf/cfg/sourcemod/sourcemod.cfg
   $ cp ~/tf2/tf/cfg/sourcemod/sourcemod.cfg ~/cfg/sourcemod_default.cfg
   $ ln -s ~/tf2/tf/cfg/sourcemod ~/cfg/sm

Редактируем ~/tf2/tf/cfg/sourcemod/sourcemod.cfg, традиционно добавляем вывод "echo", исправляем "sm_show_activity" и устанавливаем в "sm_datetime_format" привычный формат вывода даты/времени.

sourcemod.cfg
echo "*** ~/tf2/tf/cfg/sourcemod/sourcemod.cfg"
// SourceMod Configuration File
// This file is automatically executed by SourceMod every mapchange.

// Specifies how admin activity should be relayed to users.
sm_show_activity 28

// Default datetime formatting rules when displaying to clients.
sm_datetime_format "%d %b %Y - %H:%M:%S"

Всё. Остальное удаляем. Позже, когда захочется установить для серверов свои параметры, то можно взять их из сохранённого ~/cfg/sourcemod_default.cfg и указать в каком-либо файле конфигурации сервера. Почему нельзя оставить всё как есть — в оригинальном sourcemod.cfg? А потому что он выполняется при каждой смене карт следом за server{1,2}.cfg — то есть любые установки, например, касающиеся резервных слотов, прописанные в server{1,2}.cfg будут перезаписаны значениями по умолчанию из этого файла. А те же резервные слоты мы будем настраивать для наших серверов по-разному.

При установке новых плагинов SourceMod, их файлы конфигурации могут автоматически создаваться в ~/tf2/tf/cfg/sourcemod/ и становиться общими для обеих инсталляций SourceMod. Собственно, там уже лежит файл с настройками для плагина funcommands.smx

Так же SourceMod по умолчанию периодически скачивает со своего сервера (update.sourcemod.net) обновления файлов с игровыми данными, что найдёт своё отражение в логах. На примере первого сервера (~/tf2/tf/addons/sourcemod1/logs/), строчки 3,4,5:

   L 03/21/2014 - 14:52:41: SourceMod log file session started (file "L20140321.log") (Version "1.5.3")
   L 03/21/2014 - 14:52:41: -------- Mapchange to cp_well --------
   L 03/21/2014 - 14:52:56: [UPDATER] Successfully updated gamedata file "sdkhooks.games/engine.csgo.txt"
   L 03/21/2014 - 14:52:56: [UPDATER] Successfully updated gamedata file "sdktools.games/engine.csgo.txt"
   L 03/21/2014 - 14:52:56: [UPDATER] Successfully updated gamedata file "sm-cstrike.games/game.csgo.txt"
   L 03/21/2014 - 14:52:56: [UPDATER] SourceMod has been updated, please reload it or restart your server.
   L 03/21/2014 - 14:55:26: SourceMod log file session started (file "L20140321.log") (Version "1.5.3")
   L 03/21/2014 - 14:55:26: -------- Mapchange to cp_well --------

Документация по SourceMod — настройка, управление, небольшой FAQ (eng).

Так как очередные обновления Team Fortress 2 могут нарушать хрупкое взаимодействие игры и SourceMod, то имеет смысл отслеживать новые версии и билды и регулярно обновляться.

Продолжение с описанием настройки плагинов и интерактивным взаимодействием игроков с сервером описано в разделе "Плагины SourceMod", а пока двинемся дальше — к настройке запуска серверов.

Автозапуск игровых серверов

Наши игровые сервера уже достаточно взрослые для того, чтобы можно было их включать в автозапуск. Для систем с System V init можно переделать ранее созданные скрипты запуска, либо использовать примеры из TF2 Wiki. Для систем с systemd, как у нас, делаем два файла служб, незатейливо именуемых srcds1.service и srcds2.service.

Справочно, для освежения материала: После всех добавлений (Записи, SourceMod), скрипт запуска того же первого сервера ~/start1.sh в полной комплектации должен был выглядеть как-то так:

start1.sh
#!/bin/sh
#
# Запуск первого сервера.

# Путь к каталогу с игрой, где лежит файл srcds_run
GAMEFOLDER=/home/game/tf2

CMDLINE="+sv_pure 2 -game tf +maxplayers 24 
    -pidfile ${GAMEFOLDER}/tf/srcds1.pid 
    -ugcpath ${GAMEFOLDER}/steamapps/workshop1 
    -replay reply1.cfg -replayserverdir server1 
    +exec autoexec1.cfg +servercfgfile server1.cfg 
    -port 27015 -steamport 26900 +clientport 27005 +tv_port 27020 -strictportbind 
    +sm_basepath addons/sourcemod1 +sm_corecfgfile addons/sourcemod1/configs/core.cfg"

# Запускаем игровой сервер
${GAMEFOLDER}/srcds_run ${CMDLINE}

Мы уже привыкли к скрипту srcds_run, поэтому будем и дальше использовать его. Надо только озаботиться автоматическим перезапуском игрового серевера при выполнении команд quit, _restart. Сейчас скрипт перезапускает сервер только если он закончился аварийно с ненулевым кодом выхода, либо с нулевым при включенном автообновлении.

Вариантов несколько. Первый — можно просто включить стандартное автообновление (секция "Автоматическое" в разделе "Обновление серверов"). Второй — создать копию скрипта с другим именем и поправить его на предмет вечного перезапуска сервера (исходный скрипт править не стоит — он может замениться при обновлении) и использовать его в дальнейшем. Третий — если планируется обновлять сервера самостоятельно, то можно включить автообновление, добавив -autoupdate и два его параметра-сателлита в командную строку запуска, но в качестве скрипта автообновления использовать файлик типа ~/cfg/tf2_quit, состоящий лишь из одной строчки с командой quit, то есть фактически, обновления не будут проверяться.

Знания умножают печали. Но выбор за вами. В нашем же случае, для первого сервера мы в файлах конфигурации ещё не прописывали критерии окончания раундов, а второй сервер вообще будет с нестандартными картами, вполне возможно, что и с бесконечными раундами, поэтому в автозапуске будем использовать третий вариант — с фиктивным автообновлением, а настоящее обновление — через регулярный запуск update.sh скрипта в crontab. Опять же, так интереснее.

Итак, файлы служб. Для удобства мы будем использовать терминальный мультиплексор tmux (желающие могут использовать вместо него screen), который будет запускать скрипт srcds_run. Параметры командной строки перешли практически неизменными из скриптов запуска, которые мы использовали до этого.

Так как игровые сервера запускаются от имени пользователя game, то по-хорошему, можно было бы создавать файлы запуска в пользовательском окружении, в ~/.config/systemd/user/. Но данный раздел документации тестировался на centos 7, где запуск systemd в пользовательском режиме не функционирует, поэтому файлы служб мы создаём от имени root.

Заходим как root, создаём файл /etc/systemd/system/srcds1.service для первого сервера.

srcds1.service
# /etc/systemd/system/srcds1.service
#
# Team Fortress 2 Source Dedicated Server

[Unit]
Description=Team Fortress 2 Source Dedicated Server No 1
After=network.target

[Service]
User=game
Group=game
WorkingDirectory=/home/game/Steam
Type=oneshot
RemainAfterExit=yes
PIDFile=/home/game/tf2/tf/srcds1.pid
ExecStart=/usr/bin/tmux -L socket1 new-session -d '/home/game/tf2/srcds_run 
    +sv_pure 2 -game tf +maxplayers 24 
    -pidfile /home/game/tf2/tf/srcds1.pid 
    -ugcpath /home/game/tf2/steamapps/workshop1 
    -replay replay1.cfg -replayserverdir server1 
    +exec autoexec1.cfg +servercfgfile server1.cfg 
    -port 27015 -steamport 26900 +clientport 27005 +tv_port 27020 -strictportbind 
    -autoupdate -steam_dir /home/game/Steam -steamcmd_script /home/game/cfg/tf2_quit 
    +sm_basepath addons/sourcemod1 +sm_corecfgfile addons/sourcemod1/configs/core.cfg'

ExecStop=/usr/bin/tmux -L socket1 send-keys "quit" Enter ; /usr/bin/sleep 5s ; /usr/bin/tmux -L socket1 kill-session
ExecReload=/usr/bin/tmux -L socket1 send-keys "_restart" Enter
ExecStopPost=/usr/bin/rm -f /home/game/tf2/tf/srcds1.pid

[Install]
WantedBy=multi-user.target

Небольшое пояснение по параметрам ExecStop и ExecReload. Для завершения работы сервера мы посылаем ему лучи любви и команду quit в консоль, ждём несколько секунд для завершения работы, и, пока всё не запустилось заново, прибиваем сессию. Схожий механизм для рестарта сервера. При желании можно добавить вывод предупреждения игрокам о грядущем рестарте — как это было в примере одного из скриптов для обновления, в соответствующем разделе.

Копируем srcds1.service в srcds2.service, корректируем пути, порты и имя tmux сокета. Сохраняем. /etc/systemd/system/srcds2.service:

srcds2.service
# /etc/systemd/system/srcds2.service
#
# Team Fortress 2 Source Dedicated Server

[Unit]
Description=Team Fortress 2 Source Dedicated Server No 2
After=network.target

[Service]
User=game
Group=game
WorkingDirectory=/home/game/Steam
Type=oneshot
RemainAfterExit=yes
PIDFile=/home/game/tf2/tf/srcds2.pid
ExecStart=/usr/bin/tmux -L socket2 new-session -d '/home/game/tf2/srcds_run 
    +sv_pure 2 -game tf +maxplayers 24 
    -pidfile /home/game/tf2/tf/srcds2.pid 
    -ugcpath /home/game/tf2/steamapps/workshop2 
    -replay replay2.cfg -replayserverdir server2 
    +exec autoexec2.cfg +servercfgfile server2.cfg 
    -port 27016 -steamport 26901 +clientport 27006 +tv_port 27021 -strictportbind 
    -autoupdate -steam_dir /home/game/Steam -steamcmd_script /home/game/cfg/tf2_quit 
    +sm_basepath addons/sourcemod2 +sm_corecfgfile addons/sourcemod2/configs/core.cfg'

ExecStop=/usr/bin/tmux -L socket2 send-keys "quit" Enter ; /usr/bin/sleep 5s ; /usr/bin/tmux -L socket2 kill-session
ExecReload=/usr/bin/tmux -L socket2 send-keys "_restart" Enter
ExecStopPost=/usr/bin/rm -f /home/game/tf2/tf/srcds2.pid

[Install]
WantedBy=multi-user.target

Здесь мы специально запускаем две отдельные копии tmux, каждую для своего игрового сервера. Можно было бы, конечно, обойтись сессиями внутри одного tmux (tmux new-session -d -s tf1 и tmux new-session -d -s tf2), но тогда это стало бы дополнительной точкой для epic fail — когда нечаянный Ctrl-C прибил бы все наши сервера.

Не забываем создать файлик ~/cfg/tf2_quit с содержимым:

tf2_quit
quit

Проверяем, что оба .service файла доступны на запись только для root, затем запускаем, включаем:

   # systemctl start srcds1
   # systemctl start srcds2
   # systemctl enable srcds1
   # systemctl enable srcds2

Но сейчас у нас глупая ситуация — игровые сервера стартуют при запуске нашего сервера, но пользователь game не может ими управлять стандартными способами с помощью systemctl (start, stop, reload), хотя вполне может ими "управлять" при помощи Ctrl+C в tmux сессии, с последующим запуском вручную. Исправляем несправедливость.

Пока мы ещё root, запускаем visudo, корректируем файл sudoers, дописав в конец:

sudoers
Defaults:game !requiretty
game    ALL=    NOPASSWD:    /usr/bin/systemctl start srcds1.service, /usr/bin/systemctl start srcds2.service
game    ALL=    NOPASSWD:    /usr/bin/systemctl stop srcds1.service, /usr/bin/systemctl stop srcds2.service
game    ALL=    NOPASSWD:    /usr/bin/systemctl reload srcds1.service, /usr/bin/systemctl reload srcds2.service
game    ALL=    NOPASSWD:    /usr/bin/systemctl status srcds1.service, /usr/bin/systemctl status srcds2.service
game    ALL=    NOPASSWD:    /usr/bin/systemctl enable srcds1.service, /usr/bin/systemctl enable srcds2.service
game    ALL=    NOPASSWD:    /usr/bin/systemctl disable srcds1.service, /usr/bin/systemctl disable srcds2.service

Здесь мы пользователю game предоставляем возможность посредством sudo, без запроса пароля (которого у него и нет) выполнять команды start, stop, reload, status и для кучи enable с disable для первого и второго сервера. А параметр "Defaults:game !requiretty" позволит нам запускать sudo из crontab файла. По желанию можно добавить разрешение на использование иных команд типа is-* и прочих.

Разрешения на команды вида systemctl edit [--full] мы предоставлять не будем. Всё-таки безопасность должна быть… безопасной.

Выходим из-под root, проверяем из-под game:

   $ sudo -l

   Matching Defaults entries for game on this host:
    ...
    ..., !requiretty

   User game may run the following commands on this host:
    (root) NOPASSWD: /usr/bin/systemctl start srcds1.service, (root) /usr/bin/systemctl start srcds2.service
    (root) NOPASSWD: /usr/bin/systemctl stop srcds1.service, (root) /usr/bin/systemctl stop srcds2.service
    (root) NOPASSWD: /usr/bin/systemctl reload srcds1.service, (root) /usr/bin/systemctl reload srcds2.service
    (root) NOPASSWD: /usr/bin/systemctl status srcds1.service, (root) /usr/bin/systemctl status srcds2.service
    (root) NOPASSWD: /usr/bin/systemctl enable srcds1.service, (root) /usr/bin/systemctl enable srcds2.service
    (root) NOPASSWD: /usr/bin/systemctl disable srcds1.service, (root) /usr/bin/systemctl disable srcds2.service

Можно тут же запустить sudo systemctl status srcds1.service, потестировать.

Команды необходимо будет вводить без сокращения параметров. То есть sudo systemctl status srcds1.service — норм, а вот sudo systemctl status srcds1 — уже не торт.

Если при манипуляциях с игровыми серверами с помощью systemctl выдаётся ошибка вида "Failed to stop srcds1.service: Interactive authentication required." — то значит вы забыли про sudo :-)

Когда всё заработает, можно будет работать с консолями серверов уже как пользователь game, подключаясь через tmux:

   $ tmux -L socket1 attach
   $ tmux -L socket2 attach

Отключаться от tmux сессии — Ctrl+b, d.

Можно прописать алиасы в ~/.bash_profile:

.bash_profile
alias tf1="tmux -L socket1 attach"
alias tf2="tmux -L socket2 attach"

По умолчанию, размер хранимой истории для tmux составляет 2000 строк, но его можно увеличить, например до 10000 строк, создав файл ~/.tmux.conf вида:

.tmux.conf
set-option -g history-limit 10000
set-option -g set-remain-on-exit on

Вторая команда не закрывает tmux сессию при завершении основной программы, что даёт возможность почитать её последнее прости в консоли.

Перемещаться по истории — Ctrl+b, [, а далее обычными клавишами — Up/Down, PgUp/PgDown. Выход из этого режима — q.

Логи

Логов у нас будет много и разных. А именно:

Логи cron

У нас через cron запускаются скрипты проверки обновлений, сервера статистики HLstatsX, удаления устаревших Записей, а их вывод отражается в /var/log/cron в виде

   Jun 15 12:55:01 server CROND[584]: (game) CMD (cd $HOME/stat/scripts && ./run_hlstats start 2 27500 1)
   Jun 15 12:55:01 server CROND[583]: (game) CMDOUT (HLstatsX:CE daemon control)
   Jun 15 12:55:01 server CROND[583]: (game) CMDOUT (http://www.hlxce.com)
   Jun 15 12:55:01 server CROND[583]: (game) CMDOUT (---------------------------)
   Jun 15 12:55:01 server CROND[583]: (game) CMDOUT (Daemon is already running on port 27500)
   Jun 15 12:55:01 server CROND[583]: (game) CMDOUT (Daemon is already running on port 27501)
   ...

Так как /var/log/cron никто прочитать не сможет кроме пользователя root, а ему это не интересно, то хотелось бы дать доступ пользователю game к логам его crontab файла. Конечно, можно для каждого скрипта в конце строки запуска дописать что-то вида "… >> $HOME/log/cron.log" но эти "логи" будут без меток времени, да и вообще, кустарщина. Более культурный варинт "… | /usr/bin/logger --tag srcds" ничего не меняет — ну будут сообщения попадать не в /var/log/cron, а в /var/log/messages, разницы-то.

Поэтому мы в настройках демона rsyslog сделаем так, что сообщения от cron, начинающиеся с имени пользователя "(game)", перенаправляются в файл /home/game/log/cron.log, владельцем которого является пользователь game, и не попадают в дальнейшую обработку (в "cron.* /var/log/cron")

У нас установлен rsyslogd версии 8.19, и в /etc/rsyslog.conf директива $IncludeConfig /etc/rsyslog.d/*.conf находится до правила cron.* /var/log/cron, поэтому перехватывать сообщения от наших скриптов будем, создав как пользователь root файл /etc/rsyslog.d/srcds-10-cron.conf с содержимым:

srcds-10-cron.conf
# /etc/rsyslog.d/srcds-10-cron.conf

if $syslogfacility-text == "cron" and $msg startswith " (game)" then {
  action(
    type = "omfile"
    fileOwner = "game"
    fileGroup = "game"
    file = "/home/game/log/cron.log"
  )
  stop
}

Подробнее об использованных командах — omfile, properties.

Проверяем синтаксис, если всё ok, то перезапускаем демона и наслаждаемся свежесозданным логом.

   # rsyslogd -N 2
   # systemctl restart rsyslog

Пока мы ещё root, настраиваем ротацию логов, создав файл /etc/logrotate.d/srcds-cron:

srcds-cron
#/etc/logrotate.d/srcds-cron

/home/game/log/cron.log {
    su game game
    daily
    dateext
    maxage 3
    missingok
    copytruncate
    compress
    notifempty
}

Проверяем:

   # logrotate --debug --force /etc/logrotate.d/srcds-cron

Логи клиента Steam

Эти логи находятся в ~/Steam/logs/. Ротация происходит автоматически, силами самого клиента. Текущий лог переименовывается в *.previous.txt, предыдущий *.previous.txt предварительно удаляется. Специально мы их обрабатывать не будем, какой-то необходимости хранить исторические данные нет — текущие проблемы с подключением можно посмотреть в активных логах, а что было с коннектом к серверам Valve девятого термидора второго года — nobody cares...

Логи веб-сервера

У нас с игровыми серверами сотрудничают три виртуальных веб-сервера, обслуживающих:

  • Fast Download, логи в /var/www/fastdl.example.org/log/
  • Записи (Replay), логи в /var/www/replay.example.org/log/
  • HLstatsX, логи в /var/www/stat.example.org/log/

Ротация этих логов у нас настроена в /etc/logrotate.d/srcds-nginx, предполагается, что логи с ошибками будем просматривать самостоятельно, а логи доступа можно скармливать хоть Elasticsearch, Kibana и Logstash — но описание ELK стека вне объёма данного проекта.

Логи SourceMod

Эти логи находятся в каталогах ~/tf2/tf/addons/sourcemod{1,2}/logs. Их настройки прописаны в соответствующих ~/tf2/tf/addons/sourcemod{1,2}/configs/core.cfg:

Logging on
логи вкл/выкл

LogMode daily
ротация логов — ежедневная (daily), при смене карты (map), и третий режим (game) — писать в логи игрового сервера.

DebugSpew no
детализировать ли в логах обновление игровых данных

Логи SourceMod ведутся довольно скромно, поэтому достаточно настроить их регулярную ротацию, либо не заморачиваться и просто в core.cfg прописать LogMode game, тогда они гармонично впишутся в логи игровых серверов, как-то так:

   L 06/20/2016 - 04:53:24: Executing dedicated server config file server1.cfg
   L 06/20/2016 - 04:53:32: server_cvar: "sv_tags" "HLstatsX:CE,cp,increased_maxplayers"
   L 06/20/2016 - 04:53:32: tf_server_identity_account_id not set; not logging into registered account
   L 06/20/2016 - 04:53:32: server_cvar: "sv_contact" "game@example.org"
   L 06/20/2016 - 04:53:33: [UPDATER] Successfully updated gamedata file "core.games/common.games.txt"
   L 06/20/2016 - 04:53:33: [UPDATER] Successfully updated gamedata file "sdkhooks.games/game.doi.txt"
   L 06/20/2016 - 04:53:33: [UPDATER] Successfully updated gamedata file "sdkhooks.games/master.games.txt"
   L 06/20/2016 - 04:53:33: [UPDATER] Successfully updated gamedata file "sdktools.games/game.doi.txt"
   L 06/20/2016 - 04:53:33: [UPDATER] Successfully updated gamedata file "sdktools.games/master.games.txt"
   L 06/20/2016 - 04:53:33: [UPDATER] SourceMod has been updated, please reload it or restart your server.
   L 06/20/2016 - 04:53:33: Connection to Steam servers successful.
   L 06/20/2016 - 04:53:33:    Public IP is 192.0.2.0.
   L 06/20/2016 - 04:53:33: Assigned anonymous gameserver Steam ID [A:1:123456789:1234].
   L 06/20/2016 - 04:53:33: VAC secure mode is activated.
   L 06/20/2016 - 04:53:34: server_cvar: "sm_nextmap" "cp_well"

Логи игровых серверов

Логи игровых серверов находятся в ~/log/server{1,2}/. Минимальную настройку логов мы провели при написании конфигурационных файлов, но сейчас рассмотрим значение некоторых переменных поподробнее:

log off
глобально включает (on) ведение логов данного игрового сервера. Логи могут направляться в файл (sv_logfile), на консоль сервера (sv_logecho), транслироваться по UDP (logaddress_add).

sv_logfile 1
включает запись логов в файл (1), при этом требуется включение предыдущей командой. Каталог для логов и формат имени файлов задаются параметрами sv_logsdir и sv_logfilename_format.

sv_logsdir logs
каталог для логов. По умолчанию, был бы ~/tf2/tf/logs, но так как мы логи наших двух серверов разводим по разным каталогам, то каталоги /home/game/log/server1 и /home/game/log/server2 соответственно. Хотя, конечно, можно было бы писать в один каталог, но с разным именованием файлов.

sv_log_onefile 0
вести запись логов в один файл (1), либо при смене карты создавать новый (0), например: l0618000.log -> l0618001.log -> l0618002.log… l0619000.log -> l0619001.log и так далее. Отметим две особенности при включении данного параметра: во-первых, при наступлении новых суток автоматической ротации лога l0618000.log -> l0619000.log не произойдёт; во-вторых, если в консоли или посредством какого-нибудь файла конфигурации сделать log off и тут же log on, то запись начнётся в новый файл, с инкрементированным номером.

sv_logfilecompress 0
при начале записи в новый файл логов, старый будет сжиматься gzip и переименовываться в <logfilename>.log.gz. Задумка хорошая, реализация под Linux хромает. Так, при установке этой переменной в "1" и смене карты (что, при нашем sv_log_onefile = "0" вызывает запись логов в новый файл), на консоли сервера появляется ругань, создаётся пустой .gz файл, а старый файл лога не удаляется. А всё из-за регистра первого символа в имени файла — "l" vs "L", что принципиально в Linux:

      ---- Host_Changelevel ----
      Compressing /home/game/log/server2/L0713019.log to /home/game/log/server2/L0713019000.log.gz...
      Success. Removing /home/game/log/server2/L0713019.log.
      Unable to remove /home/game/log/server2/L0713019.log!
      Unable to remove /home/game/log/server2/L0713019.log!
      Server logging data to file /home/game/log/server2/L0713020.log
      Applying new item schema, version 5C0BC93D

sv_logfilename_format ""
формат именования файлов с логами. Должен указываться до параметра "log on". Если специально не указывать, то файлы с логами сейчас именуются как l<Месяц><День><000...999>.log, где первый символ — <Latin Small Letter L>, а последнее трёхзначное число в имени инкрементируется для каждого нового лога, в пределах текущих суток. Можно задавать свой формат, с использованием параметров функции strftime. То есть, при указании "sv_logfilename_format %Y%m%d" файл будет выглядеть как "20160714.log". Автонумерация в этом случае будет вида 20160714.log -> 20160714_000.log -> 20160714_001.log и так далее. Забавно, но при явной установке формата, начинает работать параметр sv_logfilecompress — предыдущий файл лога действительно архивируется.

log_verbose_enable 0
включает (1) подробное ведение логов. Так, каждые несколько секунд (определяется log_verbose_interval) туда пишутся текущие трёхмерные координаты игроков. Лог разрастается неимоверно. Включать, пожалуй, имеет смысл разве что для построения тепловых карт движения игроков, с селекцией по классам. Что-то вроде http://geit.uk/blog/player-flow/.

log_verbose_interval 3.0
задаёт интервал записи подробного лога. По умолчанию — каждые 3 секунды.

sv_rcon_log 1
при отключении (0), не выводит на консоль и в лог поступающие rcon команды (результаты выполнения команд выводятся на консоль по-прежнему). Так как в нашей конфигурации rcon использует исключительно HLstatsX, то экономия в части размеров логов невелика, но всё же спама на консоли сервера будет поменьше, без вот этого:

      rcon from "192.0.2.0:60533": command "status"
      rcon from "192.0.2.0:60533": command "hlx_sm_psay "30" 2 "Round Over - All actions/frags are ignored <...>
      rcon from "192.0.2.0:60533": command "hlx_sm_psay "30" 1 "Red got 10 points for Round Win""
      rcon from "192.0.2.0:60533": command "hlx_sm_psay "30" 1 "Asuka got 2 points (1,025) for Kill Assist""

sv_logecho 1
дублирует вывод лога на консоль. Естественно, отключаем (0).

sv_logbans 0
при включении (1) фиксирует информацию о бане игрока в лог:

      L 07/13/2016 - 23:09:31: Addip: "<><><>" was banned by IP "for 10.00 minutes" by "Console" (IP "10.1.1.1")

logaddress_add
указывает адрес: порт, куда будут транслироваться логи по UDP, в нашем случае для HLstatsX. Первому серверу мы устанавливали 192.0.2.0:27500, второму — 192.0.2.0:27501

logaddress_del
удаляет адрес: порт из трансляции.

logaddress_delall
удаляет все адреса из трансляции

developer 0
обеспечивает более подробный вывод информации на консоль сервера. Варианты значений — 0 (по умолчанию), 1, 2, 3...

Вот логи игровых серверов имеет смысл хранить некоторое время, на случай жалоб на того или иного игрока — мат в чате, оскорбление других игроков, двести восемьдесят вторая статья и так далее.

Обычно логи сервера при полной загрузке и интенсивной движухе растут на 3.5 — 4.0 тыс. строк в час, около 0.5 — 0.6 Мб.

Запись логов ведётся таким способом, что если запускать ротацию логов с помощью logrotate без параметра copytruncate в файле настроек, то после неё новых логов мы не увидим до смены карты (и то, при sv_log_onefile 0). Запуск же с параметром copytruncate приводит к обрезанию старого лога посередине строки (как повезёт — так как игровые сервера, если не включать sv_logflush 1, буферизируют запись логов в файл, причём не построчно, а покилобайтно) и бинарному мусору в начале нового файла, да так, что при уже его ротации, архив состоит из одной строки "Binary file (standard input) matches".

Учитывая это, работу с логами серверов можно организовать следующими способами:

  1. Очень ленивый. Ничего не делать. При наличии инстинкта самосохранения всё же обеспечить удаление старых логов. Ну или просто отключить их ведение.

  2. Ленивый. Для обеспечения ротации логов и экономии места на диске включить комбинацию "sv_log_onefile 0", "sv_logfilecompress 1" и "sv_logfilename_format %Y%m%d", добавить в crontab find $HOME/log/server{1,2}/*.gz -type f -mtime +30 -delete, что позволит обойтись без logrotate. Хороший, годный вариант. В случае "бесконечных" карт можно либо уповать на время от времени случающиеся обновления серверов, при перезапуске гарантирующие ротацию логов, либо принудительно перезапускать карту хотя бы раз в неделю — добавить в crontab запуск команды tmux -L socket1 send-keys "changelevel_next" Enter в часы минимальной загрузки.

  3. Активный. Если есть необходимость мониторить логи в реальном режиме времени, как-то их анализировать и обрабатывать, то можно использовать возможности rsyslog демона. Плагин omfile — File Output Module мы использовали выше в обработке лога cron, а здесь можно использовать imfile — Text File Input Module.

Попробуем настроить сохранение чата игроков первого сервера в отдельном логе. Cоздаём (из-под root) файл /etc/rsyslog.d/srcds-20-chat.conf:

srcds-20-chat.conf
#/etc/rsyslog.d/srcds-20-chat.conf

module(load="imfile" mode="inotify")

# Мониторит все *.log файлы первого сервера
input(
  type = "imfile"
  tag = "srcds1:"
  file = "/home/game/log/server1/*.log"
  ruleset = "chat-1"
)

# $now - текущая дата, на момент записи лога, в формате YYYY-MM-DD
template (name="chat1-log-name" type="string" string="/home/game/log/chat1-%$now%.log")

# Мониторим общий чат (say), командный (say_team), и steam id и ip игроков, входящих на сервер
ruleset(name = "chat-1") {
  if ($msg contains [" say ", " say_team ", " connected, address "]) then {
    action(
      type = "omfile"
      fileOwner = "game"
      fileGroup = "game"
      dynafile = "chat1-log-name"
    )
  }
}

При таких настройках, лог чата будет выглядеть как:

   Jul 23 10:40:46 server srcds1: L 07/23/2016 - 10:40:27: "Asuka<3><[U:1:12345678]><Blue>" say_team "Valar morghūlis"
   Jul 23 10:40:46 server srcds1: L 07/23/2016 - 10:40:34: "Rei<4><[U:1:09876543]><Blue>" say "Valar dohaeris, desu"

Тут стандартный формат rsyslogd — дата+время, имя сервера (железного), метка из input, и сама строчка лога. Отличие в секундах вызвано буферизацией записи игровых логов. При желании можно настроить дополнительную проверку текста сообщений на ключевые слова с немедленным извещением нас по электронной почте (модуль ommail в rsyslog)

Проверяем синтаксис, если всё ok, то перезапускаем демона.

   # rsyslogd -N 2
   # systemctl restart rsyslog

Если новый лог будете создавать в том же каталоге, откуда считываются исходные (параметр file в секции input), то убедитесь, что его имя не попадает под маску файлов из секции input, которые мониторит rsyslogd. А то получится очень, гм… рекурсивненько.

Возвращаясь к настройкам ведения логов, стоит отметить ещё два параметра:

con_logfile ""
создаёт отдельный файл лога, куда записывается всё что выводится на консоль сервера. Имя файла указывается либо с полным путём, либо относительно каталога ~/tf2/tf/ (не logs!). Если не указывать расширение ".log", то оно добавится автоматически. Имеет аналогичный параметр командной строки -consolelog <file> — только там лучше уже указывать расширение, а то получится забавно — при старте сервера создадутся три консольных лога: сначала запись пойдёт в ~/tf2/bin/<file>, затем в ~/tf2/tf/<file>, ну и наконец в ~/tf2/tf/<file>.log.

con_timestamp 0
при включении (1), весь вывод в консольный лог будет предваряться метками времени, как в примере ниже. Если указывать в командной строке запуска вместе с предыдущим параметром, как +con_timestamp 1 -consolelog <file>, то метки начнутся лишь с третьего файла.

В отличие от серверных логов, запись в консольный лог идёт построчно, и вполне корректно работает logrotate с параметром copytruncate.

Следует быть осторожным с включением записи этого, безусловно полезного лога. Иногда на игровой сервер что-то находит, и он начинает мощно спамить в консоль сообщениями вида:

   07/15/2016 - 14:59:59: DataTable warning: player: Out-of-range value (72483.898438/65536.000000) in SendPropFloat 'm_flLastDamageTime', clamping.
   07/15/2016 - 14:59:59: DataTable warning: player: Out-of-range value (72492.539062/65536.000000) in SendPropFloat 'm_flLastDamageTime', clamping.
   07/15/2016 - 14:59:59: DataTable warning: player: Out-of-range value (72479.742188/65536.000000) in SendPropFloat 'm_flLastDamageTime', clamping.

При скорости потока, как правило ~ 125 сообщений в секунду, такими темпами файл с консольным логом прирастает на ~ 64 Мб в час, 1.5 Гб в сутки, что особенно неприятно в случае "долгоиграющих" карт, так как при смене карты эта ошибка обычно исчезает. Лечится либо прописыванием критериев, обеспечивающих регулярную ротацию карты, либо смирением с полуторагигабайтным логом в сутки, тем более, что сжимаются они неплохо, а хранить их можно недолго.

Настраиваем ротацию и этих логов, создав из-под root файл /etc/logrotate.d/srcds-server:

srcds-server
#/etc/logrotate.d/srcds-server

/home/game/log/console*.log
{
    su game game
    daily
    dateext
    rotate 7
    copytruncate
    notifempty
    missingok
    compress
#    compresscmd /home/game/logrotate-filter.sh
}

Проверяем логику работы:

   # logrotate --debug --force /etc/logrotate.d/srcds-server

Можно туда добавить костыль — строчку "compresscmd /home/game/logrotate-filter.sh", а сам ~/logrotate-filter.sh вида:

logrotate-filter.sh
#!/bin/sh

/bin/grep -v ": DataTable warning:" | /bin/gzip -6 

то есть в качестве архиватора будет вызываться не gzip а этот скрипт, который входной поток пропустит через grep, вырезая DataTable warning, а остальное передавая gzip, as planned.

Кстати, как вариант — можно включить дублирование лога в консоль (sv_logecho 1), выключить ведение основного лога (sv_logfile 0) и активировать запись консольного, и иметь дело только с ним. В лог будет писаться микс вида:

   07/24/2016 - 18:50:46: DataTable warning: (class info_particle_system): Out-of-range value (-1.000000 / -1.000000)
   07/24/2016 - 18:52:21: Attempted to add job to job queue that has already been completed
   07/24/2016 - 18:57:11: DataTable warning: (class info_particle_system): Out-of-range value (-1.000000 / -1.000000)
   07/24/2016 - 18:57:48: L 07/24/2016 - 18:57:48: "GLaDOS<20><BOT><Red>" triggered "player_builtobject"
   07/24/2016 - 18:57:50: L 07/24/2016 - 18:57:50: "Companion Cube<34><BOT><Blue>" killed "GLaDOS<20><BOT><Red>" with "knife"
   07/24/2016 - 19:00:24: L 07/24/2016 - 19:00:24: "AimBot<23><BOT><Red>" triggered "domination" against "DeadHead<10><BOT><Blue>"
   07/24/2016 - 19:00:25: L 07/24/2016 - 19:00:25: "AimBot<23><BOT><Red>" triggered "killedobject" (object "OBJ_SENTRYGUN")
   07/24/2016 - 19:00:32: DataTable warning: info_particle_system: Out-of-range value (1.000000/1.000000)
   07/24/2016 - 19:00:49: DataTable warning: (class info_particle_system): Out-of-range value (-1.000000 / -1.000000)

Единственное неудобство — дублирование меток времени у вставок из игрового лога. Можно отключить у консольного (con_timestamp 0), но это тоже не дело. Если только пропускать этот лог через rsyslog, в ruleset парсить с помощью regex и формировать новый файл с использованием своего шаблона. Но это для энтузиастов.

Логи сервера статистики

Сервер статистики HLstatsX у нас настроен так, что логи его создаются в ~/stat/scripts/logs/, и по своему содержимому практически аналогичны серверным логам, поэтому после первоначальной настройки, когда покажется что всё заработало, их мы отключаем, установив в ~/stat/scripts/hlstats.conf параметр "DebugLevel 0"

Привязка к Steam и QuickPlay

При запуске наших серверов наверняка бросались в глаза сообщения (строки 2 и 7):

   Setting breakpad minidump AppID = 232250
   No account token specified; logging into anonymous game server account.  (Use sv_setsteamaccount to login to a persistent account.)
   ConVarRef room_type doesn't point to an existing ConVar
   Executing dedicated server config file server1.cfg
   ...
   Connection to game coordinator established.
   tf_server_identity_account_id not set; not logging into registered account
   *** ~/cfg/server1.cfg
   ...

Первое сообщение уведомляет, что наш сервер подключен к мастер-серверам Valve "анонимно" (хотя кто знает, что сервер сливает при подключении...), без входа в серверную учётную запись. Второе сообщение — о том, что мы не зарегистрированы в QuickPlay. Посмотрим поподробнее.

Серверная учётная запись

Это относительно недавнее нововведение, анонсированное в феврале 2014 года — hlds_announce, либо в открытом доступе, например, тут. На данный момент актуально лишь для двух игр — Counter-Strike: Global Offensive и Team Fortress 2, причём для первой регистрация обязательна. Регистрация сервера даёт как приятную, так и полезную особенности. Приятная — при смене адреса или порта у нашего сервера, новый адрес автоматически обновится в закладках у игроков, которые его в своё время добавили. Ну и полезная — позволяет теперь Valve, при обнаружении что тот или иной игровой сервер (пока только для CS:GO) нарушает их политику, блокировать не ip адрес целиком, а лишь конкретный Steam аккаунт нарушителя, на который куплена игра и к которому привязан этот серверный аккаунт. А точнее — все аккаунты Steam, к которым привязан номер телефона аккаунта-нарушителя. Большое облегчение для владельцев игровых хостингов CS:GO, наверное.

Но вернёмся к нашей игре. В упомянутом анонсе Valve от 2014 года описан процесс регистрации посредством получения ключа к api на http://steamcommunity.com/dev, последующим запросом с ним к IGameServersService/CreateAccount и так далее. Для общего развития можно пройти через это всё, а можно (XXI век всё же) перейти на страницу http://steamcommunity.com/dev/managegameservers, что мы и сделаем. Там же приведены актуальные требования для регистрации. На настоящий момент они таковы:

  • Ваш аккаунт Steam не должен быть заблокирован.
  • Ваш аккаунт Steam должен иметь неограниченные права.
  • К вашему аккаунту Steam должен быть прикреплен действующий номер телефона.
  • На вашем аккаунте Steam должна быть игра, для которой вы создаете аккаунт сервера.
  • Вы можете создать до 1000 аккаунтов серверов игры.

Лучше не использовать основной игровой аккаунт, если он у вас есть, а завести новый. Запускаем клиент Steam, регистрируем новую учётную запись (п.1 — ok), пополняем счёт на эквивалент 5 USD (п.2 — ok), в свойствах аккаунта привязываем номер телефона (п.3 — ok), добавляем в библиотеку игр Team Fortress 2 (п.4 — ok). Учитывая утвердительный ответ на вопрос "Do VAC and Game bans apply to all accounts on a phone number?" в [Базе Знаний] (https://support.steampowered.com/kb_article.php?ref=8625-WRAH-9030), имеет смысл использовать отдельный телефонный номер, только для этого аккаунта. Достаточно лишь привязать номер, активировать Steam Guard нет необходимости:

Game server login token

Если все требования мы выполнили, то переходим на страницу https://steamcommunity.com/dev/managegameservers, логинимся, если ещё не, и в самом низу видим поля для получения нового токена. Заполняем. Выполняем.

Create game server login token

Если всё успешно, то в табличке мы видим наш gameserver login token:

New game server login token

Его мы прописываем в ~/cfg/autoexec1.cfg:

autoexec1.cfg
//...

// Steam Gameserver Account
sv_setsteamaccount 3A820F219B470281C00IDDQD00A4D210

Запускаем первый сервер, смотрим (строки 2 и 8):

   Setting breakpad minidump AppID = 232250
   Logging into Steam game server account
   ConVarRef room_type doesn't point to an existing ConVar
   Executing dedicated server config file server1.cfg
   ...
   Connection to Steam servers successful.
      Public IP is 192.0.2.0.
   Assigned persistent gameserver Steam ID [G:1:21].
   VAC secure mode is activated.

Вместо привычного "Assigned anonymous gameserver Steam ID [A:1:1724597452:5521]" мы видим наш теперь постоянный Steam ID — [G:1:21]. "G" — GameServer, а ранее был "A" — AnonGameServer. Подробнее — в wiki.

Теперь на локальном компьютере запустим Team Fortress 2 из обычного, игрового аккаунта, добавляем, если ещё не, наш сервер в закладки. Открываем каталог C:Program FilesSteamuserdata<игровой id>7remote. Там должен быть файлик serverbrowser_hist.vdf, в котором хранятся закладки и история. Ищем в закладках наш сервер и видим, что теперь для него прописан серверный аккаунт (строка 9):

   "Favorites"
   {
     "4"
     {
       "name"         "192.0.2.0:27015"
       "address"      "192.0.2.0:27015"
       "LastPlayed"   "1476177442"
       "appid"        "0"
       "accountid"    "21"
     }
   }

Идентификатор accountid совпадает с тем, который мы увидели в консоли сервера.

Необходимо иметь в виду, что полученный нами токен при его неиспользовании в течение некоторого времени блокируется и необходимо использовать команду "Regenerate token" на той странице, где мы его получали.

Так что если при запуске сервера выдаются сообщения вида:

   Could not establish connection to Steam servers.  (Result = 106)
   enum_names.cpp (136) : Assertion Failed: Missing String for EResult (106)

то, как правило, это означает что токен недействителен — либо истёк срок неактивности, либо ошибка в самой записи токена. Смотрим на странице http://steamcommunity.com/dev/managegameservers, не истёк ли срок годности токена. Зная свой Steam Web API Key можно использовать интерфейс IGameServersService — для каждого login_token смотреть его is_expired.

QuickPlay

UPDATE, пока номер готовился в печать: На данный момент the quickplay system is no longer in use for Team Fortress 2.

quickplay

Поэтому я просто оставлю это здеь.

Для привлечения игроков на сервера сообщества была создана система QuickPlay. Требования к серверам время от времени меняются, поэтому с актуальными критериями лучше ознакомиться на https://support.steampowered.com/kb_article.php?ref=2825-AFGJ-3513. На данный момент основных требований несколько — сервер должен быть зарегистрирован, настройки сервера, карты и модификации должны соответствовать указанным в статье. Наш первый сервер выполняет все требования, за исключением регистрации, которой сейчас и займёмся. Это не та регистрация с использованием sv_setsteamaccount из секции выше, а отдельная, для осуществления которой на свойм компьютере запускаем клиента Steam, логинимся с той же учётной записью, которую создали ранее — это не обязательно, но так будет единообразнее. Запускаем игру Team Fortress 2, открываем в игре консоль — ~, вводим там команду cl_gameserver_create_identity. Нам в ответ выдаст:

   cl_gameserver_create_identity
   Request to create a game server account sent--please wait.
   Game server account created successfully!
   Set these convars on your game server to have it log in and receive benefits:
   tf_server_identity_account_id 284181
   tf_server_identity_token "18a>qPosnHYia?a"

Вот эти две последние строчки мы прописываем в ~/cfg/autoexec1.cfg:

autoexec1.cfg
//...

// QuickPlay
tf_server_identity_account_id 284181
tf_server_identity_token "18a>qPosnHYia?a"

Запускаем первый сервер, смотрим (строки 2, 9, 10):

   Connection to game coordinator established.
   Received auth challenge; signing into gameserver account...
   *** ~/cfg/server1.cfg
   ...
   Connection to Steam servers successful.
      Public IP is 192.0.2.0.
   Assigned persistent gameserver Steam ID [G:1:21].
   VAC secure mode is activated.
   Game server authentication: SUCCESS! Standing: Good. Trend: Steady
      Successfully logged into gameserver account 284181.
   For more information about gameserver accounts, visit https://support.steampowered.com/kb_article.php?ref=2825-AFGJ-3513.

Ну всё, теперь ждём, когда к нам толпой повалят игроки.

Если понадобится временно вывести сервер из QuickPlay, то не обязательно править autoexec1.cfg и перезапускать сервер. Можно использовать команду tf_server_identity_disable_quickplay 1.

Со временем, обещает Valve, эти tf_serveridentity аккаунты будут заменены серверными учётными записями.

Автор: abrca

Источник

Поделиться новостью

* - обязательные к заполнению поля