Несколько дней назад, 15 мая, в ScummVM, известный кроссплатформенный набор игровых движков для point-and-click adventure, была добавлена ветка кода с движком, который поддерживает классику квестового жанра, игру The Neverhood.
Это был один из самых захватывающих и длинных проектов в ScummVM. Разговоры об этом шедевре продолжались в течение нескольких лет, и на форумах регулярно просили добавить поддержку этой игры. Два года потребовалось на разработку движка, и я хочу коротко рассказать, как это происходило.
Стоит заметить, что добавление игры в ScummVM, это совсем не простая задача. На сегодня примерно для половины движков нам удалось получить исходники от авторов, но даже в этих случаях код всегда нужно переписывать. Так, в последнее время в проект поступает довольно много игр, написанных изначально на Паскале и Ассемблере, и чтобы их добавить, всё нужно транслировать в С++. Другая же половина движков получилась путём хардкорного реверс инжиниринга (по-другому и не скажешь), когда на вооружение берётся IDA, и мы потихоньку начинаем размечать оригинальный движок названиями функций, переменными и комментариями, слой за слоем разбираясь в логике его работы.
Именно второй подход и был вынужденно использован с The Neverhood. Попытки связаться с авторами особо не увенчались успехом, руки чесались, и в июне 2011 года проекту был дан старт.
Хроники проекта
Исходные данные:
* 800 кб бинарного кода
* Оригинал на С++
* 7,2 тысячи функций
* 340 виртуальных классов
Через два года работы двух человек получен результат:
* 36 тысяч строк кода
* 2 тысячи методов
* 320 классов
Первый коммит был прост:
Author: johndoe Date: Wed Jun 22 22:58:51 2011 +0000 NEVERHOOD: First code with basic detection, nothing else so far
Этот скелет по сути стандартен, и разработка каждого движка обычно с него и начинается. О, сколько попыток отреверсить игру для ScummVM на этом и заканчивалось! Но не в этот раз, не в этот раз. Уже через два дня был написан код для доступа внутрь BLB архивов, а спустя ещё два дня декодируется графика и начата работа над Module1500, вступлением к игре.
Нас не остановило то, что игра является хардкодом. БОльшая часть движков для приключенческих игр, поддерживаемых ScummVM, являют собой виртуальные машины (об этом можно писать отдельный пост), и их структура является не слишком сложной. Иногда же оригинальные разработчики пишут скрипты игры прямо на языке программирования, что увеличивает объём и сложность работы по реверсингу в десятки раз. Особо сложной является работа с C++. Компиляторы этого языка часто используют продвинутые оптимизации, также виртуальные классы трансилруются в ассемблер как неявные вызовы, что доставляет ещё больше головной боли. Также не упрощает работу тот факт, что IDA и Hex-Rays ещё не умеют толком работать с плюсами и приходится использовать много костылей.
Тем не менее, 4 июля заработала начальная заставка игры. Хотя она из себя представляет набор роликов в формате Smacker, однако даже для этого было необходимо реализовать систему сообщений, обновление экрана, обработку клавиатуры, затемнение палитры, переход между сценами, в общем, написать почти 3 тысячи строк кода. Через неделю была закончена первая сцена, и начата работа над второй сценой игры, Scene1002.
Далее сцены добавлялись одна за другой, каждую неделю. К слову, их в игре всего 71.
К середине сентября 2011 года, когда примерно половина сцен были реализованы, стартовала работа по рефакторингу. Оригинальный код, как и ожидаемо, содержал довольно много лапши. Стандарты же ScummVM довольно высоки, и для повышения качества кода мы всегда работаем над улучшением структуры, а часто и архитектуры оригинальных движков. Neverhood тут не исключение, были добавлены генераторы объектов, обёртки и многие функции были слиты вместе.
Работа практически не велась с января по июль 2012 года, а в августе были добавлены ещё дюжина сцен и начата работа над звуком. В Neverhood звук закодирован своим, самописным RLE кодировщиком, и требуется одновременное воспроизведение до трёх звуков помимо фоновой музыки. К началу октября, соответствующие вызовы добавлены во все сцены игры, и мы начали внутреннее альфа-тестирование.
После второй волны рефакторинга, когда была выкинута значительная часть дублирующегося кода, и движок сильно «похудел», началась подготовка ветки к слиянию с основным кодом ScummVM. Для этого было необходимо добавить меню, финальные титры, комнату Hall of Fame, а также запись и восстановление состояния игры.
21 января 2013 года, через полтора года разработки, до нас внезапно дошло, что оригинального героя таки зовут Klaymen, а не Klayman, как это было бы логично в соотетствии с грамматикой английского языка, и за этим озарением последовало массовое переимнование переменных и классов в коде.
Ещё немного рефакторинга, исправления багов, и 5 мая 2013 года был сделан Pull Request в основную ветку ScummVM.
Вот она, история проекта.
Коротко о будущем
Работа над движком далеко не завершена. Теперь необходимо убедиться, что игра работает на всех поддерживаемых платформах, в частности, на big-endian ARM.
Также пока, к сожалению, русские версии игры не поддерживаются, так как наши переводчики, как это часто бывает, слегка поменяли форматы там и сям, и движок в ScummVM падает после начальной заставки. Мы как раз сейчас над этим работаем. Возможно, что мы поработаем и над добавлением поддержки PSX версии игры.
Необходимо ещё сделать некоторую работу по рефакторингу, в частности, убрать глобальные конструкторы, которые суть зло. И, наконец, объявить о публичном бетта-тестировании.
Ссылки:
Сайт проекта ScummVM, для того, чтобы запустить The Neverhood, нужен daily build версии 1.7.0
Исходный код движка
Как запустить игру
Игру нужно скопировать с оригинального диска, нажать в ScummVM кнопку Add Game, указать путь, куда скопирована игра, и далее игра появится в списке (пока работает только английская версия и демо). Далее, двойной щелчок по названию игры, игра запустится.
Демо можно скачать отсюда. Купить полную игру можно на eBay, Amazon, также ещё попадаются на полках наших магазинов русификации.