Rollback-неткод врёт вам на несколько кадров — и поэтому файтинги играются онлайн
Тони Кэннон написал GGPO около 2006 года, чтобы играть в Street Fighter III через интернет. Метод нахальный: предсказать чужой ввод, показать результат немедленно, а при ошибке отмотать симуляцию назад и пересчитать.
Сначала о масштабе задачи. Файтинг работает на шестидесяти кадрах в секунду, то есть кадр длится 16,7 миллисекунды. Быстрый удар выходит за три-шесть кадров, а окно для его блокирования измеряется одним-двумя. Пакет из Лос-Анджелеса в Нью-Йорк идёт около сорока миллисекунд в одну сторону, до Токио — за сотню. Сеть медленнее, чем наименьшая осмысленная единица игры, и с этим ничего нельзя сделать. Можно только выбрать, как именно соврать игроку.
Первая ложь: задержка ввода
Классическое решение называется delay-based. Обе машины ждут ввода противника и не двигаются дальше, пока его нет. Чтобы дрожание сети не приводило к рывкам, в игру добавляют задержку ввода: ваша кнопка срабатывает не сейчас, а через несколько кадров, и этого запаса обычно хватает, чтобы пакет успел прийти.
Плюс метода в том, что обе стороны видят абсолютно одинаковую партию. Минусов два, и оба тяжёлые. Управление становится ватным: между нажатием и ударом лежат три-пять кадров, и точные защиты просто перестают работать. А при потере пакета замирают оба игрока — то самое «резиновое» подтормаживание, знакомое по онлайну старых игр SNK и ранних Arc System Works.
Вторая ложь: откат
Rollback устроен наоборот. Машина не ждёт ничего. Не получив чужой ввод, она предполагает, что противник делает то же, что и в предыдущем кадре, — предположение почти всегда верное, потому что кнопки удерживают, а не отпускают каждый кадр. Игра идёт дальше немедленно.
Когда настоящий ввод приходит и расходится с предсказанием, движок берёт сохранённое состояние того кадра, накатывает поверх правильный ввод и прогоняет заново все кадры до текущего — за один кадр отображения. На экране это выглядит как рывок противника на несколько пикселей. Ваш собственный персонаж при этом слушается мгновенно, потому что ваш ввод никогда не предсказывался.
Delay-based врёт вам о том, когда вы нажали. Rollback врёт о том, что сделал противник. Третьего варианта нет.
Почему это нельзя просто включить
Самое интересное — требования к движку, из-за которых студии годами отвечали «мы не можем добавить откат».
Во-первых, симуляция должна быть детерминированной: одинаковый ввод обязан давать одинаковое состояние, всегда. Никаких обращений к системным часам, никакого неинициализированного генератора случайных чисел, аккуратность с плавающей точкой.
Во-вторых, состояние игры нужно уметь сохранять и восстанавливать целиком, дёшево и по несколько раз в секунду — история хранится примерно на семь-восемь кадров назад. Если состояние размазано по объектам движка и по графической подсистеме, сохранять нечего.
В-третьих, симуляцию нужно отвязать от отрисовки, чтобы прогнать семь шагов логики внутри одного кадра картинки. Движок, где логика живёт внутри цикла рендера, придётся переписывать.
Как это стало нормой
GGPO написал Тони Кэннон, сооснователь турнира Evo, примерно в 2006 году — для собственных нужд, чтобы играть в старые аркадные файтинги по сети. Библиотека работала в Street Fighter III: Third Strike Online Edition в 2011-м, в Skullgirls в 2012-м, в Killer Instinct в 2013-м. 9 октября 2019 года Кэннон открыл исходники под лицензией MIT, и через несколько лет откат превратился из преимущества в обязательное требование: жанр стал отказываться от игр без него ещё до выхода.
Стоит понимать, почему метод остался в файтингах. Стоимость отката прямо пропорциональна размеру состояния и числу пересчитываемых сущностей. Два персонажа на одной плоскости — крошечное состояние, его можно копировать шестьдесят раз в секунду. Сотня игроков в открытом мире — нельзя. Шутеры используют родственную, но асимметричную ложь: клиент предсказывает движение, а сервер при проверке попадания отматывает хитбоксы назад во времени, к тому моменту, который вы видели. Отсюда и знаменитая смерть из-за угла — это чужой откат, применённый к вам.
Источник: en.wikipedia.org