- Записи
- Настройка веб-сервера
- Настройка игрового сервера
- Включение
- Обслуживание
- SourceTV
- Ускорение скачивания контента (Fast Download)
- Настройка веб-сервера
- Настройка игрового сервера
- Боты
Записи
Записи (Replays) в Team Fortress 2 — это возможность, на стороне сервера — создания записи последней жизни игрока, а на стороне клиента — её просмотра, редактирования, сохранения и публикации. Является расширением SourceTV.
Записи должны быть явно разрешены в командной строке сервера, включены и настроены в конфигурационном файле, выполняемом до загрузки карты. Кроме того, должен быть предварительно настроен веб-сервер для отдачи записей игрокам.
Настройка веб-сервера
Для наглядности мы заведём в DNS отдельный поддомен replay.example.org, создадим каталог /var/www/replay.example.org, и для удобства вынесем запись логов в отдельные файлы и предоставим возможность пользователю game читать их.
Из-под root создаём каталоги, устанавливаем владельца (game:game) и права — пользователю game на запись, остальным (веб-серверу) — на чтение. Можно заодно сделать символьные ссылки для удобства. Данный веб-сервер будет общим для обоих игровых серверов, но каждый из них будет использовать отдельные каталоги для выкладывания записей.
# mkdir -p /var/www/replay.example.org/{htdocs/server1,htdocs/server2,log}
# chown -R game:game /var/www/replay.example.org
# chmod -R 755 /var/www/replay.example.org
# ln -s /var/www/replay.example.org/log /home/game/log/www-replay
В нашей конфигурации по умолчанию все логи веб-сервера имеют владельца nginx:adm и права 640, то есть они недоступны обычным пользователям. Корректируем это для данного случая:
# touch /var/www/replay.example.org/log/{access,error}.log
# chmod 644 /var/www/replay.example.org/log/*.log
Таким образом пользователю game наши логи станут доступны для чтения. Но только до первой их ротации. Исправляем и это. В каталоге /etc/logrotate.d копируем файл nginx в srcds-nginx, в нём прописываем путь к логам и в строчке create 640 nginx adm
исправляем маску прав доступа с 640 на 644:
#/etc/logrotate.d/srcds-nginx
/var/www/stat.example.org/log/*.log
/var/www/fastdl.example.org/log/*.log
/var/www/replay.example.org/log/*.log
{
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 644 nginx adm
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}
Здесь мы в путях для ротации указали заодно каталоги с логами от сервера статистики HLstatsX и от сервера Fast Download.
Из-под root создаём файл конфигурации веб-сервера, /etc/nginx/conf.d/replay.example.org.conf:
# /etc/nginx/conf.d/replay.example.org.conf
server
{
server_name replay.example.org;
listen 80;
root /var/www/replay.example.org/htdocs;
disable_symlinks on;
autoindex off;
access_log /var/www/replay.example.org/log/access.log main;
error_log /var/www/replay.example.org/log/error.log warn;
}
Это, конечно, несколько упрощённый вариант. Так как в нашем случае веб-сервер находится на том же компьютере, что и игровые сервера и делит с ними один канал в интернет, то имеет смысл прописать дополнительные ограничения по ширине канала для отдачи записей. Но, в отличие от настроек Fast Download, устанавливать дополнительные проверки по referer нет необходимости.
Прописываем вызов replay.example.org.conf в основной файл /etc/nginx/nginx.conf если ещё не, затем тестируем конфигурацию и перезапускаем nginx.
# nginx -t
# systemctl reload nginx
Далее продолжаем как пользователь game.
Настройка игрового сервера
По умолчанию, при разрешении записей, сервера при запуске будут пытаться выполнить файл конфигурации ~/tf2/tf/cfg/replay.cfg. Так как мы записи включаем на обоих серверах, отдельные настройки которых обязательно должны быть различны, то как и в предыдущих случаях, мы готовим индивидуальные файлы для каждого сервера.
В каталоге ~/tf2/tf/cfg есть файл replay_example.cfg, изучаем его и создаём свой собственный. Для первого сервера, ~/cfg/replay1.cfg:
echo "*** ~/cfg/replay1.cfg"
replay_name "Бот для записей"
replay_local_fileserver_path /var/www/replay.example.org/htdocs/server1
replay_fileserver_offload_enable 0
replay_fileserver_host replay.example.org
replay_fileserver_path /server1
replay_enable 1
Здесь:
replay_name
имя специального бота для записи, как он будет виден в списке наблюдателей (spectators).
replay_local_fileserver_path
каталог, куда будут помещаться готовые файлы с записями. Должен быть индивидуальным для каждого игрового сервера и доступен для чтения веб-сервером.
replay_fileserver_offload_enable
если 1 — то записи выгружаются по ftp на другой сервер, который уже сам их раздаёт по http. Не наш случай.
если 0 — то раздачей занимается веб-сервер на нашей машине.
replay_fileserver_host
имя или ip веб-сервера
replay_fileserver_path
часть url — путь к записям, как отображается веб-сервером.
replay_enable
собственно, включает записи на сервере.
Таким образом из переменных replay_local_fileserver_path, replay_fileserver_host, replay_fileserver_path и не упомянутых здесь replay_fileserver_protocol (="http") и replay_fileserver_port (="80") формируется url вида "http://replay.example.org:80/server1", который передаётся клиенту для скачивания записей. А переменная replay_local_fileserver_path задаёт фактическое местоположение каталога в файловой системе и равна root из файла конфигурации nginx + replay_fileserver_path.
Копируем этот файл в replay2.cfg, исправляем пути server1 -> server2
echo "*** ~/cfg/replay2.cfg"
replay_name "My replay bot"
replay_local_fileserver_path /var/www/replay.example.org/htdocs/server2
replay_fileserver_offload_enable 0
replay_fileserver_host replay.example.org
replay_fileserver_path /server2
replay_enable 1
Делаем ссылки в ~/tf2/tf/cfg:
$ ln -s -v ~/cfg/replay{1,2}.cfg ~/tf2/tf/cfg/
Стоит иметь в виду, что эти файлы конфигурации выполняются лишь при первоначальном запуске сервера, после autoexec.cfg. При смене карт они не задействуются.
Ещё из более-менее полезных консольных переменных:
replay_dopublishtest
проводит тест готовности сервера (игрового и веб) к записям — проверят доступность путей в файловой системе, имя веб-сервера и так далее.
replay_data_lifespan
задаёт количество дней (по умолчанию 1 сутки), по прошествии которых записи на сервере будут помечаться как "несвежие", что позволит ручной или автоматической очистке их удалить.
replay_docleanup
удаляет "несвежие" записи. С параметром 'force' удаляет вообще все записи.
replay_fileserver_autocleanup
по умолчанию 0 — выкл, запускает автоматическую очистку "несвежих" записей между раундами.
replay_dofileserver_cleanup_on_start
по умолчанию 1 — вкл, при старте сервера запускает автоматическую очистку "несвежих" записей, как в ~/tf2/tf/replay/server{1,2}, так и в каталоге веб-сервера /var/www/replay.example.org/htdocs/server{1,2}.
replay_record_voice
по умолчанию 1 — вкл, записывать голосовой чат игроков.
Список актуальных, в данной версии движка Steam, переменных можно посмотреть, введя в консоли сервера find replay_
.
Включение
В скрипты запуска серверов start{1,2}.sh, в командную строку мы дописываем:
Для первого сервера:
CMDLINE="...
-replay reply1.cfg -replayserverdir server1 \
...
Для второго:
CMDLINE="...
-replay reply2.cfg -replayserverdir server2 \
...
Здесь команда "-replay" включает функции записи и при запуске сервера выполняет указанный файл конфигурации. Вторая команда, "-replayserverdir" в качестве параметра принимает имя каталога (от пути ~/tf2/tf/replay/), в котором каждый сервер будет накапливать записи.
Всё, можно запускать сервера и пробовать. В игровом клиенте, в браузере серверов около имени нашего сервера, рядом с щитком VAC появится характерная иконка Записей.
При включении записей, на сервере появляется бот в режиме наблюдателя, который собственно и ведёт записи и при этом занимает один игровой слот. Поэтому установленное при запуске сервера максимальное количество игроков "+maxplayers 24" увеличивается на одного, то есть в нашем случае становится равным двадцати пяти (а при включении SteamTV — двадцати шести).
В старых руководствах по настройке записей обычно указывается параметр командной строки сервера "-replay_port", но мы про него и не упоминаем, так как он был отменён ещё в далёком 2011 году — store.steampowered.com/news/6282/
При использовании плагинов, облегчающих массовые действия над игроками (в том числе идущие в комплекте с SourceMod), следует аккуратно относиться к боту записей. Во всяком случае, не стоит ненароком кикать его с сервера :)
Обслуживание
Файлы записей, хотя и невелики по размеру, но всё же занимают место на диске, как в каталоге replay, так и в /var/www/. И бывает, что, несмотря на установленную дату старения в одни сутки (replay_data_lifespan 1) и включенную автоочистку этих каталогов (replay_dofileserver_cleanup_on_start 1), старые файлы автоматически не удаляются. Даже при ручном запуске replay_docleanup. Поэтому для подстраховки добавим принудительную очистку старых записей, запустив crontab -e
и дописав в конец:
0 3 * * * /usr/bin/find ~/tf2/tf/replay/server{1,2}/* -type f -mtime +10 -delete
0 3 * * * /usr/bin/find /var/www/replay.example.org/htdocs/server{1,2}/* -type f -mtime +10 -delete
Предварительно неплохо бы убедиться, что cron использует шелл, поддерживающий расширение скобок — "{1,2}"
Чтение access.log показывает, что порой игроки, а точнее их игровые клиенты при подключении к нашему серверу пытаются сказать записи игр, в которые они играли и три недели назад.
Ещё момент — следует учитывать, что Записи кушают процессорное время. Пример загрузки приведён в конце раздела "Боты"
SourceTV
Теперь настроим SourceTV. Это пригодится для онлайн трансляций мировых чемпионатов, когда мы будем их у себя проводить.
SourceTV позволяет зрителям, посредством своих клиентов Team Fortress 2 наблюдать за ходом игры на сервере. При использовании цепочек прокси серверов, размер аудитории практически не ограничен, но в данном случае, когда трансляция игры будет осуществляться лишь силами нашего игрового сервера, количество зрителей имеет смысл лимитировать, так как каждый из них потребляет и ресурсы процессора и канал в интернет.
Так как при первоначальной настройке запуска игровых серверов мы уже указали в командной строке "+tv_port" со своим номером порта для каждого сервера, то можно сразу перейти к файлам конфигурации.
Так же как и для настройки записей, SourceTV должен быть активирован до загрузки карты, то есть команда "tv_enable 1" должна быть выполнена либо в командной строке запуска сервера либо в файле autoexec.cfg. Вдобавок, опытным путём было установлено, что аналогичное требование и у команды "tv_name".
Поскольку настройки SourceTV наших серверов фиксированы и при каждой смене карты меняться не планируются, то все общие мы включим в autoexec.cfg, индивидуальные — в autoexec{1,2}.cfg.
В ~/cfg/autoexec.cfg добавляем общие настройки:
//...
// SourceTV
// Заголовок в окне у зрителя
tv_title "Хлеба и зрелищ!"
// Пароль на подключение
// tv_password ""
// Максимальное количество зрителей
tv_maxclients 5
// Ширина канала для каждого зрителя
tv_maxrate 0
// Транслировать всё (1) или только POV оператора (0)
tv_transmitall 1
// Задержка в вещании
tv_delay 20
// Разрешить человека-оператора
tv_allow_camera_man 0
// Начало записи в файл
//tv_record <filename>
// Остановка записи
//tv_stoprecord
// Автоматическая запись
tv_autorecord 1
Здесь:
tv_title
заголовок в окне у зрителя при просмотре трансляции.
tv_password
пароль на подключение к трансляции.
tv_maxclients
максимальное количество зрителей, от 0 до 255, по умолчанию 128. Если нужна не онлайн трансляция, а только запись игры (tv_record, tv_autorecord), то можно выставить в ноль.
tv_maxrate
максимальная ширина канала на каждого игрока, по умолчанию — 8000 бит/сек, при установке в 0 — без ограничений. Параметр тесно увязан с предыдущим параметром, особенно если планируется полностью заполненный зрителями сервер.
tv_transmitall
по умолчанию ("0"), зрителям передаётся лишь то, что показывает оператор SourceTV (ИИ либо специально обученный человек). При установке в "1", зрителям передаётся вся информация об игре, и они могут переключаться между POV от разных игроков, либо вообще парить над/под картой. При включении параметра в два-три раза увеличивается требуемая ширина канала для каждого зрителя.
tv_delay
задержка трансляции зрителям в секундах, по умолчанию 30. Служит для уменьшения читерства, когда зритель может давать подсказки игроку.
tv_delaymapchange
задерживать ("1") или нет ("0" — по умолчанию) смену карты, до тех пор, пока не закончится трансляция (из-за задержки tv_delay).
tv_delaymapchange_protect
защищает ("1" — по умолчанию) или нет ("0") от смены карты вручную до тех пор, пока не закончится раунд.
tv_allow_camera_man
разрешать ("1" — по умолчанию) или нет ("0") игрокам-наблюдателям становиться операторами SourceTV. Если "0" — то только автоматическое управление камерой.
tv_autorecord
при включении ("1") автоматически начинаются записываться все игры в файлы с именами вида auto-<YYYYMMDD>-<hhmm>-<имя карты>.dem
в каталог ~/tf2/tf, например "auto-20160630-2208-koth_sawmill.dem".
При установке пароля ("tv_password <пароль>"), зрители не смогут подключиться из браузера серверов — им постоянно будет отказано с сообщением: "Disconnect: Bad spectator password", а в консоли сервера будет написано "Dropped <игрок> from server (Bad spectator password)". Для подключения, зрителям надо будет в консоли (~
) игры ввестиpassword <пароль>
, закрыть консоль, а затем попробовать подключиться. Либо сразу в консоли ввестиconnect 192.0.2.0:27020; password <пароль>
.
В ~/cfg/autoexec1.cfg дописываем в конец:
//...
// Включаем SourceTV
tv_enable 1
// Имя сервера в браузере
tv_name "SourceTV at Public Server No 1"
Здесь:
tv_name
имя SourceTV сервера, как оно будет показываться в браузере серверов, в закладке "Наблюдение".
tv_enable
включает ("1") или нет ("0", по умолчанию) SourceTV на сервере.
Аналогично корректируем ~/cfg/autoexec2.cfg
//...
tv_enable 1
tv_name "SoutceTV at Private Server No 2"
tv_autorecord 0
А вот для второго сервера мы в autoexec2.cfg отключили автоматическую запись. Существует проблема при включении автоматической записи ("tv_autorecord 1") на картах, подключённых из Steam Workshop, у которых имя выглядит как "workshop/", либо "workshop/.ugc" — то есть в любом случае содержит слеш "/", что приводит к корявому формированию имени файла у tv_autorecord в схеме auto-<YYYYMMDD>-<hhmm>-<имя карты>.dem
и ругани в логах вида:
Failed to write file /home/game/tf2/tf/replay/server2/sessions/20160702-074150-workshop/cp_orange_x3.ugc454299390.dmx
Failed to write file /home/game/tf2/tf/replay/server2/blocks/20160702-074150-workshop/cp_orange_x3.ugc454299390_part_0.dmx
********************************************************************************
*
* Replay recording shutting down due to publishing error! Recording will begin
* at the beginning of the next round, but may fail again.
*
********************************************************************************
ERROR: Publish timed out after 60 seconds.
и, как следствие, отключению записей. Как вариант, можно продумать схему с использованием "tv_record", позволяющей ручное указание имени файла для записи.
При включении SourceTV на сервере появляется бот в режиме наблюдателя, который занимается трансляцией игры и при этом занимает один игровой слот. Поэтому установленное при запуске сервера максимальное количество игроков "+maxplayers 24" увеличивается на одного, то есть в нашем случае становится равным двадцати пяти (а при включении Replay — двадцати шести).
Итак, команды прописаны, перезапускаем сервер и смотрим что получается. Так как у нас так же включены записи, которые тоже занимают свой игровой слот, то мы видим:
*** ~/cfg/autoexec.cfg (global)
--------------------------------------------------------
sv_pure set to 2.
--------------------------------------------------------
maxplayers set to 25
*** ~/cfg/autoexec1.cfg
Server logging enabled.
Server logging data to file /home/game/log/server1/L1008000.log
maxplayers set to 26 (extra slot was added for SourceTV)
...
Cannot verify load for invalid steam ID [A:1:0:1]
Cannot verify load for invalid steam ID [A:1:1:1]
Recording SourceTV demo to auto-20161008-1155-cp_granary.dem...
Connection to game coordinator established.
*** ~/cfg/server1.cfg
...
SourceTV broadcast active.
Connection to Steam servers successful.
Public IP is 192.0.2.0.
Итак, в начале максимальное количество игроков на сервере было увеличено с 24 до 25 — это отработал параметр командной строки "-replay", включились записи. Затем ещё один дополнительный слот был добавлен для SourceTV — это сработал "tv_enable 1" из autoexec1.cfg. На ругань про invalid steam ID [A:1:0:1] не обращаем внимание — это наши боты записи и трансляции, ради которых сервер добавил игровые слоты. Далее началась запись демки в файл ~/tf2/tf/auto-20161008-1155-cp_granary.dem — сработал параметр "tv_autorecord 1" из autoexec.cfg. И наконец нам констатировали, что SourceTV broadcast active.
Заработало. Можно заселить какую-нибудь карту ботами, подключиться зрителем и посмотреть, как выглядит трансляция при различных режимах tv_transmitall, tv_allow_camera_man.
Может случиться так, что слоты добавлены, а про "SourceTV broadcast active." ни слова, да и при вводе в консоли сервера команда tv_status
оно ругается "SourceTV not active.", хотя введённая тут же tv_enable
сообщает что всё ок — "tv_enable = 1 ( def. 0 )". В таком случае надо попробовать сменить карту — changelevel <имя карты>
. Если после смены всё заработало — то значит всё же SourceTV изначально так не активировался до загрузки первой карты — надо смотреть настройки.
Команды, которые могут пригодиться:
tv_record <имя файла>
начинает запись, сохраняемую в файл <имя файла>. Записываются все события, вне зависимости от того, что видит оператор.
tv_stoprecord
останавливает запись.
tv_clients
показывает информацию о подключённых зрителях.
tv_msg
отправить сообщение всем зрителям (появится посреди экрана).
tv_status
выводит краткую информацию о статусе сервера — время онлайн, FPS, количество зрителей, используемую полосу канала и тому подобное.
Список актуальных, в данной версии игрового сервера, переменных можно посмотреть, введя в консоли сервера find tv_
.
Ускорение скачивания контента (Fast Download)
Если мы будем использовать на своих серверах карты, модели, звуки, не входящие в стандартную поставку Team Fortress 2 и отсутствующие в Steam Workshop, то при подключении нового игрока ему необходимо будет скачать к себе на игровой компьютер наши игровые материалы (если их у него ещё нет). По умолчанию они будут скачиваться с нашего игрового сервера — этот режим называется Slow Download. Но так как игровой сервер это всё же не специализированный веб-сервер, то при частой установке новых пользовательских карт и высокой нагрузке, разумно было бы возложить функции по отдаче карт (а также звуков, моделей и так далее) на специально обученный веб-сервер. Который, по счастливому стечению обстоятельств у нас уже есть. Этот функционал и называется Fast Download.
Настройка веб-сервера
Для использования Fast Download необходимо указать веб-серверу использование каталога со структурой подкаталогов вида
dir/maps
dir/materials
dir/sound
...
где "dir" — корневой каталог для Fast Download. Создать его в /home/game мы не можем — домашний каталог у нас с правами rwx------, что не позволяет веб-серверу видеть эти файлы. Поэтому мы создадим эти каталоги где-нибудь вне пределов домашней директории пользователя game.
Для упрощения настройки, пропишем у себя в DNS отдельный поддомен fastdl.example.org, создадим каталог /var/www/fastdl.example.org, и для удобства вынесем запись логов в отдельные файлы и предоставим возможность пользователю game читать их.
Из-под root создаём каталоги, устанавливаем владельца (game:game) и права — пользователю game на запись, остальным (веб-серверу) — на чтение. Можно заодно сделать символьные ссылки для удобства. Каталог Fast Download будет общим для обоих игровых серверов.
# mkdir -p /var/www/fastdl.example.org/htdocs/{maps,materials,sound}
# mkdir /var/www/fastdl.example.org/log
# chown -R game:game /var/www/fastdl.example.org
# chmod -R 755 /var/www/fastdl.example.org
# ln -s /var/www/fastdl.example.org/htdocs /home/game/fastdl
# ln -s /var/www/fastdl.example.org/log /home/game/log/www-fastdl
В нашей конфигурации по умолчанию все логи веб-сервера имеют владельца nginx:adm и права 640, то есть они недоступны обычным пользователям. Корректируем это для данного случая:
# touch /var/www/fastdl.example.org/log/{access,error}.log
# chmod 644 /var/www/fastdl.example.org/log/*.log
Таким образом пользователю game наши логи станут доступны для чтения. Но только до первой их ротации. Исправляем и это. В каталоге /etc/logrotate.d копируем файл nginx в srcds-nginx, в нём прописываем путь к логам и в строчке create 640 nginx adm
исправляем маску прав доступа с 640 на 644:
#/etc/logrotate.d/srcds-nginx
/var/www/stat.example.org/log/*.log
/var/www/fastdl.example.org/log/*.log
/var/www/replay.example.org/log/*.log
{
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 644 nginx adm
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}
Здесь мы в путях для ротации указали заодно каталоги с логами от сервера статистики HLstatsX и от сервера с записями.
Есть ещё один забавный момент, который следует учесть. Для большинства серверов он вряд ли станет актуальным, но всё же. Ничто не мешает владельцу какого-нибудь игрового сервера с такими же как у нас пользовательскими картами, не со злобы, а для экономии своего траффика, в своих настройках Fast Download указать адрес нашего веб-сервера (узнать его просто — достаточно ввести sv_downloadurl
в консоли игрового клиента, подсоединившись к серверу).
Обнаружить таких паразитов можно по referer, с которым от нас скачиваются карты. Так, при скачивании карты игровым клиентом, с подачи нашего игрового сервера в логе веб-сервера появляется запись вида:
198.51.100.0 http://fastdl.example.org - [16/Jun/2016:20:08:28 +0600] "GET /maps/cp_orange_x5.bsp.bz2 HTTP/1.1" 200 2685506 "hl2://192.0.2.0:27015" "Half-Life 2" 0.453 "-"
Обращаем внимание на referer. Учтём это при настройке.
Итак, принимаемся за настройку веб-сервера. Сначала сделаем определение, с правильным ли referer скачивают нашу карту. В главном файле /etc/nginx/nginx.conf, в секции http {}, перед включением файла конфигурации для нашего виртуального хоста fastdl.example.org, вписываем:
# /etc/nginx/nginx.conf
http {
# <...>
map $http_referer $bad_client {
default 1;
"hl2://192.0.2.0:27015" 0;
"hl2://192.0.2.0:27016" 0;
}
include /etc/nginx/conf.d/fastdl.example.org.conf;
}
Тут всё просто. Если заголовок $http_referer соответствует одному из наших серверов, то переменная $bad_client (со значением по умолчанию 1) принимает значение 0.
Теперь создаём файл конфигурации нашего виртуального сервера /etc/nginx/conf.d/fastdl.example.org.conf.
#/etc/nginx/conf.d/fastdl.example.org.conf
server
{
server_name fastdl.example.org;
listen 80;
root /var/www/fastdl.example.org/htdocs;
disable_symlinks on;
default_type application/octet-stream;
if ($bad_client) {
# Желающие могут поиздеваться в стиле https://habrahabr.ru/post/272261/, с учётом местной специфики
return 403;
}
access_log /var/www/fastdl.example.org/log/access.log main;
error_log /var/www/fastdl.example.org/log/error.log warn;
}
Тут ещё проще — проверяем ту переменную $bad_client, и к нарушителям применяем санкции.
Вообще, у nginx есть директива valid_referers, но для нашего нестандартного $http_referer, с его нетипичной схемой, да и номером порта её не очень удобно применять. С map нагляднее.
Прописываем вызов fastdl.example.org.conf в основной файл nginx.conf если ещё не, затем тестируем конфигурацию и перезапускаем nginx.
# nginx -t
# systemctl reload nginx
Далее продолжаем как пользователь game.
Настройка игрового сервера
Пользовательские карты весьма хорошо сжимаются, поэтому их можно отдавать игрокам в архивированном виде (в формате bzip2), но при этом необходимо иметь несжатую карту (.bsp) в соответствующем каталоге игрового сервера. Например, если мы где-нибудь разжились понравившейся нам картой cp_orange_x5 (данная карта приведена только для примера — она существует в природе, но на момент написания материала её не было в Steam Workshop), то делаем следующее:
$ mv cp_orange_x5.bsp ~/fastdl/maps
$ ln -s ~/fastdl/maps/cp_orange_x5.bsp ~/tf2/tf/maps
$ bzip2 --compress --keep --verbose --best ~/fastdl/maps/cp_orange_x5.bsp
То есть нестандартные карты мы будем хранить в каталоге ~/fastdl/maps, рядом с сжатыми и символьной ссылкой подключать в каталог к стандартным. Вариант, конечно, обсуждаемый, но не лучше и не хуже других. Файлы конфигураций для карт вида <имя карты>.cfg необходимо создавать в ~/tf2/tf/cfg (ну или просто в ~/cfg, а туда указывать ссылкой).
Теперь прописываем настройки игрового сервера в ~/cfg/autoexec.cfg:
//...
// Fast Download
// Адрес веб-сервера, откуда игрокам будет отдаваться пользовательский контент
// Для отключения Fast Download указываем sv_downloadurl ""
sv_downloadurl "http://fastdl.example.org"
// Разрешает игроку загружать файлы на сервер (например, спреи). Нефиг.
sv_allowupload 0
// Разрешает игроку скачивать файлы с сервера
// влияет лишь на Slow Download. Здесь приводим просто для демонстрации.
sv_allowdownload 1
Проверим как всё работает. Если сервер не запущен, то запускаем. Если он уже работает, то перезапускаем, чтобы вынудить его перечитать autoexec.cfg с нашими новыми настройками Fast Download.
Вообще-то вполне себе допускается вызов одних файлов конфигурации из других — exec <configfile>
или из консоли. Тогда можно те же команды Fast Download вынести в отдельный файл конфигурации, включить вызов его в autoexec.cfg, а при необходимости "освежить" настройки запускать его ручками в консоли, либо вызывать из того же server.cfg. Может быть удобно при отладке настроек, чтобы каждый раз не перегружать игровой сервер. Хотя его перезагрузка позволит отработать изменения, внесённые но забытые в тот же autoexec.cfg :-)
У себя в игровом компьютере в каталоге SteamApps\common\Team Fortress 2\tf\download\maps\ ищем cp_orange_x5.bsp, если есть — удаляем (нам надо чтобы она скачалась заново).
Запускаем у себя игру, подключаемся к нашему серверу, смотрим, скачивается ли карта с Fast Download (в окошке должно быть написано именно "Downloading maps/cp_orange_x5.bsp.bz2" — с .bz2 расширением):
(На картинке карта _x3, но суть та же).
Естественно, предполагается что у игроков в настройках клиента разрешена загрузка контента с сервера, как минимум "Загружать только карты" (cl_downloadfilter mapsonly), иначе будет выдано сообщение "Map is missing".
Можем попробовать браузером скачать карту http://fastdl.example.org/maps/cp_orange_x5.bsp.bz2, если видим "403 Forbidden" — так и должно быть, referer не hl2://192.0.2.0
, радуемся.
Один момент:
Раз мы заявили возможность Fast Download (указав не пустой параметр sv_downloadurl), то при скачивании с веб-сервера, что хорошо видно в его логах, у игроков клиенты сначала пытаются скачать <имя карты>.bsp.bz2, в случае ошибки 404 пытаются скачать несжатую карту, без расширения .bz2 — <имя карты>.bsp. В случае облома и в этой попытке, игроку НЕ предоставляется возможности скачать карту с самого игрового сервера из ~/tf2/tf/maps через Slow Download, а сообщается, что карта не найдена.
Боты
В Team Fortress 2 есть два типа ботов — с искусственным интеллектом и без. Боты с ИИ активно действуют в игре, их можно активировать без использования читерских команд (то есть при sv_cheats 0), на них можно зарабатывать многие достижения. Боты без ИИ — "куклы", активируются с использованием читерских команд (sv_cheats 1).
Официальная TF wiki говорит, что боты с ИИ корректно работают на большинстве карт King of the Hill (koth_*
), некоторых Payload картах (pl_*
), Dustbowl и Gorge, картах Capture the Flag (ctf_*
) и Mann Manor (cp_manor_event
). Возможно использование ботов на других картах, но с некоторой предварительной подготовкой. И при этом они не будут настолько же хороши как живые игроки. Впрочем, те же медики подлечить сумеют. Попробуем оба варианта.
Поддержваемая карта
Попробуем добавить ботов на карту koth_sawmill, которая их поддерживает by design. У нас оба сервера на 24 игрока. Точнее, на 24 игровых слота, но в данном примере эту разницу в нюансах не учитываем. Сделаем так, что если игроков меньше 24, то остальные игровые слоты сервера будут заняты ботами. Новый игрок вошёл в игру — бот исчез. Игрок вышел — бот добавился. Экспериментировать будем на втором, подопытном сервере. Чтобы каждый раз не набирать команды в консоли сервера, укажем их в файле конфигурации для данной карты ~/cfg/koth_sawmill.cfg:
echo "*** ~/cfg/koth_sawmill.cfg"
// Уровень игры ботов
tf_bot_difficulty 3
// Режим добавления ботов в игру
tf_bot_join_after_player 0
// Возрождение ботов
tf_bot_keep_class_after_death 0
// Тип применения квоты на ботов
tf_bot_quota_mode fill
// Размер квоты ботов в игре
tf_bot_quota 24
Здесь мы сделали:
tf_bot_difficulty 3
Уровень игры ботов. 0=easy, 1=normal, 2=hard, 3=expert.
tf_bot_join_after_player 0
Боты будут добавлены в игру при старте сервера (0), либо при входе первого игрока (1), а до его входа карта будет без ботов.
tf_bot_keep_class_after_death 0
После смерти, боты будут всегда возрождаться тем же классом (скаут, солдат, ...), какой получили при создании (1) или другим (0), на усмотрение ИИ.
tf_bot_quota 24
Совместно со следующим параметром, задаёт квоту ботов в игре. Используется, если следующий параметр tf_bot_quota_mode установлен в "fill" или "match", но не более количества игровых слотов, заданных +maxplayers в командной строке запуска сервера.
tf_bot_quota_mode fill
Тип применения квоты на ботов:
"normal" — сервер не будет добавлять/убирать ботов без прямой команды (tf_bot_add / tf_bot_kick)
"fill" — сервер будет поддерживать общее количество (ботов + живых игроков) в размере, заданном параметром tf_bot_quota
"match" — сервер будет поддерживать соотношение живых игроков к ботам как 1:N, где N задано параметром tf_bot_quota.
tf_bot_add [количество] [класс] [команда] [уровень] [имя]
Принудительное добавление ботов, при этом они не подвержены автоматическому регулированию квотой (но, в любом случае, не более maxplayers)
[Класс] — Demoman, Engineer, HeavyWeapons, Medic, Pyro, Scout, Soldier, Sniper, Spy
[Команда] — red или blue
[Уровень] — аналогичен tf_bot_difficulty, только для данного бота. 0=easy, 1=normal, 2=hard, 3=expert.
По нашей политике, все файлы конфигурации стараемся держать в ~/cfg, поэтому делаем ссылку в ~/tf2/tf/cfg:
$ ln -s ~/cfg/koth_sawmill.cfg ~/tf2/tf/cfg
Запускаем сервер, если не запущен ранее, вводим в консоли команду смены карты: changelevel koth_sawmill
. Входим в игру, быстро огребаем от двенадцати expert-lvl ботов и идём исправлять tf_bot_difficulty на 1 :-)
Пользовательсякая карта
Теперь добавим ботов на произвольную карту. В данном случае cp_orange_x3.
Копируем koth_sawmill.cfg в cp_orange_x3.cfg, учитывая что эта карта подключена из Steam Workshop:
$ mkdir ~/tf2/tf/cfg/workshop
$ cp ~/cfg/koth_sawmill.cfg ~/tf2/tf/cfg/workshop/cp_orange_x3.ugc454299390.cfg
И желательно в cp_orange_x3.ugc454299390.cfg исправить в echo имя файла, во избежание непоняток.
Меняем карту. В консоли сервера вводим changelevel workshop/cp_orange_x3.ugc454299390
. Входим в игру и видим невесёлую картину — ребята стоят, скучают:
Не отчаиваемся. В консоли игрового сервера, вводим команды: sv_cheats 1
— разрешает использование чит-команд и следом nav_generate
— создаёт навигационную сетку (сохраняемую в файле <имя карты>.nav), используя которую боты могут двигаться. Ждём некоторое время...
Generating Navigation Mesh...
Sampling walkable space...
Sampling walkable space...
Sampling walkable space...
Creating navigation areas from sampled data...
Connecting navigation areas...
Merging navigation areas...
Created new fencetop area 1781(fc537be) between 3(1f542dcf) and 49(274fa843)
Finding hiding spots...DONE
Finding encounter spots...DONE
Finding sniper spots...DONE
Computing mesh visibility...
Computing mesh visibility... 0%
Computing mesh visibility... 1%
Computing mesh visibility... 5%
Computing mesh visibility... 17%
Can't compute incursion distances from the Red spawn room(s). <...>
Can't compute incursion distances from the Blue spawn room(s). <...>
Computing mesh visibility... 84%
Optimizing mesh visibility...
NavMesh Visibility List Lengths: min = 12, avg = 104, max = 280
Computing mesh visibility...DONE
Finding earliest occupy times...DONE
Start custom...
Post custom...
Custom game-specific analysis...DONE
Generation complete! 77.8 seconds elapsed.
Navigation map '/home/game/tf2/tf\maps\workshop/cp_orange_x3.ugc454299390.nav' saved.
[TF Workshop] Preparing map ID 454299390
[TF Workshop] Successfully prepared client map from workshop [ workshop/cp_orange_x3.ugc454299390 ]
---- Host_Changelevel ----
и так далее.
После чего сервер перегружает уровень. Кстати вот тут и проявилась польза от прозорливо указанного параметра "sv_cheats 0" в server2.cfg. При смене карты, произошедшей выше, вручную включенный sv_cheats сбросился в 0, и можно не задумываться — а не забыли ли мы выключить то, что включили.
Входим в игру — и всё в порядке, боты ожили и на этой карте. Точки захватываются, враги убивают, медики лечат. Хотя инженеры и шпионы не покидают точку респауна.
Но на мало-мальски сложных картах маршруты движения ботов могут быть очень неоптимальными, для исправления этого есть возможность корректировки навигационной сетки. Перечень навигационных команд приведён в Navigation Mesh Commands, а скачать уже готовые и оптимизированные файлы можно на Steam Users Forum.
Ещё есть "кукольные" боты (Puppet bots). Они обделены ИИ и могут либо стоять на месте, либо двигаться, повинуясь командам игрока. Здесь мы их не рассматриваем. Подробнее о них можно прочитать в TF Wiki, по ссылке в начале главы. А заодно и посмотреть впечатляющий ролик https://youtu.be/Dn9970dxQ2g
Следует иметь в виду, что боты, как ни странно, кушают процессорное время. В качестве демонстрационного примера, вот вывод программы top для трёх запущенных игровых серверов на хиленьком Atom N2800:
На первом сервере 24 бота с активной жизненной позицией (и сервер перегружен и ощутимо лагает, играть невозможно), на втором 12, на третьем ботов нет. Ах да, ещё на первом и третьем сервере включены Записи. Если на том же третьем их выключить, то его загрузка будет вдвое ниже, менее 7%. Ну и tf_bot_join_after_player 1 снизит нагрузку на серверах без игроков.
И, логичный, но не всегда очевидный момент — настройки ботов (да и не только их), заданные в файлах конфигурации карт (koth_sawmill.cfg и cp_orange_x3.ugc454299390.cfg в нашем примере) не сбрасываются при смене карты, а продолжают действовать и на следующих картах, при их ротации. Другое дело, что поведение ботов будет зависеть от типа карты — как было продемонстрировано в примерах выше, на каких-то картах боты могут быть активны "из коробки", на других картах, без сгенерированных .nav файлов они будут стоять на точках респауна. Поэтому, если требуется включать ботов только на некоторых картах, то имеет смысл прописать tf_bot_quota 0 в server{1,2}.cfg — при смене карты количество ботов будет равно нулю, а уже в файлах конфигурации для конкретной карты их можно включать целенаправленно.