Сказ о том, как я дизассемблировал Supaplex и почти написал клон с 3D графикой

    Картинка для привлечения внимания

    Я думаю, большинство людей, кто застал времена DOS и ранних Windows 9x, играли или хотя-бы слышали о такой замечательной игре, как Supaplex. Лично для меня — это игра-легенда. Я до сих пор с трепетом вспоминаю долгие зимние вечера, проведённые в попытке пройти какой-нибудь сложный уровень на стареньком 286-м.

    Так сложилось, что я программист. И не просто программист, а программист компьютерных игр. Так что, где-то в 2008 году я занялся написанием движка-«убийцы крузиса» (или что там было круто на тот момент, я уже не помню). Примерно через год меня настигло прозрение, что моих человеко-часов на проект уровня Unreal Engine не хватит. И я решил сделать легкую, «казуальную», версию движка и написать на ней пару простеньких игрушек.

    Мой выбор пал на клон Supaplex. Правда, на тот момент уже существовало несколько клонов под Windows и другие платформы, поэтому просто писать все с нуля было неинтересно. Зато в мою голову заползла крамольная мысль: а что, если дизассемблировать оригинальный Supaplex и сделать игру с логикой, «идентичной натуральной». Такая задача казалась крайне заманчивой, и я взялся за её осуществление. Я заказал 3D-модельки у одного хорошего знакомого фрилансера и, пока он был занят моделлингом, я приступил к изучению пациента. Сразу предупреждаю, что я уже не помню многих деталей и могу что-то забыть или приврать, всё-таки это было довольно давно.

    Дизассемблирование


    Немного забегая вперёд отмечу, что всё, что у меня осталось по этому проекту (скрипты дизассемблера, исходники прототипа) я выложил на гитхаб. Ссылку ищите в конце статьи.

    Началось всё с того, что исполняемый файл то ли запакован, то ли зашифрован. После безуспешного поиска чего-нибудь, что сможет его распаковать (хотя я не особо старательно искал), было принято решение писать свой распаковщик. Наверное, велосипедостроение у меня в крови. Я уже не помню досконально, как он работал, но идея заключалась в эмуляции инструкций CPU до точки, когда программа успешно запустилась, после чего содержимое памяти сохранялось на диск в виде EXE-файла. Этот замечательный декомпрессор можно найти в материалах к статье.

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

    По мере дизассемблирования я начал составлять C++-псевдокод, пытаясь понять что делает тот или иной участок ассемблерного кода. С самыми сложными и непонятными блоками я разбирался с помощью самописного отладчика, который отслеживал попадание в те или иные участки кода Supaplex в процессе игры и оповещал меня об этом. Таким способом я проверял гипотезы о предназначении некоторых участков. На более позднем этапе я начал переписывать участки кода на С++, продолжая обращаться к другим участкам из оригинала, что позволило проверить корректность дизассемблирования каждого блока.

    Результатом всего этого стал почти чистый C++ код игровой логики, с небольшим вкраплением goto и переменных со странными именами типа byte_403C3. Его вы тоже найдете в материалах к статье.

    3D-версия


    Выглядит прототип вот так:

    Скриншот

    Немного про движок. Код самого движка довольно объёмный, хотя он прост и нефункционален до безобразия. Оригинальный, «большой», движок писался с использованием библиотеки Qt. Потом по какой-то причине я решил от нее отказаться (не помню уже деталей) и написал собственную замену классов Qt.

    Для отрисовки используется старый OpenGL с расширениями. В движке есть интересная деталь: если я правильно помню, в то время OpenGL 2.0 и GLSL были не очень распространены (как минимум, мой ноутбук с видеокартой Intel их не умел). Я взял из Mesa (open-source реализация OpenGL) компилятор из GLSL в ассемблерные шейдеры. В итоге, шейдеры пишутся на GLSL, но движок работает даже на очень старом железе.

    В игре нет меню или хоть какого-то пользовательского интерфейса. В ресурсах лежит оригинальный levels.dat от Supaplex. По умолчанию игра запускается на первом уровне, но если создать в директории с бинарником файл level.cfg и написать там номер уровня (от 1 до 111), то игра запустится на выбранном уровне. Управление такое же, как и в оригинале — стрелки перемещают персонажа (кстати, его зовут Murphy) в выбранном направлении, пробел+стрелка съедает объект в указанном направлении без перемещения персонажа, длительное удержание пробела устанавливает красный диск (если они у вас есть, конечно). Нажатие Esc приводит к моментальному суициду (привет, Роскомнадзор!).

    Исходники


    На момент разработки я пользовался SVN репозиторием. Я перезалил всё в Git и немножко «причесал» код, чтобы он собирался не только на Windows, но и на Linux с OSX. Все доступно на гитхабе: github.com/zapolnov/superplex3d_prototype, собирается CMake'ом. Там же есть бинарники для особо нетерпеливых.

    Я пока не планирую развивать этот проект. Весь свой код я перевожу в публичное достояние, весь арт доступен под лицензией CС Attribution-NonCommercial-ShareAlike. Звуки и музыка скачаны с этих ваших Интернетов и их лицензия мне неизвестна.

    По очевидным причинам, дизассемблированный код игровой логики (supaplex_game.cpp, а также его версии в директории disassembly) предоставляется исключительно в ознакомительных целях, после прочтения его необходимо сжечь или съесть, а также забыть всё, что вы там увидели.

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 34

      +2
      Откройте для себя Rocks`n`Diamonds и не занимайтесь дизассемблированием того что есть в исходниках.
        +5
        Спасибо, я его видел. Однако это все-таки ремейк, а на тот момент было очень интересно покопаться в оригинале и изучить оригинальную логику.
          +9
          Вообще-то, если уж на то пошло — Supaplex — это тоже клон, причем из один из последних.

          Оригинал — Boulder Dash — вышел в 1984. Потом пошла волна лицензированных продуктов (Boulder Dash 2, 3 и еще тыщи всяких дополнений). Потом пошла волна клонов первого поколения (всякие там Rockford, Skulldiggery, Rockmoor) в районе ~1987-1988, потом опять затишье, потом — клоны второго поколения (в том числе Supaplex) в районе ~1991-1992. Потом произошла дикая смена платформ, пришествие DOS / PC, умирание всего остального (Atari — сразу, Amiga — долго и мучительно) и т.д. и т.п. — и об этих играх незаслуженно забыли.

          Потом было долгое молчание — по сути лет на 15 (если не считать собственно Rocks-n-Diamonds в 1995 году) — и воскрешение интереса к подобным играм, но уже в среде казуалочек и на мобильных телефонах — всякие там варианты Gameloft'а и т.п. — но это уже по сути новейшая история.

          Так что в этом плане, субъективно, Supaplex и Rocks-n-Diamonds примерно в одинаковом положении. И, насколько я помню, авторы модуля Supaplex'а для Rocks-n-Diamonds тоже заявляли о том, что дизассемблировали сам Supaplex.
            +5
            О том, что в Rocks-n-Diamonds код тоже получен дизассемблированием я не знал, спасибо за информацию. В любом случае, я не претендую на уникальность. Просто захотелось поделиться с сообществом.
              +2
              Сам _код_ там как раз написанный руками — хотя бы потому, что RnD предоставляет автору модуля что-то типа очень domain-specific виртуальной машины, внутри которой описывается собственно игра. Дизассемблировали оригинальные игры для того, чтобы понять логику работы и в точности ее повторить, вплоть до всех таймингов и, вероятно, этих самых пресловутых багов Supaplex'а.
                0
                А какие там баги? Пресловутые.
                  +1
                  Если не считать очевидных — например, то, что некоторые действия неправильно привязаны к таймеру и скорость может зависеть от скорости процессора — то есть n-ное количество своеобразного поведения игровой логики. Вот чуть ниже уважаемый mejedi привел пример одного из них и ссылку на более-менее полный список.

                  Я сам не копался глубоко в представлениях, но, насколько я помню, там проблема в том, что одни и те же данные представлены что-то типа 2-3-4 разными вариантами (например, взрывы одновременно кодируются списком взрывов, битмапом отображаемых тайлов, битмапом непроходимых тайлов и битмапом убивающих тайлов) — причем эти структуры данных обновляются не одновременно, а для разных игровых объектов разными алгоритмами в разных местах, что регулярно приводит к их рассинхронизации и всяким своеобразным эффектам типа временного или постоянного образования невидимых стенок, прохождения объектов друг сквозь друга, возможности сделать невозможное типа поставить 2 круглых шара (которые «zonk») друг на дружку и т.д.
                    +2
                    Массива там только два: текущее состояние уровня и активные взрывы (причем, взрывы еще дублируются в первом массиве). Но ситуация усугубляется тем, что практически все движущиеся объекты одновременно существуют в нескольких ячейках (из которой вышел и в которую направляется), а все кадры анимации кодируются отдельным кодом. И если подгадать тайминги, можно взорвать левую половину движущегося объекта, а правая «доползет» до места и это будет выглядеть странно. Ну и еще такие «половинчатые» объекты обладают странными свойствами (например, попа уползающего Мёрфи ведет себя как стена — на ней замирают падающие предметы, а сник-снак и электрон от нее уползают в обратную сторону, не вызывая взрыва).
              0
              Есть ещё Симпаплекс (2004) от Alawar с главным героем по имени… Мямля. Помимо схожей логики и названия, на сколько помню, есть даже похожие уровни.
                0
                Эм, да после 2000 я их даже считать смысла не вижу. Этих клонов только на флеше дикие сотни, а если считать мобильные игры — то запросто тысячи…
          +1
          Работают ли tricks в твоей версии?
            +4
            По идее должны, хотя я не проверял. Там большинство трюков растет из способа хранения игровых данных. Когда Мёрфи ползет по уровню, он занимает две ячейки (левая и правая половина), и эти ячейки обрабатываются специальным образом. Именно поэтому, например, сник-снак отворачивается от Мёрфи, а не съедает его, если отойти в сторону в момент, когда он подошел вплотную.
            0
            Было бы интересно посмотреть туториал по дизассемблированию.
              +3
              Я попробую написать что-нибудь на эту тему в ближайшее время. Правда, не факт, что до Нового года. Спасибо за идею.
                0
                У меня в закромах есть игрунька поменьше, но пока я не разобрал ее до последнего кирпичика, туториал писать как-то боязно. Теперь хоть знаю, что есть единомышленники.
                  0
                  А что за игра, если не секрет?
                    0
                    Skycat от Gamos. С (якобы?) правообладателями связаться удалось, но на вопрос «Можно?» ответа жду уже полгода. В частности, нашел человека, похожего на руководителя отдела рекламы Gamos, Павла Мусатова. Гендира, Евгения Сотникова, так и не нашел.
                      0
                      С этой игрой я, к сожалению, не знаком. В любом случае, удачи, коллега!
                        0
                        Играл в это, но не очень помню суть )))
                +4
                совпадение почти ;)
                я тоже вчера выложил дизассемблированную игрушку

                правда это EXOLON для ZX Spectrum.

                bitbucket.org/esl/exolon-zx
                  0
                  О, про особенности EXOLON — очень интересно почитать. Расскажете?

                  Мега штука своего времени. Для меня, например, это вообще первая игра\программа с которой начались компьютеры.
                    +1
                    а что бы хотелось узнать? ;)
                      0
                      Интересные особенности и открытия :)

                      Кое-что уже прочитал в readme в исходниках. Например, почему оно тормозит на большом количестве объектов — весьма интересно.
                        +1
                        было интересно посотртеть как оно работает,

                        «открытий» — как таковых то и нет.

                        основное откртытие — там вообще нет синхронизации с лучём ;)

                        тормозит — прозаичесски не успевает отрисовывать столько объектов на экране
                        чем больше на экране объектов — тем больше тормозит.

                        там почти нет компенсации кол-ва спрайтов.
                        точнее есть две, одна для мелких спрайтов 8x8
                        если их на экране <8 то оно искуственно отрисовывает недостающие пустые
                        вторая 16x16 — тоже такое хотели сделать (враги, 6 спрайтов)
                        но забыл вставить увелечение счётчика, и оно всегда работает как задержка
                        независимо от кол-ва спрайтов ;)

                        может народ займется и оптимизирует ее

                        собственно обсуждают это тут zx-pk.ru/showthread.php?t=24083&page=4

                          +1
                          Оу, спасибо за детали. — На форуме много интересного нашел.
                          И отдельно очень порадовало, что есть связь с автором! Это оччень-оччень круто :)
                          Мега дело делаете! )

                          Raffaele Cecco — закладывал основы. Exolon, Cybernoid, Stormlord! Эх, Nostalgie… 8)
                  –1
                  Порт этой игры на телефоны в моем рейтинге занимает пожалуй первое место среди мобильных игр)
                    +3
                    Классная была игрушка
                    Помню, в школе написал редактор уровней к ней
                      0
                      Игра раннего детства, блин!
                        +1
                        Началось всё с того, что исполняемый файл то ли запакован, то ли зашифрован. После безуспешного поиска чего-нибудь, что сможет его распаковать
                        Во времена DOS-a был универсальный распаковщик CUP386, его не пробовали?
                        Единственное из попадавшегося мне, что было ему не по зубам — файлы, упакованные упаковщиком com-файлов от Microsoft. Но для последнего был распаковщик от самого MS.
                          0
                          Нет, к сожалению не пробовал. В далекие времена, когда я сидел еще под DOSом у меня была коллекция упаковщиков и распаковщиков всех мастей. Но на момент, когда я занялся дизассемблированием, у меня этой коллекции уже давно не было, а имена упаковщиков из моей памяти стерлись. Поэтому я попытался погуглить, но не очень успешно. Правда, как я написал в статье, я не особо-то и старался. Все-таки идея написать свой распаковщик привлекала сильнее и я, скорее, искал моральное оправдание для написания велосипеда.
                          –1
                          А как вы создавали псевдокод на C++? Ведь супаплекс написан под 16-bit DOS, который IDA не умеет переводить в Pseudo C++?
                            0
                            Я его руками создавал. Читал оригинал, пытался понять как оно работает и как реализовать это на С++. Это можно частично проследить через импортированные из SVN коммиты (те, которые датируются 2009 годом).

                            Сначала я сделал компилирующийся .asm-файл и начал в нем разбираться, давая разумные имена функциям и переменным, гуляя по нему отладчиком. Потом, когда было по большей части понятно, что делает та или иная функция, я их переписал на С++.
                              0
                              Жаль :( Я думал, за последнее время что-то поменялось и Ильфак запилил эту фичу. А так бы хотелось спокойно и удобно получить компилирующиеся сырки той-же Civilization.

                              Опыт получения сырков для Win32 имеется — есть компилирующиеся исходники Diablo: Hellfire

                              А вам в любом случае респект за труд. Супаплекс прекрасная игра, на 286 в нее рубился очень много
                            0
                            Я когда-то порт Supaplex на J2ME нашёл. Довольно годный, но есть один удручающий недостаток: с ростом открытых уровней серьёзно растёт время запуска. На заполнение хипа вряд ли списать можно, поскольку он такими темпами давно бы кончился, посему вангую случайный ботлнек. Надо было бы поковырять… Даже если автор сырцов не оставил — Java, даже обфусцированная и минифицированная, довольно хорошо дизассемблируется тем же JaD.

                            Only users with full accounts can post comments. Log in, please.