{"id":3843,"url":"\/distributions\/3843\/click?bit=1&hash=d0b9071c1d51ff8dd5fb0c35f42f4694a7ad9533adc9c6fcd790aa99ecda7c05","title":"\u0414\u043e\u0440\u043e\u0433\u0438\u0435 \u0433\u043e\u043b\u043e\u0441\u043e\u0432\u044b\u0435 \u0440\u043e\u0431\u043e\u0442\u044b vs. \u043d\u0435\u0434\u043e\u0440\u043e\u0433\u0438\u0435 \u0433\u043e\u043b\u043e\u0441\u043e\u0432\u044b\u0435 \u0440\u043e\u0431\u043e\u0442\u044b","buttonText":"","imageUuid":"","isPaidAndBannersEnabled":false}
Gamedev
Artyom Kaleev

Как оптимизировать поведение тысяч предметов в игре одновременно: опыт создателей Satisfactory Статьи редакции

Транспортные ленты против сетевого кода.

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

Это означает, что серверу нужно в реальном времени обрабатывать данные обо всех объектах на заводе. То, с чем пришлось разбираться в Coffee Stain — это уникальная ситуация, с которой вряд ли сталкивались разработчики типового многопользовательского шутера.

В своём блоге на Gamasutra сетевой программист Coffee Stain Гафхар Даваллиус рассказал о том, как в студии оптимизировали сетевой код игры. Мы выбрали главное из материала.

По словам разработчика, есть два пути, по которым можно было бы пойти при создании сетевой инфраструктуры Satisfactory.

Первый — это полная синхронизация карты между всеми игровыми клиентами. В таком случае на компьютерах игроков бы воспроизводилась локальная симуляция. Так поведение всех объектов было бы на 100% предсказуемым — а вся информация бы обновлялась только тогда, когда происходят непредвиденные явления (например, действия игрока).

Второй — это обработка всей информации на сервере, после чего она бы отправлялась на клиенты игроков и там воспроизводилась. Это решение используют в шутерах, и именно его взяли за основу при создании Satisfactory.

Если бы разработчики пошли первым путём, то тогда им нужно было добиваться того, чтобы игра работала предсказуемо во всех отношениях. По словам Даваллиуса, это даже не цель, которую нужно достичь, а необходимое требование для работы системы. Малейшая неточность породит цепную реакцию, из-за которой вся игра рассинхронизируется.

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

Гафхар Даваллиус
сетевой программист Satisfactory

Более того, из-за этого игроки бы чувствовали сильную задержку. Изменения не будут видны, пока все игровые клиенты не подтвердят, что получили информацию от всех пользователей. Проблему можно было бы решить, если бы компьютеры игроков хранили копию состояния сервера пару секунд назад — однако это бы сильно перегрузило оперативную память и процессор.

Поэтому, после выбора модели неткода, перед разработчиками встали следующие задачи.

  • Минимализировать количество отправляемой информации. Это можно сделать, выяснив, какие данные наиболее важны в определённый промежуток времени. К примеру, не нужно отправлять то, что игроки не видят.
  • Уменьшить частоту отправления информации. Если какой-то объект не меняется часто или его поведение достаточно предсказуемо, данные о нём можно посылать реже.
  • Сжать и уменьшить количество сведений, необходимых для точного отображения состояния игры.

Также создателям нужно было разработать систему, которая бы вычленяла важную информацию отдельно для каждого игрока. Если бы эти задачи не были решены корректно, то клиенты бы недополучали пакеты с данными, а также испытывали задержку — гораздо большую, чем пинг.

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

На двух примерах Даваллиус объяснил, что сделали в Coffee Stain. В первую очередь разработчики переработали систему инвентаря. В Satisfactory помимо игрока предметы могут хранить контейнеры и некоторые объекты фабрики: информация о них обновляется в реальном времени, так как все ресурсы поступают напрямую в хранилища.

Чтобы снизить нагрузку на клиенты, авторы сделали так, чтобы у игрока не обновлялись данные инвентарей, которые он не видит в текущий момент времени. Благодаря этому перестал перегружаться процессор — ему больше не нужно было обрабатывать вообще все изменения.

Впрочем, у такого подхода есть свои минусы: иногда игра не может предсказать, когда игрок соберётся открыть тот или иной инвентарь, и потому обновляет данные слишком поздно. Однако в большинстве случаев это незаметно — особенно если играть с невысоким пингом.

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

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

Например — вместо того, чтобы отсылать данные про все 25 предметов на конвейере, мы отправляем лишь сведения о двух новых предметах, которые на нём появились, и об одном, который с него сошёл. То есть, мы используем только 12% всей информации.

Гафхар Даваллиус
сетевой программист Satisfactory

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

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

Мы хотим минимализировать количество данных — однако в таком случае падает точность. Поэтому главная загвоздка заключается в том, чтобы найти линию в коде, которую можно было бы просто пропустить — с наименьшей потерей точности. К тому же, если мы где-то можем предсказать какое-то явление или паттерны, отправку данных можно пропустить вовсе.

Гафхар Даваллиус
сетевой программист Satisfactory

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

Также появилась неточность в расположении предметов на конвейере — однако это удалось устранить благодаря системе, которая предсказывает их позицию согласно уже известным паттернам.

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

Гафхар Даваллиус
сетевой программист Satisfactory
0
35 комментариев
Написать комментарий...
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
Igor

Да, лучше почитать дневники разрабов Factorio

Ответить
Развернуть ветку
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
Александр Золотарев
попить с этими чешскими чуваками баварского пива в Варшаве
Ответить
Развернуть ветку
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
Cabluc

Адресок подскажи, а то в сл. месяце как раз там буду.

Ответить
Развернуть ветку
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
Алексей Сластихин

А еще у них самая вкусная рулька.

Ответить
Развернуть ветку
Cabluc

Благодарю. Обязательно зайду.

Ответить
Развернуть ветку
Никита Хэзэковъ

Вельвет наливают в каждом втором приличном пабе европы.

Ответить
Развернуть ветку
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
Алекс Иванов

Просто пиво на азоте?

Ответить
Развернуть ветку
Успешный яд

И не говори. "Чтобы уменьшить нагрузку на сеть, мы уменьшили объем отправляемых данных" - вот и вся статья...

Ответить
Развернуть ветку
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
Максим Малыгин

Описание алгоритмов дано, дальше уже реализация, которая никому и не нужна.

Ответить
Развернуть ветку
Kirill Vorotov
создатели применили метод «сериализации delta»

Я понимаю, что в оригинале статьи так и написано, "delta serialization"; но, на мой взгляд, всё-таки было бы правильнее перевести как "дельта-компрессия" или "дельта-кодирование"
https://ru.wikipedia.org/wiki/%D0%94%D0%B5%D0%BB%D1%8C%D1%82%D0%B0-%D0%BA%D0%BE%D0%B4%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5

Ответить
Развернуть ветку
Александр Валиулин

По поводу ссылки с википедии. Чтобы отражались хорошо, просто поставь пробел в конце адресной строки и удали. Тогда вместо таких символов просто кириллица будет.
https://ru.wikipedia.org/wiki/Дельта-кодирование

Ответить
Развернуть ветку
Kirill Vorotov
Первый — это полная синхронизация карты между всеми игровыми клиентами. В таком случае на компьютерах игроков бы воспроизводилась локальная симуляция. Так поведение всех объектов было бы на 100% предсказуемым — а вся информация бы обновлялась только тогда, когда происходят непредвиденные явления (например, действия игрока).

Тут мне кажется не хватает небольшого пояснения:
Синхронизация всех клиентов с сервером происходит на старте игры/при подключении клиента к серверу. Сервер пересылает клиенту актуальное состояние мира, после чего клиент может симулировать мир локально, без необходимости синхронизации с сервером несколько раз в секунду кроме случаев, когда игроки производят какие-то действия (но и даже так, можно было бы передавать только действия игроков, без необходимости передавать полный стейт игрового мира).
Но такой подход будет работать только при 100% детерминированной модели игрового мира, т.е. когда при одинаковых входных условиях мы всегда будем наблюдать абсолютно одинаковое развитие событий. К сожалению 100% детерминированности для сложной игры не добиться (по разным причинам, вплоть до разницы в вычислениях с плавающей запятой на разных архитектурах процессоров), о чём, собственно и идёт речь далее в статье.

Ответить
Развернуть ветку
Starik

А ещё первый вариант больше подвержен читерству (подмене данных клиента).

Ответить
Развернуть ветку
Artyom Kaleev
Автор

Спасибо за замечание, поправил :)

Ответить
Развернуть ветку
Madzai Sa

Я бы почитал как эту проблему решают в промышленных модах для Майнкрафта, который изначально на такое небыл рассчитан в принципе. Хотя там кроме мата читать наверное было бы нечего...

Ответить
Развернуть ветку
Анон Хмельный

Так там нет такой нагрузки, как в сф. Большинство машин "черные ящики", трубы не тянутся километрами с тысячами объектов внутри, предметы передвигаются стаками. Хотя лагомашина из труб билдкрафта вполне себе работала, когда в нее кучу предметов закидывают и заставляют по кругу циркулировать, с выбором в мир и загрузкой снова в трубы.

Ответить
Развернуть ветку
Madzai Sa
трубы не тянутся километрами с тысячами объектов внутри

Это потому что они лагают. И загрузка чанков дорого стоит, особенно на серверах в мультиплеере.

предметы передвигаются стаками

От мода зависит.

Хотя лагомашина из труб билдкрафта вполне себе работала

Пару майнеров с макс. апргейдами нормальненько нагружают. Конечно да, оптимально использовать машины(так и транспорт) в виде черного ящика который по-факту ничего не переносит, но красивости с трубами, конвеерами и мульти-блоковыми машинами сейчас в тренде. А если еще жидкости с газами...

Ответить
Развернуть ветку
ForJest

Майнкрафт изначально был расчитан на такое, прямо с момента появление редстоун-логики. К тому же не будем забывать . что автоматизация, инвентари и прочая есть и в ваниле: воронки, печки, тележки

Ответить
Развернуть ветку
Valery Arugin

Для тех кто хочет действительно в технические детали, есть толк от Юнити, где они рассказывают про реализацию сетевой составляющей в своем FPS Sample, в которой они применили большинство используемых сегодня техник, начиная от ECS, заканчивая упомянутой дельта-компрессией, интерполяцией и предсказанием на клиенте: https://www.youtube.com/watch?v=k6JTaFE7SYI

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

Ответить
Развернуть ветку
Крошечный клуб

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

Ответить
Развернуть ветку
Yes, Your Grace

Судя по описанию, обычное использование lodов

Ответить
Развернуть ветку
Wong Fei

а что там можно взаимодействовать с барахлом на ленте, например сбросить или передвинуть, есть физика?

Ответить
Развернуть ветку
Анон Хмельный

Нет нельзя. Можно только в инвентарь взять.

Ответить
Развернуть ветку
Wong Fei

ха, тогда непонятно откуда какие-либо проблемы и зачем в стиле КО для слабоумных пересказывать Source Multiplayer Networking

Ответить
Развернуть ветку
Дмитрий Орлов
По словам Даваллиуса, это даже не цель, которую нужно достичь, а необходимое требование для работы системы.

а требование - это типа не цель?)

Ответить
Развернуть ветку
Олег Воскобоев

Ноуп. Цель — игра без лагов и диких нагрузок на железо игрока/сервера.
А вот эта байда — обязательная составляющая первой предложенной схемы

Ответить
Развернуть ветку
Ivan Orlov

Требование первично, цель вторична.

Ответить
Развернуть ветку
Дмитрий Духнич

Пффф... технических деталей 0

Ответить
Развернуть ветку
Бaтыр Санжueв🛰️

Интересная тема. Но мало схем, графиков, цифр и кода. Все как будто на словах.

Ответить
Развернуть ветку
Читать все 35 комментариев
null