Горящие дома и жопы игроков в Ultima Online: как чинили баг с дюпом предметов
В честь 25-летия игры разработчики поделились историей одного весьма интересного бага — клонирования предметов.
На годовщину Ultima Online разработчики рассказали про занятный случай c дюпом предметов. Разобрал кратко в Твиттере. Самая вишенка в истории в том, что вместо какого-то фикса нормального, они помечали такие предметы, а потом после выкатки обновления разом их все удалили 😈
Баг проявлялся на границах зон. Если сократить, то суть бага: один игрок бросат сундук в лагающем участке (между зонами), а потом другой игрок пытается подобрать его одновременно с тем, как бросивший игрок пытается его же поднять.
В итоге у каждого оказывалась копия сундука.
В UO нету типичных зон с подгрузками, вместо них разработчики изобрели прямоугольные бесшовные «подкарты» с методом, позволяющим пройти от одной стороны к другой, в то время как вещи на другой стороне всё ещё видны и обновлялись в режиме реального времени.
Каждый игровой сервер фактически был разделён на районы, и был код, который обрабатывал передачу состояния игры, условий объектов и событий с одной стороны границы на другой. Но пересечение этих границ в качестве игрока иногда заметно тормозило.
Эти районы, по сути, копировали вашего игрового персонажа и отправляли друг другу в пакете, содержащем всю вашу информацию. Когда игрок пересекал границу, старая копия игрока на исходной стороне уничтожалась.
У игры не было привычной БД. Использовали дампы памяти 🤔
- Каждый шард выполнял отключение/резервное копирование в определённое время.
- Полное игровое состояние каждого ареасерверы сбрасывалось из памяти в большой двоичный файл.
- Как только серверы завершали резервное копирование, они отключились, перезапускались и переходили в режим ожидания, в то время как «игровой сервер» делал то же самое.
- Игровой сервер выключался, перезапускался, а затем инструктировал каждый ареасервер загрузить свою последнюю заведомо исправную резервную копию.
- Каждый ареасервер загружал бинарную резервную копию и воссоздавал ранее сохранённое состояние игры; он также выполнял любые триггеры/хуки.
- Куча других вещей, включая появление новых мобов или ежедневных редких предметов.
- Ареасерверы инорфмировали, что всё в порядке, и сообщали игровому серверу, а он повторно объявлял о себе авторизационным серверам, что он доступен для игры.
П.2 был самой большой проблемой. Найти дубли в дампе нереально.
Но п.5 натолкнул разработчиков на идейку: на старте сервака помечать наиболее ценные предметы и сохранять их в глобальный хеш-реестр.
В общем, на ценных предметах висела уникальная метка. Когда по предмету проводилась логика какая-то по копированию, то на копии оставалась метка и можно было свериться с глобальным реестром. Если уже был предмет с такой меткой, то копия потом помечалась тегом «I AM DUPED».
За несколько недель скопилось много таких предметов и стали решать, что же делать.
Но когда начали общаться с директором и QA/КМ'ами, то те сразу дали понять, что дропать все дубли не самая лучшая идея, т. к. вызовет гнев очень большого числа игроков.
В итоге:
- Нашли багоюзеров и их хранилища
- Нашли всех причастных в «кольце дублирования»
- Написал скрипт
- Служба поддержки массово забанила мошенников
- Остановили соединение gameserv/loginserv с теми же серверами, к каждому жилищу, прикрепили скрипт
Сам скрипт:
- Удалить дом и его содержимое. Рекурсивно.
- Заполнить область чёрным щебнем.
- Создать кучу вечных огненных полей среди щебня.
- В центре поставить соломенный манекен с надписью «An Effigy of a Traitor».
Мир игры вспыхнул, как и жопы игроков 😈
Поддержку завалили письмами.
С технической точки зрения, даже с отсутствием БД, странно, что не сделали какие-то программные транзакции с двухфазным коммитом, чтобы избежать клонирования в этих зонах.