Рассказывать о новых проектах это, конечно, хорошо, но не всегда всё получается, как мы хотим.
В общем, начали тут вспоминать факапы из прошлого, когда решение одной проблемы прибавляло новых, увлеклись и решили поделиться парочкой. Как забанить невиновных игроков, заддосить собственные сервера, ошибиться в одной букве и словить тонны негатива от пользователей — вот это всё, как мы любим.
Было время, когда нашу игру War Robots из-за недостатков в архитектуре атаковали читеры. Были утилиты, увеличивающие запас здоровья до космических значений, что делало их практически бессмертными. Таск с читерами мы в итоге закрыли, но не сразу.
Сначала мы хотели решить проблему красиво на техническом уровне: заблокировать возможность изменять на клиенте параметры робота. Сделать нам этого не удалось (потом, конечно, нашли способ). И тогда первым работающим решением стал банхаммер, который вычислял читеров по простой схеме:
Решение было костыльным, но действенным. Проблемы из-за него начались чуть позже, но сначала придется немного рассказать о другом баге и особенности разработки синхронного мобильного PvP.
Когда у игроков сильно шалит интернет-соединение (а в мобильных играх это нормальная ситуация), при обмене данными между клиентом и серверами могут происходить совершенно волшебные вещи. Запросы от клиентов приходят неполными, не в том порядке или с сильной задержкой. В общем, один серверный баг допускал, что при плохом соединении клиент может присылать результаты боя два или даже три раза подряд. Соответственно, игроки могли получать в 2-3 раза больше наград или случайно потратить на ремонт вдвое больше ресурсов.
Эту проблему мы решили довольно быстро: профиль-сервер научился игнорировать лишние результаты боя от одного клиента. После успешного тестирования мы зарелизили новую версию.
Вот тут-то нас и накрыло.
Целую кучу игроков ежедневно начало банить банхаммером, про который мы благополучно забыли, т.к. проблема неубиваемых роботов с бесконечным запасом здоровья была далеко в прошлом. Оказалось, что как только клиент игрока присылал на сервер результаты одного боя в двойном количестве, банхаммер воспринимал это так, что каждый погибший робот был убит дважды — т.е. получил урон, вдвое превосходящий его здоровье. И после каждого боя игроки улетали в бан пачками.
Всех, конечно, разбанили и даже компенсацию выплатили, но ситуация так себе, не позитивная точно.
Уже писали про эволюцию нашей инфраструктуры серверов, а сейчас вспомнили один случай того времени.
В конце 2015 года состоялся релиз долгожданной фичи в War Robots — кланов. Когда вышло обновление (а это было поздно вечером), мы открыли шампанское и все было бы хорошо. Но радоваться пришлось недолго — серверам внезапно стало плохо. Оказалось, что мы собственными руками устроили себе DDoS-атаку.
Как? Очень просто. Клиент на экране результатов боя в попытках получить информацию о кланах игроков делал слишком много запросов. И когда сервер отвечал «отстань, ошибка», клиент без какого-либо тайм-аута возвращался к серверу.
Той же ночью мы запилили флажок (шампанское мы при этом закрыть не успели), который контролировался с профиль-сервера — он полностью блокировал работу Hangar Client API. Игрокам, которые уже вступили в кланы, мы этот флажок оставили включенным, то есть у них все работало, потому что их количество было недостаточно, чтобы заDDoSить сервера.
В итоге мы начали корректно обрабатывать ответы сервера в игре, а в случае ошибки — увеличивать таймаут на повтор запроса.
Отдельная история — это когда некачественная реализация встречает человеческий фактор. Только теперь никого не банили, а наоборот раздавали рейтинг налево и направо. Короче, как-то ночью наш мониторинг (а мы мониторим вообще всё) зафиксировал слишком быстрый рост рейтинга игроков.
Потом выяснилось, что сама реализация подсчета очков в теории позволяла дублировать данные. Но никто бы на это не обратил бы внимания, если бы дежурный админ из-за опечатки в одной букве случайно рестартнул сервер, который не должен был работать. Именно он и начал удваивать игрокам рейтинги.
Пришлось срочно выпускать фикс и пройтись по базе, чтобы удалить все лишние очки, которые успели начислиться. Чтобы этого не повторилось — на всех серверах мы выпилили старую схему расчета очков и исключили возможность ошибочного запуска сервисов там, где они работать не должны. Надо было так с самого начала сделать, конечно, но было бы слишком скучно.
С опечаткой был еще один факап, но куда более серьезный.
Как-то на Хэллоуин мы запускали новую гачу — лотерею. Если кто не знает, гача — это механика получения предмета из нескольких разных случайным образом. В лотерее у игрока был ограниченный видимый набор призов разной ценности. За каждое открытие игрок получал 1 приз, этот приз вынимался из набора, а цена открытия с каждым разом возрастала. Таким образом игрок мог гарантированно скупить все призы лотереи, а счастливчики вынимали самые ценные призы на первых открытиях (и соответственно получали их очень дёшево).
В общем, потом и кровью мы запилили фичу к ивенту, протестили, выложили. Запускаем, обновляем графики… УРА! Они рванули вверх!.. И одновременно на нас обрушиваются тонны негатива в комьюнити, что мы якобы обманываем своих игроков.
Уже через полчаса лотерею пришлось выключить. Да, мы действительно обманывали игроков. Но дело было вовсе не в шансах или призах — дело было в одной букве.
В интерфейсе лотереи указана стоимость текущего открытия (та, которая возрастала с каждым разом), например, PRICE: 100 Gold. Вот как выглядел концепт (обратите внимание, что по задумке на каждой карточке также дополнительно указана цена ее открытия):
А вот как это вышло на проде, когда в результате ряда «улучшений» PRICE (цена за участие в лотерее) внезапно для проектировщика превратилась в PRIZE (приз):
В то же самое время из-за неразберихи перед релизом и плохого чекинга с каждой отдельной карточки пропала цена за открытие, что всё вместе и запутало игроков.
И они рефлекторно жали кнопку, пока не тратили всю харду. Ну а что, «приз» же увеличивается с каждой покупкой. И так было на 18 языках. При этом у нас еще и «локали» были на клиенте, поэтому исправить даже одну букву можно было только через хотфикс.
Ситуацию в итоге развернули, ввели дополнительные чек-поинты, золото игрокам вернули и локали запилили на сервере, чтобы ничего подобного не повторялось.
Самое время вводить хештег #косякинапроде
В общем, начали тут вспоминать факапы из прошлого, когда решение одной проблемы прибавляло новых, увлеклись и решили поделиться парочкой. Как забанить невиновных игроков, заддосить собственные сервера, ошибиться в одной букве и словить тонны негатива от пользователей — вот это всё, как мы любим.
Проиграл — получи бан
Было время, когда нашу игру War Robots из-за недостатков в архитектуре атаковали читеры. Были утилиты, увеличивающие запас здоровья до космических значений, что делало их практически бессмертными. Таск с читерами мы в итоге закрыли, но не сразу.
Сначала мы хотели решить проблему красиво на техническом уровне: заблокировать возможность изменять на клиенте параметры робота. Сделать нам этого не удалось (потом, конечно, нашли способ). И тогда первым работающим решением стал банхаммер, который вычислял читеров по простой схеме:
- Каждый робот после матча проходил проверку на полученные повреждения.
- Если повреждения, полученные роботом, превышали значение его максимального здоровья — то игрок признавался читером, а его аккаунт блокировался.
Решение было костыльным, но действенным. Проблемы из-за него начались чуть позже, но сначала придется немного рассказать о другом баге и особенности разработки синхронного мобильного PvP.
Когда у игроков сильно шалит интернет-соединение (а в мобильных играх это нормальная ситуация), при обмене данными между клиентом и серверами могут происходить совершенно волшебные вещи. Запросы от клиентов приходят неполными, не в том порядке или с сильной задержкой. В общем, один серверный баг допускал, что при плохом соединении клиент может присылать результаты боя два или даже три раза подряд. Соответственно, игроки могли получать в 2-3 раза больше наград или случайно потратить на ремонт вдвое больше ресурсов.
Эту проблему мы решили довольно быстро: профиль-сервер научился игнорировать лишние результаты боя от одного клиента. После успешного тестирования мы зарелизили новую версию.
Вот тут-то нас и накрыло.
Целую кучу игроков ежедневно начало банить банхаммером, про который мы благополучно забыли, т.к. проблема неубиваемых роботов с бесконечным запасом здоровья была далеко в прошлом. Оказалось, что как только клиент игрока присылал на сервер результаты одного боя в двойном количестве, банхаммер воспринимал это так, что каждый погибший робот был убит дважды — т.е. получил урон, вдвое превосходящий его здоровье. И после каждого боя игроки улетали в бан пачками.
Всех, конечно, разбанили и даже компенсацию выплатили, но ситуация так себе, не позитивная точно.
Как устроить самому себе DDoS
Уже писали про эволюцию нашей инфраструктуры серверов, а сейчас вспомнили один случай того времени.
В конце 2015 года состоялся релиз долгожданной фичи в War Robots — кланов. Когда вышло обновление (а это было поздно вечером), мы открыли шампанское и все было бы хорошо. Но радоваться пришлось недолго — серверам внезапно стало плохо. Оказалось, что мы собственными руками устроили себе DDoS-атаку.
Как? Очень просто. Клиент на экране результатов боя в попытках получить информацию о кланах игроков делал слишком много запросов. И когда сервер отвечал «отстань, ошибка», клиент без какого-либо тайм-аута возвращался к серверу.
Той же ночью мы запилили флажок (шампанское мы при этом закрыть не успели), который контролировался с профиль-сервера — он полностью блокировал работу Hangar Client API. Игрокам, которые уже вступили в кланы, мы этот флажок оставили включенным, то есть у них все работало, потому что их количество было недостаточно, чтобы заDDoSить сервера.
В итоге мы начали корректно обрабатывать ответы сервера в игре, а в случае ошибки — увеличивать таймаут на повтор запроса.
«Бесплатный» рейтинг
Отдельная история — это когда некачественная реализация встречает человеческий фактор. Только теперь никого не банили, а наоборот раздавали рейтинг налево и направо. Короче, как-то ночью наш мониторинг (а мы мониторим вообще всё) зафиксировал слишком быстрый рост рейтинга игроков.
Потом выяснилось, что сама реализация подсчета очков в теории позволяла дублировать данные. Но никто бы на это не обратил бы внимания, если бы дежурный админ из-за опечатки в одной букве случайно рестартнул сервер, который не должен был работать. Именно он и начал удваивать игрокам рейтинги.
Пришлось срочно выпускать фикс и пройтись по базе, чтобы удалить все лишние очки, которые успели начислиться. Чтобы этого не повторилось — на всех серверах мы выпилили старую схему расчета очков и исключили возможность ошибочного запуска сервисов там, где они работать не должны. Надо было так с самого начала сделать, конечно, но было бы слишком скучно.
Бесценный приз
С опечаткой был еще один факап, но куда более серьезный.
Как-то на Хэллоуин мы запускали новую гачу — лотерею. Если кто не знает, гача — это механика получения предмета из нескольких разных случайным образом. В лотерее у игрока был ограниченный видимый набор призов разной ценности. За каждое открытие игрок получал 1 приз, этот приз вынимался из набора, а цена открытия с каждым разом возрастала. Таким образом игрок мог гарантированно скупить все призы лотереи, а счастливчики вынимали самые ценные призы на первых открытиях (и соответственно получали их очень дёшево).
В общем, потом и кровью мы запилили фичу к ивенту, протестили, выложили. Запускаем, обновляем графики… УРА! Они рванули вверх!.. И одновременно на нас обрушиваются тонны негатива в комьюнити, что мы якобы обманываем своих игроков.
Уже через полчаса лотерею пришлось выключить. Да, мы действительно обманывали игроков. Но дело было вовсе не в шансах или призах — дело было в одной букве.
В интерфейсе лотереи указана стоимость текущего открытия (та, которая возрастала с каждым разом), например, PRICE: 100 Gold. Вот как выглядел концепт (обратите внимание, что по задумке на каждой карточке также дополнительно указана цена ее открытия):
А вот как это вышло на проде, когда в результате ряда «улучшений» PRICE (цена за участие в лотерее) внезапно для проектировщика превратилась в PRIZE (приз):
В то же самое время из-за неразберихи перед релизом и плохого чекинга с каждой отдельной карточки пропала цена за открытие, что всё вместе и запутало игроков.
И они рефлекторно жали кнопку, пока не тратили всю харду. Ну а что, «приз» же увеличивается с каждой покупкой. И так было на 18 языках. При этом у нас еще и «локали» были на клиенте, поэтому исправить даже одну букву можно было только через хотфикс.
Ситуацию в итоге развернули, ввели дополнительные чек-поинты, золото игрокам вернули и локали запилили на сервере, чтобы ничего подобного не повторялось.
Самое время вводить хештег #косякинапроде