Методы контроля целостности ресурсной системы в процессе разработки игры

Виталий Чибриков
Системый программист проекта «Аллоды Онлайн» (Аструм Нивал, Mail.ru). Разработчик инструментов для контроля целостности ресурсной системы игры и аддонов к корпоративной системе таскооборота.
Первую игру (ПВО) написал в 7 лет на Basic 2.11 для советского ПК «Вектор 06Ц». За прошедшее с тех пор время закончил МФТИ и немного поработал на отечественную и мировую науку.
В большом геймдеве чуть больше 2 лет.

Содержание

  1. Ресурсная система — понятия и определения
  2. Статистика создания ресурсов в проекте «Аллоды Онлайн»
  3. Методы контроля ошибок на стадии разработки
  4. Система коммит-хуков и ее результативность

Ресурсная система — понятия и определения

Любая компьютерная игра — это набор взаимодействующих объектов.

Объекты, которые составляют виртуальный мир, сами состоят из взаимодействующих частей — ресурсов. Ресурсы — атомы мира, они обладают некоторыми свойствами, но неделимы. Ресурс либо есть, либо его нет.

Для программистов ресурс — объект программного класса, созданный на некотором наборе данных, определяющих свойства ресурса. Рассмотрим взаимосвязь ресурсов, составляющих игровой объект, на примере одного из самых узнаваемых персонажей серии АО — саблезубой белки:

Белка

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

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

Ресурсы в АО представлены файлами. Запуск игры — создание игровых объектов на основе программных классов и сериализованных ресурсов.

Подробнее о том, как устроена ресурсная система в АО, можно посмотреть в докладе Димы Сидоренко. КРИ 2008.

В моем докладе речь пойдет НЕ об устройстве ресурсной системы и НЕ о процессе ее разработки. Я хочу рассказать о процессе наполнения ресурсной системы. Иными словами о том, как помочь разработчикам создавать объекты, состоящие из десятков и сотен ресурсов. И о трудностях, которые при этом можно встретить.

Статистика создания ресурсов в проекте «Аллоды Онлайн»

В первую очередь я хочу обрисовать «масштаб трагедии». Чтобы было понятно, с чем мы столкнулись, и к каким последствиям это могло привести.

При разработке АО над созданием ресурсов работало больше 30 человек в течение 3 лет. По состоянию на март 2010 игра состояла из почти 200 тысяч ресурсов. Между этими ресурсами было более чем 800 тысяч ссылок. Таким образом, на каждый ресурс приходилось в среднем 4 ссылки.

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

Диаграмма

Если бы при разработке мы только добавляли ресурсы, не удаляя их, в ресурсной системе было бы более 300 тысяч ресурсов. Теперь представьте себе процесс удаления более чем 100 тысяч ресурсов, когда на каждый из них приходится по 4 входящие ссылки. Даже если учесть, что треть из этих ссылок ведет на удаляемые ресурсы, после удаления мы получим примерно 250 тысяч невалидных ссылок.

К счастью, ситуация не столь ужасна, и разработчики стараются не делать ошибок. Используя данные, источник которых я поясню в конце доклада, разработчики ошибаются где-то в 10% случаев. С этим допущением у нас получится 25 тысяч невалидных ссылок.

Каждая невалидная ссылка — это потенциальный NullPointerException, приводящий к принудительному выходу из игры. Что особенно актуально, если выход произошел на серверной стороне. Поиск проблемы может занимать от 5 минут до нескольких часов (что во много зависит от прозрачности архитектурных решений, реализованных программистами), и еще 15 минут занимает ее исправление. В этом случае исправление 25 тысяч ошибок займет более 80 тысяч часов. Один человек будет выполнять эту работу 10 тысяч дней.

Типы ошибок

Кроме невалидных ссылок, при разработке могут возникнуть и другие типы ошибок:

  1. Ошибки именования и размещения ресурсов. Примером может быть нарушение соглашения о том, что ресурсы разных типов лежат в разных папках, что имена файлов с ресурсами должны быть нужного формата и не содержать запрещенных символов. Возможно, для качества игры эти ошибки не столь важны, но они могут существенно замедлить процесс разработки. И повысить напряженность в коллективе.
  2. Ошибки в структуре файлов с ресурсами. Например, ошибки xml структуры сериализованного ресурса. Фактически, это та же ошибка, что и отсутствующий ресурс. Файл, на основе которого нельзя создать ресурс — бесполезен.
  3. Ошибки на стадии загрузки ресурсов. Ошибки типизации и ссылок между ресурсами. Представим, например, что дизайнер создал новый ресурс, заполнив нужные поля, а программист в это время переименовал эти поля в коде. В результате мы получим частично не работающий ресурс.
  4. Ошибки значений полей ресурсов и связей между полями в ресурсах. Это могут быть ограничения на значение числовых величин (параметры вещей, цены, величины опыта за квест, недопустимые символы в описании вещей, и.т.д.). Например, разработчики механики игры решили, что оружие ближнего действия бьет не дальше чем на 1 метр, а дизайнер прописал для меча дальность 2 метра. Результат может быть странным и сильно зависит от действий программиста, которого могли вообще не посвятить в тонкости ограничения.
  5. Ошибки в полностью загруженной ресурсной системе. Например, ошибки связей между ресурсами, неправильное положение виртуальных предметов относительно друг друга.

Общее число типов проверок за 2 последних года разработки АО выросло с 50 до 320.

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

Еще раз повторю, технические ошибки чаще всего приводят к:

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

Вы играли в Gothic 3? Я начал играть в нее, как раз когда приступил к этой работе. Все выше перечисленные признаки технических ошибок в ней можно обнаружить за первые 5 часов игры.

Еще немного статистики: в среднем ресурс, доживший до релиза, был изменен 7 раз. Общее количество изменений над ресурсами проекта — почти 1.5 миллиона.

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

По статистике 23% коммитов содержат простую (не критическую) ошибку. В результате, мы получаем 16 тысяч коммитов данных с ошибками.

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

Методы контроля ошибок на стадии разработки

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

Методы контроля ресурсных ошибок:

  1. Контроль правильности ресурса в редакторе. Самый очевидный вариант — сделать так, чтобы при работе с ресурсами нельзя было допустить ошибок. Плюсы: работают на стороне пользователя, работают быстро, ошибки могут быть обработаны тут же, как только они появились. Минусы: учитывает только локальные изменения, не позволяет проводить комплексные проверки (например, что какое-то значение должно быть единственным на всю ресурсную систему), иногда удобнее править ресурсы не в редакторе.

    Editor

  2. Контроль целостности ресурсной системы при старте игры (на старте сервера и при работе клиента). Пусть при старте игра проверяет свое состояние и пишет лог ошибок. Плюсы: проверяем именно то, что увидит конечный пользователь. Можно проводить комплексные проверки. Относительно быстро показывает проблемы. Минусы: работает на компьютере разработчика, нельзя проводить дополнительные проверки (время слишком дорого), учитывает только локальные изменения, вывод ошибок не в самом удобном для разбора формате.

    ServerLogs

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

    TeamCity

  4. Коммит-хуки. Сделаем так, чтобы ошибку просто нельзя было добавить в общий репозиторий. Если разработка идет мелкими изменениями, можно проверять каждое во время коммита изменений. Разработчик создал новую сущность и отправляет ее на коммит. Мы перехватываем его обращение, проверяем, и если оно содержит ошибки — отменяем коммит и возвращаем список ошибок. Плюсы: всегда работает с последней версией, проверка сразу после изменений, можно проверить все что угодно. Минусы: жесткие требования на производительность и качество работы проверяющей программы.

Hooks

О хуках я расскажу подробнее, а пока для удобства — сводная таблица методов:

Своевременность Объем проверок Изменения других разработчиков Удобство восприятия Требовательность к производительности
Редактор + - - + + -
Логи на старте + + - + - - -
Билдер - + + + + -
Коммит-хуки + + + + -

Применяйте все эти методы. И старайтесь сделать так, чтобы они все использовали одни и те же правила.

Система коммит-хуков и ее результативность

При работе над АО мы использовали систему контроля версий — subversion. Каждый наш ресурс — это файл в svn. Таким образом, коммит новых данных от разработчика - это коммит текстовых файлов, содержащих сериализованные ресурсы.

Технические подробности: Репозиторий проекта в SVN содержит шаблоны коммит-хуков — скрипты, которые svn выполняет во время коммита. Они находятся в директории hooks и называются pre-commit.tmpl и post-commit.tmpl. Если переименовать их в pre-commit и post-commit и дать права на исполнение (755), svn перед каждой операцией коммита изменений в репозиторий будет запускать скрипт pre-commit, а при успешном завершении коммита — post-commit. Если pre-commit после выполнения вернет значение отличное от 0, коммит разработчика не пройдет и ему будет возвращен лог ошибок этого скрипта.

mv pre-commit.tmpl pre-commit

vim pre-commit (svn передает в скрипт два аргумента, используя их, можно получить полную информацию о коммите)

chmod 755 pre-commit

Создание нашей системы коммит хуков проходило в несколько стадий:

Простые проверки: при коммите от разработчика приходят изменения ресурсов, и мы можем проверить правильность именования ресурсов, правильность их размещений, правильность заполнения полей, ограничения на их значения. Для создания такого типа проверок достаточно написать скриптовые проверки и запускать их из pre-commit. Проверка проходит очень быстро, но мы ограничены только текущими изменениями.

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

Работа с метаинформацией: создаем процесс-демон, в котором храним всевозможные данные о ресурсах. Например, кэш входящих и исходящих ссылок, значения полей, etc. Любые изменения, которые коммитит разработчик, отправляем демону. Демон анализирует изменения, и при наличии ошибок отправляет их обратно разработчику. При каждом прошедшем коммите меняем метаинформацию так, чтобы она отражала текущее состояние ресурсной системы. Тогда следующий коммит будет проверен с учетом прошедшего.

Звучит здорово.

Проблемы, с которыми мы встретились:

  1. Производительность. Если коммит идет больше 5 минут, разработчик либо часто ходит пить кофе, либо копит изменения вместо того, чтобы добавлять их, когда они готовы, еще сильнее затягивает коммит, получает необходимость объединять свои изменения с изменениями других пользователей (мержить данные) и 100 сообщений об ошибках в ресурсах, о которых он уже забыл. Чтобы избежать такой ситуации, мы решили, что коммит не должен идти больше минуты.
  2. Полнота проверок. Если мы сильно ограничены во времени проверок, как достичь ее объемности? Во-первых, производительность «железа». Во-вторых, интеграция с ресурсной системой игрового сервера. Для второй и третьей стадии разработки коммит-хуков нам нужно загружать ресурс для получения значения его полей и ссылок. Мы не стали писать новый загрузчик ресурсов, а использовали модуль загрузки ресурсов сервера игры. Таким образом, во время коммита ресурса мы загружаем его по точно таким же правилам, по каким его загружает сервер во время старта.
  3. Стабильность. Любые ошибки и простои в системе хуков прямо отражаются на производительности (и моральном духе) разработчиков. Представьте, что вы пытаетесь добавить в систему результаты недельной работы, а вам не дают это сделать, и притом не справедливо. Развивать систему, которая уже применяется в условиях жестких требований к производительности и качеству работы, и, кроме того, зависит от модуля другой, тоже постоянно изменяемой и дорабатываемой, программы (ресурсная система игрового сервера) без ошибок не возможно. Для того чтобы в таких условиях избежать конфликтов с другими разработчиками, система коммит-хуков должна быть максимально гибкой в настройке. У вас должна быть возможность в любой момент выключить любое правило проверки коммита. В нашем случае на «горячем» демоне мы всегда можем: отключить систему целиком, отключить любую из стадий проверок (например, отключить проверки на демоне, а проверки над файловой системой оставить), отключить любое из 320 правил проверки по имени ошибки, оставив остальные.
  4. Конфликт интересов. Казалось бы, такая система контроля ошибок полезна всем разработчикам. Она своевременно оповещает о проблемах, позволяет сэкономить время. Однако, на практике это не совсем так.
    Представьте, что вам как разработчику руководитель утвердил план работы на неделю. Вы сделали его ровно за неделю и пытаетесь «залить» свои изменения в общий репозиторий. И в этот момент «злые» коммит-хуки не дают вам этого делать и выводят большой список ошибок, которые они нашли в вашей работе. Вы видите, что к установленному сроку сдачи работы исправить вы эти ошибки не успеете. Ваши чувства? Ваши действия? Может быть, можно уговорить парня, который пишет хуки выключить их? Попытка. Нет, не получилось его уговорить. Но вы слышали, что ваш друг в подобной ситуации как-то обошел проверки и залил данные с ошибками и успел все сдать во время…
    Если вы пишите систему хуков, не надейтесь на сотрудничество со стороны ваших непосредственных пользователей. Скорее всего, вы последним узнаете о «дыре» в вашей системе защиты. Бороться с описанной выше ситуацией можно, и мы достигли больших успехов в этом за 3 года ее использования. Повышайте уровень ответственности разработчиков. Повышайте степень посвященности руководителей в устройство и особенности вашей системы. Собирайте статистику о ее полезности. Ни в коем случае не создавайте способов обхода системы. Права на выключение и модификацию правил должны быть только у 2 человек. И это должны быть стрессоустойчивые люди.

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

Результаты по основным типам ошибок:

  1. Удаление ресурса, на который стоит ссылка — 3%
  2. Добавление ресурса со ссылками на несуществующие ресурсы — 5%
  3. Остальные типы ошибок — 23%
  4. Коммиты без ошибок — 69%

TeamCity

Производительность: 320 проверок, время работы — примерно 30 секунд.

Благодарности

Большое участие в разработке системы контроля принимали:

  • Тимур Бухараев — старший программист команды сервера
  • Дмитрий Сидоренко — разработчик ресурсной системы сервера
  • Петр Иванов — QA команды сервера
  • Михаил Мельников — старший программист инструментария

[13.07.2010]

Copyright © 2017 ООО "ДТФ.РУ". Все права защищены.

Воспроизведение материалов или их частей в любом виде и форме без письменного согласия запрещено.

Замечания и предложения отправляйте через форму обратной связи.

Пользовательское соглашение