Хабрахабр

[Перевод] Сетевой код Age of Empires: 1500 лучников на модем 28,8 кбит/с

image

Примечание переводчика: этой статье уже 17 лет, и интересна она только с исторической точки зрения. Любопытно узнать, как удавалось разработчикам добиться плавной сетевой игры в эпоху 28,8k-модемов и первых «Пентиумов».

Также в ней излагаются современные и будущие подходы с созданию сетевой архитектуры, используемые Ensemble Studios в своих игровых движках. В этой статье рассказывается об архитектуре и реализации, а также о некоторых уроках, полученных при создании многопользовательского (сетевого) кода игр Age of Empires 1 и 2.

Мультиплеер Age of Empires: требования к структуре

В начале работы над многопользовательским кодом Age of Empires в 1996 году мы поставили перед собой очень конкретные цели, необходимые для реализации требуемого игрового процесса.

  • Масштабные и эпичные исторические битвы со множеством различных боевых единиц
  • Поддержка до 8 игроков в многопользовательском режиме
  • Плавная симуляция игрового процесса по LAN, через прямое модемное соединение и по Интернету
  • Поддержка целевой платформы: Pentium 90 с 16 МБ ОЗУ и модемом на 28,8 кбит/с
  • Система коммуникаций должна работать с уже имеющимся движком (Genie)
  • Стабильные 15 кадров в секунду на машинах с минимальной конфигурацией

Движок Genie уже был готов, а игровой процесс в однопользовательском режиме начинал принимать свои формы. Движок Genie — это двухмерный однопоточный движок игрового цикла. Спрайты рендерятся в 256 цветах в состоящем из тайлов мире. Случайно генерируемые карты заполнены тысячами объектов: от деревьев, которые можно срубать, до скачущих газелей. Приблизительная разбивка (после оптимизации) времени на выполнение задач движка: 30% на рендеринг графики, 30% на ИИ и поиск путей, 30% на выполнение симуляции и служебных задач.

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

Усложняло задачу и то, что время на выполнение каждого шага симуляции могло сильно меняться: время рендеринга зависело от того, наблюдает ли пользователь за юнитами, выполняет скроллинг или смотрит на неисследованную область, а длинные пути или стратегическое планирование ИИ значительно влияли на время выполнения игрового хода: колебания составляли до 200 мс.

Если просто передавать координаты X и Y, состояние, действие, направление взгляда и урон, то в игре может быть не больше 250 подвижных юнитов. Краткие расчёты показали, что передача даже небольшого набора данных о юнитах и попытки их обновлений в реальном времени сильно ограничивают количество юнитов и объектов, с которыми может взаимодействовать игрок.

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

Одновременные симуляции

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

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

Усовершенствование базовой модели

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

Поскольку при таком подходе она должна брать на себя ответственность за одновременно перемещение сотен или тысяч объектов, система обязана оставаться жизнеспособной даже при колебаниях задержек от 20 до 1000 миллисекунд и успевать обрабатывать изменения во время обработки кадров.

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

Марк [Террано] использовал систему пометки команд, которые должны быть выполнены через два «хода обмена данными» в будущем (ходы обмена данными в AoE были отделены от самих рендерящихся кадров).

Рис. То есть команды, отданные в ходе 1000, назначаются для выполнения во время хода 1002 (см. В ходе 1001 выполняются команды, отданные в ходе 0999. 1). Это позволяло нам принимать, подтверждать и подготавливать к обработке сообщения, в то время как игра продолжала отрисовывать анимации и выполнять симуляцию.

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

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

«Контроль скорости»

Рисунок 2. Контроль скорости.

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

При этом любая пауза сразу же становится заметной. Геймплей может ощущаться «тормозящим» по двум причинам: если частота кадров одной машины падает (или она ниже, чем у остальных), то другие машины обрабатывают свои команды, рендерят всё в выделенное время и в результате им приходится ждать следующего хода. Кроме того, тормозит игру задержка обмена данными — игрокам приходится ждать, пока машина получит достаточно данных для завершения хода.

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

Средний пинг до самого долгого клиента он отправлял тоже в сообщении о завершении хода (всего для контроля скорости использовалось 2 байта). Кроме того, каждый клиент также измерял «время пинга» от себя до других клиентов и обратно.

Затем хост отправлял новую частоту кадров и длительность хода обмена данными. В каждом ходе машина, назначенная хостом, анализировала сообщения о завершении хода, вычисляла необходимую частоту кадров и поправку на задержку передачи данных по Интернету. На рисунках 3-5 показано, как разбивался ход обмена данными в разных условиях.

Рисунок 3. Обычный ход обмена данными.

Рисунок 4. Высокая задержка передачи данных по Интернету с нормальной скоростью машины.

Рисунок 5. Низкая скорость машины с нормальной задержкой передачи данных.

«Ход обмена данными», который был приблизительно равен времени пинга туда-обратно для сообщения, был разделён на число кадров симуляции, которые в среднем могла выполнить за это время самая медленная машина.

Обычно игра замедлялась и тормозила только в моменты самых наихудших пиков — задержка передачи команд повышалась, но оставалась плавной (и увеличивалась всего на несколько миллисекунд за ход), потому что игра постепенно снижала задержки до наилучшей возможной скорости. Длительность хода обмена данными была взвешенной, поэтому могла быстро увеличиваться в соответствии с изменениями задержек передачи данных по Интернету и медленно снижаться до наилучшей средней скорости, которую можно поддерживать постоянно. Это создавало максимально возможную плавность игрового процесса, в то же время обеспечивая подстройку под изменяющиеся условия.

Гарантированная доставка

В сетевом слое использовался UDP, а упорядочиванием команд, распознаванием утерь и повторной передачей занимался каждый клиент. В каждом сообщении использовалась пара байтов, обозначающая ход, на который запланировано выполнение команд, и порядковый номер сообщения. Если сообщение принималось после хода, оно отклонялось, а для выполнения сохранялись входящие сообщения. Из-за самой природы UDP Марк использовал при получении сообщений следующий принцип: «Если есть сомнения, то нужно считать сообщение утерянным. Если сообщения приняты вне порядка, то получатель немедленно отправляет запрос на повторную передачу утерянных сообщений. Если подтверждение о получении принято позже предсказанного времени, отправитель просто снова отправляет сообщение, не ожидая сигнала о его утере».

Скрытые преимущества

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

Скрытые проблемы

Поначалу может показаться, что одинаковое выполнение двух экземпляров аналогичного кода реализовать легко, но это не так. Менеджер по продукции Microsoft Тим Знаменачек ещё на самых ранних этапах проекта сказал Марку: «В каждом проекте есть один упорный баг, который не сдаётся до самого финиша. Думаю, в нашем случае это будет рассинхронизация». И он оказался прав. Сложности поиска ошибок рассинхронизации множились при каждом небольшом изменении. Олень, чьё положение слегка отличается при создании случайной карты, будет двигаться немного иначе, а минуты спустя охотник слегка сместится с пути или промахнётся копьём, в результате вернувшись домой без мяса. Поэтому то, что иногда казалось всего лишь разницей в контрольных суммах количества пищи, имело причины, которые было очень сложно отследить.

Огромные (по 50 МБ) объёмы трассировки сообщений и дампов объектов мира ещё больше усложняли проблему. Хотя мы проверяли контрольными суммами мир, объекты, поиск путей, прицеливание и все остальные системы, всегда оставалось что-то, чего мы не могли учесть. Часть сложностей была концептуальной — программисты не привыкли к написанию кода, который использовал одинаковое количество вызовов генератора случайных чисел в симуляции (да случайные числа тоже порождались и синхронизировались).

image

Полученные уроки

При разработке сетевой части Age of Empires мы получили несколько уроков, которые можно применить к разработке любой игровой многопользовательской системы.

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

Поскольку они играли в однопользовательскую игру, было очень просто имитировать разные уровни задержек передачи команд и получать отзывы игроков («управление кажется хорошим/медленным/дёргающимся/просто ужасным»). На ранних этапах процесса разработки Марк с ведущим дизайнером прототипировали задержки обмена данными (этот прототип несколько раз пересматривался в процессе разработки).

Также интересно заметить то, что игроки привыкли к «темпу игры» и мысленному ожиданию задержки между нажатием мыши и реакцией юнита. Для игр жанра RTS задержки передачи команд в 250 миллисекунд даже незаметны, при 250-500 мс геймплей вполне играбелен, а заметны тормоза становятся при 500 мс и выше. Постоянная замедленная реакция была лучше, чем скачки задержек передачи команд (допустим, от 80 до 500 мс) — в этом случае постоянные задержки в 500 мс воспринимались играбельными, а переменчивые казались «дёргаными» и усложняющими игру.

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

Поскольку активные действия в нашей игре постоянно нарастали, самые высокие требования к обмену данными возникают в середине и ближе к концу игры. Также мы замеряли требования пользователей к системе — обычно они отдавали команды (двигаться, атаковать, рубить деревья) примерно каждые полторы-две секунды, иногда с пиками в 3-4 команды в секунду во время ожесточённых боёв.

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

В целом, наблюдение за пользователями позволит вам:

  • Узнать ожидания пользователей о задержках в игре
  • Прототипировать аспекты мультиплеера ещё на ранних этапах разработки
  • Увидеть поведение, вредящее скорости многопользовательского режима.

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

Такие неожиданные вещи, как случайные гонки между ИИ, сложные в вычислении пути и плохо структурированные пакеты команд могут вызывать огромные проблемы производительности, даже когда система в остальном работает хорошо. Урок: часть проблема с обменом данными в AoE возникла, когда Марк выводил метрики слишком рано, и не проверял уровни сообщений (длину и частоту) заново после подготовки финального кода.

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

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

В целом, метрики должны обладать следующими свойствами:

  • Быть человекочитаемыми и понятными тестерам
  • Указывать на узкие места, тормоза и проблемы
  • Мало влиять на выполнение и постоянно быть запущенными.

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

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

Другие уроки. Это должно быть обычным здравым смыслом — но если вы зависите от сторонней сети (в нашем случае это DirectPlay), то напишите независимое тестовое приложение, подтверждающее, что когда владельцы заявляют о «гарантированной доставке», сообщения действительно доходят, что «гарантированной порядок пакетов» на самом деле есть, и что в продукте нет скрытых узких мест или странного поведения при обработке передаваемых данных в вашей игре.

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

Ведь проблемы сложно изолировать (в чём причина резкого снижения скорости — провайдер, игра, коммуникационное ПО, модем, служба поиска соперников для матча или что-то ещё?), а пользователи не хотят возиться с медленными dialup-соединениями, привыкнув к мгновенным скоростям LAN. Проводите тестирование с модемами (и, если повезёт, с симуляторами модемов) как можно раньше; продолжайте модемное тестирование (как бы мучительно это ни было) на протяжении всего процесса разработки. Жизненно необходимо выполнять тестирование на модемных соединениях с тем же упорством, что и при многопользовательских играх по LAN.

image

Усовершенствования для Age of Empires 2

В Age of Empires 2: The Age of Kings мы добавили такие многопользовательские функции, как запись игр, передача файлов и постоянное отслеживание статистики на сайте The Zone. Также мы улучшили такие системы мультиплеера, как интеграция с DirectPlay и контроль скорости, чтобы справиться с багами и проблемами скорости, выявленными после выпуска Age of Empires.

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

В Age of Kings мы расширили её, и это позволило нам управлять параметрами запуска и обеспечивать постоянную отчётность о статистике. Наша интеграция с системой поиска соперников (матчмейкинга) сервиса The Zone была ограничена в Age of Empires простым запуском игры. В бэкенде мы реализовали постоянную отчётность и отслеживание статистики. Это позволяло игрокам лучше находить игры, которые им были интересны, потому что они могли видеть параметры уровня матчмейкинга, а не ждать перехода на экран настройки игры. Данные из этой структуры использовались для создания рейтингов пользователей и их демонстрации на веб-сайте The Zone. Мы предоставили The Zone общую структуру, которая заполнялась и передавалась на сервер в конце игры.

image

Мультиплеер RTS3: задачи

RTS3 — это кодовое имя стратегической игры Ensemble нового поколения (прим. пер.: игра вышла под названием Age of Mythology). Структура RTS3 создаётся на основе успешной формулы, использованной в серии игр Age of Empires, с добавлением множества новых функций и требований к многопользовательскому режиму.

  • Основана на наборе возможностей Age of Empires 1 и 2. Обязательны такие требования, как игра по Интернету, большие и разнообразные карты, тысячи управляемых юнитов.
  • 3D: RTS3 — это полностью трёхмерная игра с интерполируемой анимацией и недискретными положениями и поворотами юнитов.
  • Больше игроков — поддержка более чем восьми игроков.
  • Поддержка TCP/IP: наша основная цель — Интернет-подключение TCP/IP со скоростью 56 кбит/с.
  • Поддержка домашних сетей — поддержка сетевых конфигураций конечных пользователей, в том числе фаерволлов и NAT.

Ещё на ранних этапах разработки RTS3 мы приняли решение придерживаться той же внутренней сетевой модели, что и в Age of Empires 1 и 2 — синхронной симуляции — потому что структура RTS3 сможет во многом использовать преимущества такой архитектуры. В AOE/AOK мы использовали для служб передачи и управления сессиями DirectPlay, но для RTS3 решили создать базовую сетевую библиотеку, используя в качестве основы исключительно основные процедуры сокетов.

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

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

Архитектура обмена данными RTS3

Рисунок 6. Строгая объектно-ориентированная сетевая архитектура RTS3.

Рисунок 6). Объектно-ориентированный подход. Сетевая архитектура RTS3 обладает строгой объектно-ориентированностью (см. Требования поддержки различных сетевых конфигураций позволяют воспользоваться преимуществами ОО-подхода, абстрагироваться от специфики платформы, протокола и топологии, лежащих в основе набора обобщённых объектов и систем.

Основной функционал этих объектов изобилирован в высокоуровневые родительские объекты. Специфичные для протокола и топологии версии сетевых объектов содержат как можно меньший объём кода. Никакие другие объекты системы (такие как Channels, TimeSync и т.д.) не требовали изменений, потому что они имели интерфейс с клиентом и сессией только через свои высокоуровневые абстрактные интерфейсы. Для реализации нового протокола мы расширяли только те сетевые объекты, которым требовался специфичный для протокола код (например, для клиента и сессии, которые в зависимости от протокола должны действовать немного по-разному).

В RTS3 мы продолжили использовать эту топологию, потому что при реализации с моделью синхронной симуляции она имеет неотъемлемые преимущества. Одноранговая топология. Движок Genie поддерживал топологию сети peer-to-peer, в которой все клиенты в сессии соединяются друг с другом в конфигурации «звезда».

То есть каждый клиент подключен ко всем остальным клиентам. Одноранговая топология подразумевает использование для подключенных в сессии клиентов конфигурации «звезда» (Рисунок 7). Такая же схема использовалась в Age 1 и 2.

Рисунок 7. Конфигурация «звезда» одноранговых клиентов в сессии.

Преимущества Peer-to-peer:

  • Снижение латентности благодаря схеме передачи сообщений «клиент-клиент» вместо «клиент-сервер-клиент».
  • Нет центрального слабого звена — если клиент (даже хост) отключается от сессии, игра может продолжаться.

Недостатки Peer-to-peer:

  • Больше активных соединений в системе (сумма от n=0 до k-1 (n)), то есть больше потенциальных слабых звеньев и выше вероятные задержки.
  • Невозможность поддержки в такой схеме некоторых конфигураций NAT.

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

Рисунок 8. Четыре слоя служб нашей сетевой модели.

нового поколения, в котором используется модульная архитектура с такими библиотеками компонентов, как звук, рендеринг и сеть. RTS3 основана на нашем движке BANG! (а также с различными внутристудийными инструментами). Подсистема сети встроена сюда как компонент, но связана с движком BANG! Рисунок 8). Наша сетевая модель разделена на четыре слоя служб, которые почти, но не полностью, не похожи на сетевую модель OSI, применённую в игре (см.

Socks, уровень 1

Он абстрагирован для создания обобщённого набора низкоуровневых сетевых процедур для множества операционных систем. Первый уровень, Socks, обеспечивает фундаментальный API уровня сокетов на языке C. Уровень Socks в основном используется более высокими уровнями сетевой библиотеки и на самом деле не предназначен для использования кодом приложения. Интерфейс напоминает интерфес сокетов Беркли.

Link, уровень 2

Объекты на этом уровне, такие как Link, Listener, NetworkAddress и Packet, представляют собой полезные элементы, необходимые для установки соединения и передачи по нему сообщений (см. Уровень 2, Link, обеспечивает службы транспортного слоя. Рисунок 9).

  • Packet (пакет): это наша фундаментальная структура сообщений — расширяемый объект, автоматически управляющий своей сериализацией/десериализацией (исключительно с помощью виртуальных методов) при передаче по объекту ссылки.
  • Link (ссылка): соединение между двумя конечными точками сети. Она может быть также ссылкой на себя, и в этом случае обе конечные точки находятся на одной машине. Методы send и receive ссылки знают, как работать с пакетами, а также с буферами данных void*.
  • Listener (слушатель): генератор ссылок. Этот объект слушает входящие соединения и создаёт ссылку после установки соединения.
  • Data stream (поток данных): это произвольный измеряемый поток данных через заданную ссылку, используемый, например, для передачи файлов.
  • Net Address (сетевой адрес): объект сетевой адресации, независимый от протокола.
  • Ping: простой класс пинга. Сообщает о задержке сети, присутствующей при связи со ссылкой.
  • Рисунок 9. Уровень Link.

Multiplayer, уровень 3
Уровень мультиплеера — это самый высокий уровень объектов и процедур, присутствующий в API net.lib. Это слой, с которым взаимодействует RTS3 при сборе объектов более низкого уровня, таких как ссылок и их преобразовании в более полезные концепции/объекты — клиенты, сессии и так далее.

являются те, которые находятся в уровне мультиплеера. Самыми интересными объектами в сетевой библиотеке BANG! Здесь API предоставляет набор объектов, с которыми может взаимодействовать уровень игры, однако обеспечивает в реализации независимый от игры подход.

  • Client (клиент): самая базовая абстракция конечной точки сети. Может быть сконфигурирована как удалённый клиент (ссылка) или как локальный клиент (ссылка на себя). Клиенты не создаются напрямую, а порождаются объектом сессии.
  • Session (сессия): это объект, отвечающий за создание, выполнение соединений, сбор и управление клиентами. Сессия содержит все другие объекты уровня мультиплеера. Для использования этого объекта приложение просто вызывает host() или join(), передавая им или локальный, или удалённый адрес, а всем остальным занимается сессия. В сферу её обязанностей входит автоматическое создание/удаление клиентов, отправка уведомлений о событиях сессии и управление трафиком к соответствующим объектам.
  • Channel и Ordered Channel: этот объект представляет собой виртуальный канал передачи сообщений. Передаваемые по каналу сообщения автоматически разделяются и получаются соответствующим объектом канала в удалённых клиентах. Упорядоченный канал работает с объектом TimeSync, чтобы обеспечить одинаковый порядок полученных по этому каналу сообщений для всех клиентов.
  • Shared Data: представляет собой коллекцию общих для всех клиентов данных. Можно расширить этот объект для создания конкретных экземпляров, содержащих ваши собственные типы данных, а затем использовать встроенные методы для обеспечения автоматического и синхронного обновления этих элементов данных по сети.
  • Time Sync: управляет плавным изменением синхронизированного сетевого времени для всех клиентов в сессии.

Game Communications, уровень 4

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

image

Новые функции и улучшенные инструменты

Улучшенная система синхронизации. Никто из команды разработки Age of Empires не мог бы сказать, что нам не нужны более качественные инструменты синхронизации. Как и в любом проекте, при анализе процесса разработки в постмортеме оказывается, что на некоторые области тратилось больше всего времени, но его могло быть гораздо меньше, если бы мы занялись ими заранее. При начале разработки RTS3 в верхних строчках списка таких областей была отладка синхронизации.

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

Проверка синхронизации в RTS3 выполняется с помощью двух наборов макросов:

#define syncRandCode(userinfo)
gSync->addCodeSync(cRandSync, userinfo, __FILE__, __LINE__)

#define syncRandData(userinfo,
v) gSync->addDataSync(cRandSync, v, userinfo, __FILE__, __LINE__)

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

syncRandCode("syncing the random seed", seed);

Консольные команды — это простые вызовы функций, выполняемые с помощью файла конфигурации запуска, внутриигровой консоли или UI, которые вызывают произвольный функционал игры. Синхронные команды консоли и переменные конфигурации. Как может подтвердить любой разработчик модов для Quake, консольные команды и переменные конфигурации очень важны для процесса разработки. Переменные конфигурации являются именованными типами данных, предоставляемыми через простые функции get, set, define и toggle, которые мы используем для всевозможного тестирования и настройки параметров конфигурации.

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

Они могут быстро добавлять новые инструменты тестирования и конфигурации и с лёгкостью включать их в сетевом окружении. Благодаря использованию этих двух инструментов разработчики могут использовать систему мультиплеера без написания кода.

Подводим итоги

Синхронная симуляция и модель peer to peer успешно использовались в серии игр Age of Empires. Несмотря на критическую важность вложения времени в создание инструментов и технологий для решения основных проблем такого подхода (таких как синхронизация и сетевые метрики), жизнеспособность этой архитектуры в жанре стратегий реального времени доказана опытом. Последующие улучшения, внесённые нами в RTS3, привели к тому, что многопользовательский игровой процесс практически неотличим от однопользовательского даже в самых ужасных условиях сетевых соединений.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»