Сучасна диджитал-освіта для дітей — безоплатне заняття в GoITeens ×
Mazda CX 5
×

Почему я выбрал серверную разработку в геймдеве

Меня зовут Арсен, я .NET Developer в компании Plarium, занимаюсь серверной частью проекта Raid: Shadow Legends, мобильной RPG в жанре темного фэнтези.

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

Как я пришел к .NET

Я начал карьеру с должности фулстек-девелопера в небольшой IT-компании: бэкенд — на .NET, фронтенд — на Angular. Мне нравилось самому отвечать за весь цикл разработки и знать, как что реализовано на клиенте и сервере, как хранится в базах данных. Но были и минусы — огромный спектр задач и миллион ежедневно обновляющихся фреймворков. Когда пытаешься уследить за одним, пропускаешь другое и неизбежно где-то проседаешь. Я захотел стать узконаправленным специалистом, поэтому начал задумываться о переходе на .NET или фронтенд.

Когда я почувствовал себя увереннее в профессии, мне захотелось работать в компании покрупнее, с более интересными проектами. Я перешел в другую аутсорс-компанию, где занимался чисто сервером. Работая там, попал на конференцию uDev и узнал больше о Plarium. К тому времени я уже немного разбирался в Unity — смотрел уроки на YouTube, делал pet projects, — поэтому решил попробоваться как Unity Developer и получил оффер.

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

Что отличает работу в геймдеве

Восприятие продукта своим

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

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

С огромным проектом на аутсорсе так не происходит. Ты не знаешь, будет он у вас завтра или нет. Даже когда в разработке долгосрочный проект, всё равно чувствуешь, что выполняешь его для внешнего заказчика, который внезапно может сказать: «Ребята, вы нам не подходите, мы решили работать с другой компанией».

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

Быстрое решение проблем

Думаю, геймдев не подойдет тем, кто считает, что разработка игр — сплошной фан и развлечения. Это далеко не так.

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

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

Ответственность за фичи и фидбэк от игроков

Когда сделал фичу, люди ставят 5 звезд, пишут «классно», и это вдохновляет. Но, если фича нравится игрокам, это в первую очередь заслуга гейм-дизайнеров. Как серверный разработчик я отвечаю за то, чтобы фича работала корректно и стабильно, чтобы игра не вылетала и не было проблем с производительностью.

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

На одном из проектов как-то начали откатываться пользователи. Это была офлайн-игра: каждое действие пользователя мы сохраняли на девайсе и раз в 30–40 секунд отправляли на сервер. Сервер валидировал, сохранял и отправлял на клиент запрос, что всё в порядке. Но иногда действия на клиенте и сервере разнились. Если у сервера не получалось повторить действие клиента, он автоматически думал, что клиент читер, и всё откатывал. Клиент опять пытался отправить запрос на сервер — и всё заново.

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

Под капотом серверной разработки

У нашего сервера очень тонкий стек. Он построен так: чистый .NET, ASP.NET и MS SQL Server. Никаких сложных и долгих entity-фреймворков, всё происходит просто и быстро. Наши серверы обрабатывают 16 тысяч запросов в секунду и 140 миллионов внутриигровых битв в день.

Когда работаешь с высоконагруженной системой, должен понимать на уровень глубже, знать все узкие места и понимать, как всё устроено внутри платформы. На небольших проектах я не задумывался, как работает какой-нибудь сборщик мусора. А на таких проектах, как Raid: Shadow Legends, даже он может работать долго — мы увидели это, когда собрали аналитику. Я не знал, что такое возможно: в .NET сборщик мусора реализован автоматически и тебе не нужно за ним следить.

Глубокое знание системы

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

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

Для нашего проекта иногда выгоднее написать кастомное решение. Например, мы сами запилили сериализатор JSON: в плане производительности было неэффективно использовать third-party фреймворки. Они сложные, и у них объемный функционал: валидация данных, сбор аналитики, диагностика проблем. Но нас интересовала только одна задача, которую нужно было выполнять максимально быстро: сериализовать модель данных в JSON-строку и обратно. Использовать свой простой инструмент для нас оказалось в несколько раз эффективнее.

Задачи, которые невозможно загуглить

Я думаю, что большая часть проблем, с которыми сталкивается серверный программист в геймдеве, связаны не с особенностями системы, а с бизнес-задачами. Когда я был начинающим фулстек-разработчиком, я постоянно гуглил: как добавить что-то на страничку, как в вебе что-то посчитать, как в ангуляре что-то реализуется. А здесь — чистый .NET. Да, я могу погуглить, как Apple реализует какой-то API, но это всё.

У меня был таск на сохранение прогресса игроков без привязанного ID. Что, если игрок на 100-м или 200-м уровне нечаянно удалит игру? Мы заботимся о наших пользователях, поэтому для нас было важно попытаться сохранить и восстановить прогресс.

Сложность заключалась не в техническом исполнении, а в поиске решения. На других наших проектах не было такого функционала, мы придумывали всё с нуля. Поскольку это офлайн-игра, нам нужно было придумать, как сохранять данные до следующего интернет-подключения. В итоге мы решили использовать Google Drive или iCloud. Когда пользователь устанавливал игру, в облачном хранилище автоматически создавался токен. Без подключения к интернету данные хранились на телефоне. Как только подключение появлялось, данные синхронизировались с облаком. Если игра удалялась, мы теряли токен на сервере, но он сохранялся в облачном хранилище. При повторной установке игры мы проверяли токен и предлагали игроку выбор: восстановить прогресс или играть заново.

Но возникла еще одна проблема: оказалось, что токен мог прилетать с драйва не сразу. Google Drive работает рандомно, iCloud стабильнее, но всё равно токен мог не прийти или не записаться. У нас был сервис, который постоянно крутился в цикле и проверял, есть токен или нет. Google синхронизировал токен каждые 24 часа: получается, в течение суток прогресс игрока мог быть недоступен. Пользователь мог скачать игру заново, получить двадцатый уровень. А потом токен обнаруживался, подтягивался с драйва и у пользователя оказывалось два прогресса. В таком случае мы показывали игроку оба прогресса: заработанный уровень и монеты в каждом. Игрок сам выбирал, какой прогресс сохранить, а второй мы удаляли.

Для меня геймдев — это технический вызов. На мой взгляд, если ты кайфуешь от игр, это не значит, что будешь более крутым разработчиком. Главное, чтобы тебе нравилось решать именно такие задачи.

Полезные ресурсы

Разобраться в высоконагруженных системах, игровой и мобильной разработке мне помогли несколько книг и курсов. Если вам тоже интересно, велкам :)

Что послушать:

  • Мини-конференции CLRium — канал с конференциями по .NET. Про устройство платформы .NET: выделение памяти, сборка мусора, потоки, реализация внутренних механизмов, многопоточность, оптимизация и многое другое. Будет интересно тем, кто хочет копнуть чуть глубже;
  • Brackeys — канал о геймдеве, по нему я начинал учить Unity;
  • Unit Testing for C# Developers — курс для начинающих по юнит-тестам на C#;
  • React Native — The Practical Guide — курс, который я прошел, чтобы «потрогать» мобильную разработку. Было настолько интересно, что на протяжении месяца я вставал в 6 утра, чтобы смотреть уроки.

Что почитать:

  • «CLR via C#. Программирование на платформе Microsoft .NET», Джеффри Рихтер;
  • «C# для профессионалов. Тонкости программирования», Джон Скит;
  • «Эффективная работа с унаследованным кодом», Майкл Физерс;
  • «Приемы объектно-ориентированного проектирования. Паттерны проектирования», Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес;
  • «Unity в действии. Мультиплатформенная разработка на C#», Джозеф Хокинг;
  • «Высоконагруженные приложения. Программирование, масштабирование, поддержка», Мартин Клеппман.
👍ПодобаєтьсяСподобалось14
До обраногоВ обраному3
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Но возникла еще одна проблема: оказалось, что токен мог прилетать с драйва не сразу. Google Drive работает рандомно, iCloud стабильнее, но всё равно токен мог не прийти или не записаться. У нас был сервис, который постоянно крутился в цикле и проверял, есть токен или нет. Google синхронизировал токен каждые 24 часа: получается, в течение суток прогресс игрока мог быть недоступен.

Любопытно, а зачем пришлось рвать зубы через задницу вместо того, чтоб просто сделать обязательное подключение, проверять наличие интернета и синхронизироваться с сервером? Или там было прям критично, чтоб игра оставалась оффлайновой? В таком случае звучит как идиотский каприз геймдизайнера. Можно и компромиссный вариант сделать — значок статуса онлайн\оффлайн и предупреждать игрока, что в оффлайн-моде его прогресс «мей би лост».

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

Вариант со значком статуса, кстати, прикольный:)

Он построен так: чистый .NET, ASP.NET и MS SQL Server. Никаких сложных и долгих entity-фреймворков, всё происходит просто и быстро.

Так и что никаких ORM при связке .net + mssqlserver? Что там остается — только голые запросы на ADO.NET? Ок, а если пишите кастомное и «быстрое», то как с секьюрностью вопросы решаете, те самые OWASP top-10...

Хороший вопрос!)

Давайте пройдемся по основным пунктам, которые применимы к нашему проекту.

  • Injection — Все верно, ORM мы не используем. Вместо запросов, которые построены формированием строк, используем параметризированные запросы. Кроме того, все данные игрока хранятся в сжатом и зашифрованном виде. Поэтому риск SQL-инъекций и несанкционированного чтения этих данных сводится к минимуму.
  • Broken Authentication — Мы регулярно проводим аудиты наших модулей аутентификации. По результатам — не было найдено критических уязвимостей.
  • Sensitive Data Exposure — Вся работа с данными игрока производится в рамках GDPR.
  • Broken Access Control — Ролей у нас в игре всего 2: обычные игроки и админы. Функционал определения админа определяется конфигом, который извне никак не поменять.
  • Security Misconfiguration — Мы используем разные конфигурации для разных серверов (Test, Production). Следим за тем, чтобы конфиденциальные данные не были отображены в ошибках и различных сообщениях на клиенте.
  • Insecure Deserialization — Мы не принимаем сериализованные объекты из ненадежных источников. Используем их только для обмена данными между внутренними сегментами и сервисами.
  • Plarium это не геймдев, Plarium это про то, как подсаживать людей на наркотики.

    А який геймдев не про наркотики?) Як ще людей змусити нести свої гроші?

    Робити хороші сінглплеєри які люди будуть купувати?

    Робити хороші сінглплеєри які люди будуть купувати?

    Такие как геншин, например? Проект автора нервно курит под плинтусом, если сравнивать с «наркотичностью» и баблососательностью этого сингплеера (ну, точнее, мультиплеер там есть, но очень условный).

    Робити хороші сінглплеєри які люди будуть купувати?

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

    Неплатежеспособная аудитория, разработка не окупится

    Plarium это не геймдев, Plarium это про то, как подсаживать людей на наркотики.

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

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

    а если лично вы не понимаете — загляните в раздел Apple Arcade. вот то про игры, а не про подсаживание людей на иглу.

    Это вы не понимаете разницу между бизнесом и благотворительностью. Мораль применимо к бизнесу ограничена законодательством. Все, что не запрещено, не наказуемо и при этом приносит деньги — морально.

    Apple Arcade без внутриигровых покупок и рекламы — всего лишь одна из моделей монетизации, которая имеет большую проблему: для того, чтоб сохранить их демократичную цену, нужно огромное количество подписчиков. Причем постоянных подписчиков. Для того, чтоб они оставались, нужен качественный и обновляющийся контент, который стоит дорого. И тут получается замкнутый круг — для того, чтоб заинтересовать разработчиков игр (финансово, разумеется), эпплу нужно платить им немалое количество денег. Иначе игры будут скучны, с плохой графикой и со скудным контентом: художники, геймдизайнеры, аниматоры и программисты работают не бесплатно (сюрприз!). А для того, чтоб деньги платить, нужно много подписчиков. Пока что яблочная компания эту проблему не решила. Год назад вообще было относительно громкое событие, когда расторгли контракт с несколькими разработчиками для Apple Arcade:

    While Apple Arcade was critically acclaimed upon launch, none of the 120 titles on offer managed to taste great popularity. While the company hasn’t revealed performance figures, Arcade recently began offering a second free trial month that might be an indicator that users don’t retain their subscription for long.

    gadgets.ndtv.com/...​etain-subscribers-2255959

    Платформа еще относительно молодая и ее судьба зависит от политики Apple и будут ли они готовы вливать в нее деньги (т.е. платить разработчикам) с расчетом на будущее. Посмотрим.

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

    Кстати, Apple Arcade — далеко не новаторский подход. Около 10-12 лет назад стали популярны казуальный Hidden Object игры от дистрибутора Big Fish Games. Половина Украины, помню, на них пахало — условия были индивидуальны для каждой студии разработки, но в целом это был fixed price плюс крохотный процент от продаж. Для пользователя это была фиксированная цена за игру (новые — дороже, старые — дешевле), плюс можно было оформить подписку, которая давала возможность покупать со скидкой. Затем интерес к таким играм угас и началась эра микротранзакций.

    Мораль применимо к бизнесу ограничена законодательством. Все, что не запрещено, не наказуемо и при этом приносит деньги — морально.

    дальше просто не вижу смысла продолжать эту дискуссию.

    дальше просто не вижу смысла продолжать эту дискуссию.

    Да, не нужно, поберегите своё белое пальто.

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

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

    либо и дальше донатить, донатить, донатить

    www.youtube.com/...​G8ow&ab_channel=iXBTgames

    Можно в 12 ночи зайти в чат команды, а там как будто полноценный рабочий день.

    Додавайте це в опис кожної геймдев вакансії, будь ласка.

    Raid: Shadow Legends

    это ж самая агрессивная мобильная донатная помойка ©

    Почему я выбрал серверную разработку в геймдеве

    В тексті написано, що не обирав, а так склалось. Отримав типове:

    по-другому относиться к проектам: они больше воспринимаются «своими».

    Вони не твої, якщо нема чуттєвого відсотку від прибутку. І за цей єдиний «плюс», отримав:

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

    То питання з заголовку лишається. Валіть з геймдеву. Можна мати не гірше по всім параметрам, і можна обрати по яким набагато краще буде (бобло, work/life, impact, tech complexity).

    Мы заботимся о наших пользователях,

     — як гравець, я не зовсім згідний з цим твердженням. І доказом можуть послужити коментарі під постами з офіційної сторінки у фб :)
    А в цілому, цікаво було почути вашу історію. Окрема подяка за референс на книги та канали з курсами :)

    максимально быстро: сериализовать модель данных в JSON-строку и обратно. Использовать свой простой инструмент для нас оказалось в несколько раз эффективнее.

    В Go така штука вирішується через кодогенерацію, а у вас як?
    Замість JSON-у могли вибрати оптимальнішу сералізацію Protobuf чи FlatBuffers

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

    А об’єднати монети?

    Замість JSON-у могли вибрати оптимальнішу сералізацію Protobuf чи FlatBuffers

    Як завжди, на великих лайв проектах, потрібно дивитись на імпакт від такого рішення і провести хороший trade-off аналіз (про методику його можна почитати тут)

    Та і protobuf це ж не тільки про серіалізацію. Думаю, з врахуванням кількості написаного коду для комунікації між сервісами та клієнтами, перехід на protobuf може бути дорожчий, аніж оптимізація існуючого підходу. Хоча, знову ж таки, на мою думку, на таке рішення потрібно провести trade-off та порахувати імпакт аби можна було ствердно приймати рішення опираючись на факти

    В Go така штука вирішується через кодогенерацію, а у вас як?
    Замість JSON-у могли вибрати оптимальнішу сералізацію Protobuf чи FlatBuffers

    FlatBuffers и ProtoBuf ещё не было, когда начиналась разработка сервера социальных проектов, а многое из них сейчас используется на Рейде.

    Потом рассматривали Protobuf, но не стали переходить из-за недостатка клиентских библиотек. Также мигрировать всех пользователей на этот формат на живых проектах очень рискованно. Ну и плюс можно сказать, что у JSON в целом преимущество в читаемости, плюс наша библиотека работает быстрее Jil, .NET Core сериализации, и даже быстрее, например, чем MessagePack.
    Надо учитывать, что с нашими нагрузками важен не только размер данных, а и эффективность самой библиотеки, чтобы при большом кол-ве вызовов и потоков не возникло проблем с производительностью.

    А об’єднати монети?

    Точной причины я уже не помню, но монеты мы решили не суммировать.

    FlatBuffers и ProtoBuf ещё не было, когда начиналась разработка сервера социальных проектов, а многое из них сейчас используется на Рейде.

    чёт тебе не то рассказали, протобаф уже был, лет 7 назад ваш Паша согласился с моими доводами что эта переделка сериализатора костыль и к тому же опасный костыль. И да это переделка, а не кастомная реализация, в основе ньютонсофт старючей версии, а ускорение за счёт удаления отказоустойчивости, валидации и прочего. Если сейчас там что-то другое, то заменили соответственно 6 лет назад или позже, а протобафу 13 лет официально, но он не с нуля, все то что он делает было в не сильно удобной реализации под другим именем. А вот эти все отговорки про то что джейсон можно прочитать полный бред, это исключительный случай и не текстовую сериализацию, при желании, тоже можно прочитать предварительно конвертнув

    Підписатись на коментарі