Свой сервер

AutoChangeMapMut: смена карты, если на сервер Killing Floor никто не может зайти

Иногда после рестарта выделенного сервера Killing Floor на него никто не может зайти, хотя сервер работает. В логе при этом:

RecvFrom returned SOCKET_ERROR 111
RecvFrom returned SOCKET_ERROR 113

В Linux 111 означает «соединение отклонено», 113 — «нет маршрута до узла». Flame с killingfloor.ru столкнулся с этим на Linux-серверах в 2012 году, возможно после очередного патча игры, и заметил, что помогает смена карты. Чтобы не ждать админа, он написал мутатор, который делает это автоматически.

Что делает мутатор

  • После старта карты раз в минуту проверяет, подключился ли хотя бы один игрок.
  • Как только кто-то зашёл, до конца карты проверки прекращаются.
  • Если матч всё ещё ждёт старта, а ожидание превысило waitingInterval, мутатор вызывает RestartGame() с разрешённой сменой уровня, и сервер переходит на следующую карту по списку.

Переход не мгновенный: прибавьте до минуты на таймер и примерно 48 секунд на саму смену карты.

Установка

  1. Скомпилируйте исходник ниже (см. ucc make) или возьмите оригинальный пакет.
  2. Добавьте мутатор в список мутаторов сервера как AutoChangeMapMut.AutoChangeMapMut.
  3. Задайте время ожидания в секундах в AutoChangeMapMut.ini:
[AutoChangeMapMut.AutoChangeMapMut]
waitingInterval=600

В посте на форуме сказано, что по умолчанию 10 минут, но в опубликованном исходнике стоит waitingInterval=7200 (два часа). Пропишите значение явно.

Исходный код

class AutoChangeMapMut extends Mutator config(AutoChangeMapMut);

var config int waitingInterval;
var int startWaiting;
var bool playersCanConnect;

function PostBeginPlay()
{
    startWaiting = Level.TimeSeconds;
    playersCanConnect = false;
    SetTimer(60.0, true);
}

function Timer()
{
    local int playersN;

    // once at least one player got in, stop checking
    if (playersCanConnect)
        return;
    // only act while the match is waiting to start
    if (!Level.Game.bWaitingToStartMatch)
        return;

    playersN = PlayersNumber();
    if (playersN > 0)
    {
        playersCanConnect = true;
        return;
    }

    if (Level.TimeSeconds - startWaiting >= waitingInterval)
    {
        Level.Game.bChangeLevels = true;
        Level.Game.bAlreadyChanged = false;
        Level.Game.RestartGame();
    }
}

function int PlayersNumber()
{
    local int N;
    local Controller C;

    for (C = Level.ControllerList; C != None; C = C.NextController)
    {
        if (C.IsA('PlayerController') && C.PlayerReplicationInfo.PlayerID > 0)
            N++;
    }
    return N;
}

defaultproperties
{
    waitingInterval=7200
    bAddToServerPackages=True
    GroupName="AutoChangeMapMut"
    FriendlyName="AutoChangeMapMut"
    Description="Changes the map if nobody plays on current map for a period of time"
}

Как это работает

  • bChangeLevels = true и bAlreadyChanged = false заставляют RestartGame() переключить карту по ротации, а не перезапустить текущую.
  • PlayersNumber() считает все PlayerController с валидным PlayerID, то есть зрителей тоже. Если зашёл хотя бы зритель, значит подключения работают.
  • bAddToServerPackages=True для чисто серверного мутатора не нужен: на клиентах он ничего не делает. Можно поставить False, чтобы клиенты не скачивали пакет.

Побочные эффекты

  • На тихом сервере мутатор сменит карту и тогда, когда сервер просто пустой: «никто не может зайти» и «никто не пришёл» он не различает. С длинным интервалом это безвредно.
  • Саму сетевую проблему он не исправляет. Если ошибки повторяются после каждого рестарта, проверьте файрвол и порты (7707 UDP для игры, 7708 UDP для запросов, 28852 для мастер-сервера) и на каком сетевом интерфейсе слушает сервер.

Что ещё помогало

У другого админа тот же симптом был в локальной сети, где сервер стоял сразу в двух сетях (роутер плюс обычный LAN). После смены карты одна сеть подключалась без проблем, а вторая не видела сервер до следующей смены. Сервер работал на Windows 7, и после перехода на Windows Server 2008 проблема исчезла.

Ещё два случая с форума killingfloor.ru:

  • Пускает только одного игрока или вечное подключение. В теме «Проблема: "Не удается установить соединение"» (2013) сервер после выхода единственного игрока считал его ещё на сервере (1/30) и не пускал никого до смены карты; помогло увеличение числа зрителей. В теме «Не заходит на сервер» (2012) DominatorRUS решил вечное подключение к Linux-серверу так: в KillingFloor.ini стояло MaxSpectators=0, после замены на MaxSpectators=2 всё заработало.
  • Виноват мутатор. В той же теме у другого админа MaxSpectators не помог: сервер переставал пускать игроков через одну-две смены карты, пока админ не переключал карту вручную. Отключив все мутаторы и включая их по одному, он нашёл виновников: мутатор Kill Message и мутатор, выбрасывающий весь инвентарь. По его словам, с Kill Message сервер работал на версии 1032 и начал сбоить с 1033.