DoubleDox

DoubleDox

Разработчик игр и музыкант группы "Одна Волна" :)
Пикабушник
Дата рождения: 10 октября
3023 рейтинг 3 подписчика 24 подписки 9 постов 3 в горячем
Награды:
5 лет на Пикабу
11

Реверс-инжиниринг из детства - вытаскиваем данные из Carmageddon TDR2000 - часть 2

Серия Геймдев

Ну что, двигаем дальше?) В прошлый раз Реверс-инжиниринг из детства - вытаскиваем данные из Carmageddon TDR2000 удалось распаковать архив с данными, самое время эти данные визуализировать!

Итак, погнали. За что цепляется взгляд?
tga - очевидно, текстуры, до них дойдем в последний момент
dcol - в PAK локаций я видел scol, логично предположить, что это Динамический КОЛлайдер
mshs - судя по всему - меш (MESH)
hie - какой то текстовый файл, описание модели?

Как и обычно в таких случаях - начинаю с меша (как оказалось потом - зря:) )
Открываем хекс-редактором

Первое, что запоминаем, это порядок байт - Little endian.
Что мы можем найти?
целые числа - обычно четыре байта, можно узнать по нулям в правых байтах.
float - 4 непонятных байта :)), но в редакторе можно выделить - и в анализе данных будет вполне адекватное значение.
а есть читабельные флоаты, например 00 00 80 3F - это 1
еще есть такой маркер - если корень суммы квадратов 3-х чисел равен 1 - значит перед нами нормаль :)
В общем, просто накидал простой парсер, который бинарные данные дампит по такой логике в таблицу - так разобрать куда легче )

Опыт работы с такими данными подсказывает, что пачки флоатов в начале - это вершины. Иногда они идут вместе с UV. Но здесь есть закономерность именно по 3 числа - что как бы намекает, что перед нами список векторов. Предполагаем, что число 30 перед этим блоком - количество векторов. Умножаем на 12... Ну, почти совпадает :)
Опущу эксперименты с визуализацией, у меня получилась такая схема:

Дальше начинается интересное, если отбросить следующие 3 флоата (анализ которых говорит что это нормаль), дальше идут числа 0, 1, 2 - ну, собственно, вот они, номера вершин полигона. И такой паттерн повторяется каждые 132 байта. Значит, каждые такой блок - это полигон.
Смотрим, сколько таких блоков? оу, 38, прям как было в первом числе.
Итак, в начале имеем количество полигонов и количество вершин, далее - данные. Но файл на этом не заканчивается. Далее... снова знакомый паттерн. количество поликов - 0 - 1 - количество вершин. И так до конца файла.
Итог - mshs файл это некоторое количество мешей, каждый меш состоит из вершин и поликов. Вот что с этим делать? Как они позиционируются? Я слегка забуксовал, думая, что позиции мешей записаны в самом файле, но нет, ключ был в файле hie, с которого и стоило начинать анализ :)

Number of textures, number of materials - тут всё логично, есть материалы, материалы ссылаются на текстуры (те tga, что мы видели при распаковке, очевидно)
Что особенно интересно:

  • Matrices

  • Nodes

  • Meshes - а блин, количество как раз совпадает с количеством блоков, считанных в mshs )))

Взгляд цепляется за Nodes, как будто это те данные, которые выстраивают иерархию модели, вот только узлов как то многовато. Если данные развернуть в дерево, то получится довольно громоздкая структура.
Ответ в поле TYPE. каждый узел этого дерева иерархии отвечает за свой тип.
Ну, осталось только сопоставить где какой тип :)
Я заметил такую закономерность, для каждого типа узла есть свой диапазон значения в поле INDEX.
Что получаем?
1 - в пределах количества Matrices
2 - в пределах количества Textures
3 - в пределах количества Meshes
4 - в пределах количества Expressions (не упоминал ранее, но есть в HIE-файле)
5 - в пределах количества Materials
7 - в пределах количества Collision Meshes
Значит, алгоритм следующий.
Элементы типа 1 представляю собой собственно иерархию "костей", к каждой кости применяем матрицу преобразования, которая ей соответствует.
элемент типа 2 - устанавливает тектуру.
элемент типа 3 - читает меш из файла mshs
элемент типа 4 - применяет expression из самого файла hie (но, каюсь, не доразобрался зачем оно надо:) )
элемент типа 5 - устанавливает материал
элемент типа 7 - читает коллизию из файла *col (на данной стадии мне не особо это важно было, поэтому не парсил)
Пара скринов процесса :)

когда наконец-то понял, как позиционировать меши :)

когда наконец-то понял, как позиционировать меши :)

А вот с применением текстур ) рядом подвинул лоу-поли модель :)

А вот с применением текстур ) рядом подвинул лоу-поли модель :)

Повреждёная модель всё в том же файле :)

Повреждёная модель всё в том же файле :)

Ееее! Выцепил )

Ееее! Выцепил )

Применил логику ко всем машинам в карме - ну, не всё прям прочиталось отлично, где то проблемы с текстурами, но эксепшны не лезут - уже успех :))

Что дальше? Надо расковырять локации! А пока пока - вот вам скрин тачки из Carmageddon TDR2000 на трассе из Need for Speed 3 (которую я расковырял уже давно) :)

Надеюсь, до встречи следующей части! План - расковырять локации :)

Показать полностью 10
25

Реверс-инжиниринг из детства - вытаскиваем данные из Carmageddon TDR2000

Серия Геймдев

Оффтоп - у меня навязчивая идея сделать гонки, где можно было бы проехать на машинах из одной старой игры трассу из другой старой игры :) Уже поковырялся в NFS1-NFS5, Carmageddon1-2, и вот, дойдя до TDR2000 решил, что пора как-то уже делиться с людьми своими наработками :)

Итак, заходим в папку игры, что мы имеем? папку Assets и папку Saves. Очевидно, данные в первой :)

А там уже есть и папка Tracks (локации) и папка Cars (тачки)!

Ну, ввиду того, что цель стоит в том, чтобы разобраться как всё устроено - начнём с Cars, там обычно меньше данных :))

Ткнём, ну, в electric_blue

файл *.h - это описание каких то нод, пока запомним про его наличие :)

*descriptor.txt - а вот это, похоже, важный файл, есть упоминания файлов, входящих в описание модели. Думаю, обязательно к нему вернёмся :)

*texturedescriptor.txt - наверняка описание использования текстур. к нему если и вернёмся, то на стадии текстурирования модели :)

Вот что и правда интересно, и не поддается анализу через супер-утилиту Блокнот (ахахах) - так это файл dir и файл pak.

Логично предположить (исходя из размера и названия) - dir это индекс, pak - это сами упакованные данные.

Вообще обычно в старых играх индекс и сами данные лежат в одном файле. А тут - отдельно. Ну, мне же проще. Открываем DIR в Hex-редакторе...

ан нет, не проще :))

Глаз цепляется за то, что каждый нечётный байт как будто бы содержит контент, а чётный - видимо какие то флаги.

Вообще, при расшифровке таких архивов важно получить следующие данные:

- Название файла
- Смещение начала даннах
- Размер данных

Вернёмся же к индексу.

В чётных байтах как будто записаны названия файлов.

Но названия (String) должны либо иметь длину в начале, либо заканчиваться нулём.

Здесь ни то ни то, но в байте флагов в конце строчки - всегда 08h!

Запомним-с. а лучше - запишем-с

А что идёт после названия? наверняка нужные нам указатели смещения и размера.

C9 7F 16 00 - хм. какое то большое значение для смещения первого элемента.

B6 02 00 00 - а вот это для размера норм. Но, как бы там ни было, смещение укладывается в размер файла PAK (1474505 внутри файла 1 475 199 байт) - и даже тот факт, что так близко к верхней границе, говорит о том, что мы близко к истине :) просто первый элемент в индексе не является первым в самом архиве.

Пора писать скрипт чтения архива!

Вот здесь я реально немного задолбался писать свои копания в архиве, скажу кратко - в DIR файле не просто индекс, он еще и "заархивирован" так, чтобы повторяющиеся части путей не писать повторно. В итоге файл делится на блоки - ноды.

вся суть в байте флагов (про который я говорил ранее)

исследование привело к следующим выводам:

- 08h - завершение строки. после него сразу идут смещение и размер данных в файле PAK

- 40h - у текущего символа есть "вложения" - нужно дальше искать ноды и присобачить текущий преффикс к ним перед тем, как возвращать имя этих записей

- 80h - ничего не делаем, просто читаем дальше имя записи.

Итак, вот у нас есть список имён файлов, их смещения и размеры внутри PAK.

Пробуем читать.

На первый взгляд всё ок - смещения, а так же смещения+размер - все укладываются в размер файла PAK.

Но, что то не так.

Файлы, которые называются .txt ведут на данные, которые не очень то похожи на текстовые.

Запакованы?

В те времена часто использовался zlib для упаковки, который можно проверить по наличию байтов компрессии (с просторов интернета):

78 01 - No Compression/low
78 5E - Fast Compression
78 9C - Default Compression
78 DA - Best Compression

И да, 78 DA частенькой находится в файле PAK

Единственное, что смущает - он не в начале данных конкретной записи файла идёт... значит, пишем алгоритм, который пропускает всё, что идёт до этих данных. А остальное скармливаем ZLib'у (использую Ionic.zlib). Как результат - теперь получаем пачку файлов с данными машины. А вот об этом уже дальше, если вдруг это и правда интересно :)

На CSV не смотрите, это следующий шаг анализа dcol-файлов :)

На CSV не смотрите, это следующий шаг анализа dcol-файлов :)

Если есть желающие тоже в этом покопаться - черканите, оформлю в реп то, что уже накодил.

И, если есть ссылки на уже готовые решения - тоже пишите, мало ли, я провафлил этот момент и изобретаю велосипед :)

Показать полностью 4
22

Кризис среднего возраста (или "Как я стал музыкантом")

Я немного удивлён, что у меня теперь есть 2 подписчика, так что… почему бы не поразглагольствовать :))

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

Согласился.

Выступил.

И всё - я понял, что вот там на сцене я чувствую себя живым.

Поставил себе цель - я хочу петь так круто, чтобы можно было выступать на постоянной основе.

Пошёл на уроки вокала. Первый год был тяжелый. Я пел, записывал себя, слушал, и… пил =)))

Но я пел каждый день.

И со временем я стал меньше плеваться от своего вокала.

А потом как то само собой закрутилось. Сначала пел по интернету (в Smule), потом пел на благотворительных мероприятиях для детей в детских домах. А потом попал в настоящий мюзикл! На главную злодейскую роль. Правда, мюзикл финансово не взлетел :( Но это был охрененный опыт - дополнительно прокачал актерский навык и завел знакомства с талантливыми ребятами.

Чтобы иметь какую-то реализацию в качестве вокалиста, решил - надо собрать кавер-группу, будем играть на репбазе, буду качать вокал, а заодно, может, дорастем до какой-нибудь небольшой сцены (где можно будет играть кавера).

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

А где то фоном зрела мысль, что нужны авторские песни.

Вообще у меня не было опыта написания собственных песен, и я был уверен что креатив - это не моё, но… но хотелось иметь собственный материал. В то время как раз бахнул ковид, и все сидели по домам, поэтому решил заняться изучением музыкальной теории. И вдруг оказалось что писать музыку самому - это вполне реально :))

Ну ладно, значит вопрос в тексте. Но что делать? стихи я не писал никогда (ну если только в рамках стёба зарифмовать что то, но ничего особо осмысленного). Окей, гугл, как писать стихи? :) Вот эта задача была гораздо сложней (спойлер: да и даже сейчас я трачу на тексты песен намного больше времени, чем на музыку). Но, в итоге, после нескольких неудач у меня состыковалась музыка с текстом, так появился на свет мой первый трек “Первый шаг”. Да, это трек про меня в том числе, но я всегда его посвящаю тем, кто решается сделать тот самый первый шаг, на который, как правило, нужно половину усилий - ведь дальше всё проще :)

Песня написана 3 года назад, с тех пор я успел собрать группу для выступлений, дать пару десятков концертов, даже организовать несколько своих фестов и сольник, записать в студии и выпустить 11 треков. Это были долгие 3 года, но, думаю, не стоит ими перегружать этот пост, но если будет интересно - расскажу в отдельном, каково это - поднимать группу с нуля :)

Оставлять прямые ссылки на паблики мне не позволяет скромность, но если кому интересно, группа называется “Одна Волна” - есть на всех основных музыкальных площадках :)

Основную работу, кстати, не бросил :) Даже как то меньше стал выгорать. Да и стабильный заработок нужен - музыка требует вложений: в оборудование, звукозапись и концерты.

А, к чему я это всё? Нет, я пока не чувствую, что добился чего то существенного. Но я хотя бы ощущаю себя на своём месте. И, мне бы хотелось своим примером вдохновить других. ТВОРИТЕ! это наполняет человека, придаёт жизни смысл.

Показать полностью 1
16

Яндекс.доставка, вы там перегрелись? =)

Заказали доставку, были дома, но пропустили звонки от курьера, курьер не придумал ничего лучше, кроме как заблокировать дверь коробками. Спасибо, вы сделали наш день (даже фото прислал снаружи!) :))

Яндекс.доставка, вы там перегрелись? =)
Показать полностью 1
Отличная работа, все прочитано!

Темы

Политика

Теги

Популярные авторы

Сообщества

18+

Теги

Популярные авторы

Сообщества

Игры

Теги

Популярные авторы

Сообщества

Юмор

Теги

Популярные авторы

Сообщества

Отношения

Теги

Популярные авторы

Сообщества

Здоровье

Теги

Популярные авторы

Сообщества

Путешествия

Теги

Популярные авторы

Сообщества

Спорт

Теги

Популярные авторы

Сообщества

Хобби

Теги

Популярные авторы

Сообщества

Сервис

Теги

Популярные авторы

Сообщества

Природа

Теги

Популярные авторы

Сообщества

Бизнес

Теги

Популярные авторы

Сообщества

Транспорт

Теги

Популярные авторы

Сообщества

Общение

Теги

Популярные авторы

Сообщества

Юриспруденция

Теги

Популярные авторы

Сообщества

Наука

Теги

Популярные авторы

Сообщества

IT

Теги

Популярные авторы

Сообщества

Животные

Теги

Популярные авторы

Сообщества

Кино и сериалы

Теги

Популярные авторы

Сообщества

Экономика

Теги

Популярные авторы

Сообщества

Кулинария

Теги

Популярные авторы

Сообщества

История

Теги

Популярные авторы

Сообщества

Недвижимость и ремонт

Теги

Популярные авторы

Сообщества