Тест в MMORPG для Telegram неделю проверял вещи, которых в игре уже не было: как зелёная проверка смотрит в прошлое

Я делаю EclipseFall, MMORPG внутри Telegram, которую не нужно устанавливать. В прошлом лонге я рассказывал, как бот больше двух месяцев молча стирал письма игроков, и там виновата была одна строка кода. Здесь виноваты три теста, которые всё это время были зелёными.

Технический разбор: почему зелёный тест ничего не доказал
Технический разбор: почему зелёный тест ничего не доказал

Как в игре хранятся вещи

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

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

Легендарки, которых не было

Лавка продаёт за золото только вещи до 24-го уровня, а лучшее снаряжение последнего уровня добывается в бою. Замок лавки проверял это на легендарках: они есть в каталоге, и все лежат выше границы.

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

Латы для новичка с босса последнего уровня

Тот же аудит вскрыл вторую историю. Девятнадцать вещей первого набора остались на старой сетке уровней от 1 до 15, хотя боссы уже переехали на сетку до 30. Полый титан, босс 28-го уровня, ронял Латы стража пятого: в конце кампании игрок получал вещь для новичка.

Латы стража: вещь пятого уровня, которую ронял босс двадцать восьмого
Латы стража: вещь пятого уровня, которую ронял босс двадцать восьмого

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

Сводка, которая печатала прошлое

Сводку чисел проекта я не пишу руками: её собирает и сверяет третий замок. Вечером второго августа я вычитывал документацию и нашёл в сводке границу лавки 348 на 92: столько вещей можно купить и столько нельзя. В живой базе было 346 на 94.

Две волны правок лута сдвинули уровни у 28 вещей, и две из них перешли через 24-й уровень. Замок сводки читал только вставки. В тот же день я чинил эту ошибку в двух соседних замках, записал правило и пропустил третий.

Полый титан, с которого падали вещи для новичков
Полый титан, с которого падали вещи для новичков

Правило и где оно стоит

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

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

Что я из этого вынес

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

Игра живёт внутри Telegram, ставить ничего не нужно: открыть EclipseFall. Про такие разборы я пишу в девлоге: t.me/eclipsefall_game.