Введение
«В моё время игры были лучше. Они были интереснее, потому что геймплей считался более важным, чем графика».
— Геймеры, рождённые в любом десятилетии
Каким бы ни было «ваше время», думаю, вы в какой-то степени согласны с этим мнением. Для меня это был период с середины 80-х до середины 90-х, когда я проводил бесчисленные часы за Sir Fred, Atic Atac, Airborne Ranger, Monkey Island, Twilight: 2000, Stunts, Gunship 2000, Twinsen’s Adventure, Dark Sun, Challenge for Ancient Empires, серией the X-Wing и очень многими другими играми.
Иногда мы испытываем приступы ностальгии и нам хочется сыграть в одну из тех игр снова. В этом случае у нас есть на выбор несколько вариантов.
Сыграть в remastered-версию. Некоторые игры настолько потрясающи и собрали настолько преданную базу фанатов, что выпускается официальное «новое издание». Это точно такая же игра, но с современной графикой. Отличным примером таких игр может быть замечательная Monkey Island Special Edition.
Это идеальный вариант. К сожалению, переделывают только очень немногие игры, причиной тому являются затраты, утерянный исходный код оригинала или даже недостаточный интерес в случае относительно малоизвестных игр.
К похожей категории относятся игры, исходный код которых открыт, например шутеры от первого лица компании id. Существуют проекты, создающие новые графические ресурсы для этих игр, но они редки, да и немногие разработчики открывают исходный код своих игр.
Сыграть в ремейк. Некоторые игры настолько потрясающи и собрали настолько преданную базу фанатов, что кто-нибудь решает переписать игру с нуля, обычно без малейшей поддержки авторов оригинала. Если вам удастся найти хороший ремейк, то вы получаете почти оригинальную игру, но с современной графикой.
Это хорошая альтернатива, но, опять же, не у многих игр есть ремейки. Так получилось потому, что ремейки обычно создаются фанатами, а задача невероятно сложна — настолько же сложна, как создание игры заново, и к этому добавляется сложность как можно точного воспроизведения оригинального геймплея. Единственный способ достичь высокой степени точности — дизассемблировать код оригинала и воссоздать его логику.
Запустить эмулятор. Всегда можно воспользоваться DOSBox и специальными решениями для некоторых игр, например ScummVM. Это хорошо работает, но будем честны, графика большинства игр не похожа на вино, которое со временем становится лучше. Тем не менее, вы всё-таки играете в оригинальную игру.
Итог
Если у игры, в которую вы хотите сыграть, есть remastered-версия, то это отлично! Но для подавляющего большинства игр, у которых нет ремастеров, остаётся всего два варианта: использовать эмулятор (он широко доступен, обеспечивает идеальный геймплей и устаревшую графику) или надеяться на то, что кто-то создаст ремейк (относительно редко, неидеальнй геймплей, современная графика).
Новый подход
Но что, если мы сможем запустить неизменный двоичный код, только с улучшенной графикой?
Предположим, что вы запустили игру в эмуляторе. У вас нет исходного кода, но вы можете быть уверены, что где-то в двоичном коде сокрыт метод «отрисовать спрайт». Или метод «вывести символ». Или метод «воспроизвести звуковой эффект». Или метод «отрендерить полигон».
Что, если можно будет использовать интегрированный с эмулятором отладчик/дизассемблер для нахождения входных точек этих методов? Что, если мы выясним, какие регистры какие параметры содержат, или их порядок в стеке?
Что, если мы можем запрограммировать эмулятор вызывать произвольный метод C++, когда эти входные точки должны быть выполнены, извлечь в этот момент состояние регистров и выполнить собственный код отрисовки спрайтов? Или код рендеринга шрифта TrueType? Или код воспроизведения MP3? Или несколько вызовов OpenGL?
Если нам удастся заменить все эти методы реализациями на C++, то в результате мы получим игру, в точности следующую логике оригинала, но выглядящую современно. Мы получим эмулированный ремейк с точно воспроизведённым геймплеем, который можно будет постепенно дополнять, и для этого достаточно очень поверхностного понимания дизассемблерованного кода.
Я немного исследовал вопрос и оказалось, что это достаточно свежая идея. Почему никто раньше не пробовал сделать такого?
Будет ли это работать?
Проверка концепции
Я решил проверить эту безумную идею. Я написал эмулятор 8086 + CGA со всего 44 реализованными опкодами, которых едва хватает для запуска экрана заставки игры Goody:
Я написал два инструмента — дизассемблер и средство запуска с похожим на gdb интерфейсом, позволяющие пошагово выполнять код, устанавливать контрольные точки и так далее.
Как нам найти интересные функции без полного дизассемблирования? Я использовал множество способов — установка контрольных точек и изучение регистров, выполнение кода по небольшим фрагментам, случайное заполнение содержимого симулируемой видеопамяти, чтобы посмотреть, что будет отрисовываться, патчинг кода для пропуска некоторых вызовов, чтобы посмотреть, что перестало работать, и изучение дизассемблированного кода, чтобы добавить полезные для меня комментарии.
Благодаря этим техникам мне удалось найти несколько интересных «функций»:
Я добавил перехватчик C++, чтобы выполнять собственную отрисовку в отдельном окне:
Я добавил немного черновой графики, скрестил пальцы, и…
…и узрите, у меня есть «ремейк»! Посмотрите, «старое» окно выполняется рядом с «новым» окном; это не статичное изображение, а новая графика, управляемая оригинальным кодом X86!
Посмотрите сами
Демо целиком (эмулятор x86 / дизассемблер / отладчик, перехватчики Goody и черновая графика) выложено на GitHub. Оно работает в Linux и Mac; требуются SDL2 и компилятор C++0x.
Исходный код выпущен под лицензией Whatever/Credit: можете делать с кодом всё, что угодно; если создадите что-то крутое, то я буду признателен за указание моего авторства. Если что, код даже не альфа-качества — это качество «проверка концепции/работает на моей машине».
В репозитории содержится оригинальная игра (goody.com
) — я получил неофициальное благословение одного из авторов оригинала Гонзо Суареса на её распространение, к тому же её легко найти на любом сайте с устаревшим ПО; если кто-то будет против, я удалю игру из репозитория.
Я набросал графику, воспользовавшись своими ужасными навыками работы в Gimp и ресурсами в общественном достоянии или с лицензией Creative Commons с OpenGameArt: 1, 2, 3, 4, 5. Если читающий эту статью художник захочет поделиться оригинальной графикой для этого демо, я буду очень благодарен.
Ответы на ожидаемые вопросы
В: Вы ведь в курсе, что существует отличный ремейк Goody?
О: Да. Но я выбрал Goody для проверки концепции, потому что эта игра нравилась мне больше всех из эры CGA, потому что она содержится в файле COM, то есть не ей не требуется загрузчик EXE, и потому что она очевидно основана на тайлах, то есть я считал, что с ней будет достаточно просто работать.
В: Почему вы не воспользовались любыми доступными эмуляторами x86 или даже DOSBox?
О: Потому что написание эмулятора x86 — интересная задача. После фазы проверки концепции я намереваюсь полностью приспособить для этого DOSBox.
Мысли в заключение
Масштабируется ли система?
Можно ли использовать эти техники для более сложных игр? Я не вижу препятствий. Можно всегда начать с DOSBox и заменить, допустим, звук. Это уже будет началом частичного ремейка.
Другой вопрос заключается в том, где провести линию — на каком уровне абстракции добавлять перехватчики. В какой-то мере, можно создать в DOSBox перехватчики на самом низком уровне — на отрисовке отдельных пикселей. Моя проверка концепции выполняет перехват на уровне «отрисовки тайла» и «отрисовки глифа». Но возьмём, например, шрифты. Отрисовка глиф за глифом вполне подходит для таких аспектов, как деньги и счётчики жизней, но для текстов инструкций на главном экране можно придумать что-то получше, например, перехватчик на уровне «отрисовки строки», и использовать FreeType для получения пропорционального шрифта с красивым кернингом.
Похожие рассуждения применимы и к 3D-играм с программным рендерингом типа X-Wing или Stunts. Может быть, удастся перехватить функцию «отрендерить треугольник», и в таком случае очень низкополигональные модели будут рендериться в видеопроцессоре, или перехватить функцию «отрендерить модель» и использовать новые 3D-модели. Или можно взять оригинальный Wing Commander, в котором даже не используются 3D-модели — вместо них там битовые изображения кораблей повышенного разрешения, и на самом деле рендерить 3D-корабли.
В качестве ещё одного примера можно привести звук. Можно перехватывать программируемый таймер и порты ввода-вывода динамика, чтобы генерировать соответствующие волны на лету (предполагаю, что так и делает DOSBox), или перехватить функцию «воспроизвести звуковой эффект» и воспроизводить вместо звуков файлы MP3.
А как насчёт частоты кадров? Анимация смерти Гуди занимает два кадра и длится около секунды. Даже с красивыми ресурсами анимация всё равно будет выглядеть рваной. Думаю, что решением проблем такого типа станет более умная обработка рендеринга состояния — в идеале можно было бы написать полностью новый рендерер на основании считываемого из памяти состояния игры без необходимости непосредственно перехватывать любые методы отрисовки.
Применимость за рамками игр
Эту идею можно применить не только в играх. В некоторых системах используется очень старое ПО, потому что на протяжении долгих лет было добавлено так много подробностей бизнес-логики, что невозможно или непрактично переписывать такие системы с нуля. Но благодаря этим техникам можно будет выполнять логику без изменений и заменить код ввода/вывода/баз данных чем-то более современным.
Законность
Хотя это не юридический совет, потому что я не юрист, я не могу придумать никаких причин, по которой сама техника может быть незаконной, потому что в комплекте «ремейком» не поставляется оригинальные двоичные данные игры (только если игра сама не распространяется бесплатно).
С графикой всё сложнее. В ремейке не может быть и оригинальных ресурсов; художники и музыканты должны будут переделывать их с нуля. Но даже тогда я не уверен, будет ли создание, скажем, 3D-моделей X-Wing или изображения Дарта Вейдера законным. Возможно, они могут считаться фан-артом?
Дополнительное чтение
Если вам нравится реверс-инжиниринг, старые игры или то и другое, то вам стоит изучить веб-сайт Фабьена Санглара.
Подведём итог
Проверка концепции подтверждает жизнеспособность идеи; в конце концов, оказалось, что она не такая уж и безумная. Ремейки можно делать подключением современного кода рендеринга/звука/сетевой передачи данных в эмулятор/виртуальную машину, в которых запущена оригинальная игра.
Изменит ли это революционным образом способ создания ремейков? Я сильно на это надеюсь! С радостью поиграл бы в игры прошлого с современной графикой и оригинальным геймплеем.
Автор: PatientZero