Reverse Engineering игры Parkan Железная стратегия 1998
Сборка проекта
Проект написан на C# под .NET 9
Вам должно хватить dotnet build для сборки всех проектов отдельно.
Все приложения кросс-платформенные, в том числе UI.
Состояние проекта
- Поддержка всех
NResфайлов - звуки, музыка, текстуры, карты и другие файлы. Есть документация. - Поддержка всех
TEXMтекстур. Есть документация. - Поддержка файлов миссий
.tma. - Поддержка шрифтов TFNT.
- Поддержка файлов скриптов
.scr. - Поддержка файлов параметров
.var. - Поддержка файлов схем объектов
.dat.
Структура проекта
Внимание!
Проект делается как небольшой PET, поэтому тут может не быть
- чёткой структуры
- адекватных названий
- комментариев
Я конечно стараюсь, но ничего не обещаю.
Для Reverse Engineering-а использую Ghidra
Наблюдения
- Игра использует множество стандартных библиотек, в частности stl_port, vc++6 и другие. Если хотите что-то изучить в игре, стоит поискать по строкам и сигнатурам, что именно используется в конкретной
dll. - Строки в основном используются двух форматов -
char*иstd::string. Последняя состоит из 16 байт -undefined4, char* data, int length, int capacity. - В игре очень много
inlineфункции, которые повторяются по куче раз в бинарнике. - Игра загружает и выгружает свои
dllфайлы по несколько раз, так что дебаг сMemory Mapочень затруднён. - Игра активно и обильно течёт по памяти, оставляя после чтения файлов их
MapViewOfFileи подобные штуки. - Игра нормально не работает на Win10. Мне помог dgVoodoo. Хотя с ним не работает
MisEditor.
Как быстро найти текст среди всех файлов игры
grep -rl --include="*" "s_tree_05" .
Как быстро найти байты среди всех файлов игры
grep -rlU $'\x73\x5f\x74\x72\x65\x65\x5f\x30\x35' .
Как работает игра
Главное меню:
Игра сканирует хардкод папку missions на наличие файлов миссий. (буквально 01, 02, 03 и т.д.)
Сначала игра читает название миссии из файла descr - тут название для меню.
- Одиночные игры -
missions/single.{index}/descr - Тренировочные миссии -
missions/tutorial.{index}/descr - Кампания -
missions/campaign/campaign.{index1}/descr- Далее используются подпапки -
missions/campaign/campaign.{index1}/mission.{index2}/descr
- Далее используются подпапки -
Как только игра не находит файл descr, заканчивается итерация по папкам (понял, т.к. пробуется файл 05 - он не существует).
Загрузка миссии:
Читается файл ui/game_resources.cfg
Из этого файла загружаются ресурсы
library = "ui\\ui.lib"- загружается файлui.liblibrary = "ui\\font.lib"- загружается файлfont.liblibrary = "sounds.lib"- загружается файлsounds.liblibrary = "voices.lib"- загружается файлvoices.lib
Затем игра читает save/saveslots.cfg - тут слоты сохранения
Затем Comp.ini - тут системные функции, которые используются для загрузки объектов.
-
Host.url- этого файла нет -
palettes.lib- тут палитры, но этот NRes пустой -
system.rlb- не понятно что -
Textures.lib- тут текстуры -
Material.lib- тут какие-то материалы - не понятно -
LightMap.lib- видимо это карты освещения - не понятно -
sys.lib- не понятно -
ScanCode.dsc- текстовый файл с мапом клавиш -
command.dsc- текстовый файл с мапом клавиш
Тут видимо идёт конфигурация ввода
-
table_1.man- текстовый файл -
table_2.man- текстовый файл -
hero.man- текстовый файл -
addition.man- текстовый файл -
Снова
table_1.man -
Снова
table_1.man -
M1.tbl- текстовый файл -
Снова
table_2.man -
Снова
table_2.man -
M2.tbl- текстовый файл -
Снова
hero.man -
Снова
hero.man -
HERO.TBL -
Снова
addition.man -
ui/hq.cfg -
Снова
ui/hq.cfg
Дальше непосредственно читается миссия
mission.cfg- метадата миссииunits\\units\\prebld\\scr_pre1.datиз метаданныхobject prebuild-cpфайл (грузятся подряд все)- Опять
ui/hq.cfg mistips.mis- описание для игрока (экран F1)scancode.dsc- хзcommand.dsc- хзui_hero.man- хзui_bots.man- хзui_hq.man- хзui_other.man- хз- Цикл чтения курсоров
ui/cursor.cfg- тут настройки курсора.ui/{name}- курсор
- Снова
mission.cfg- метадата миссии descr- названиеdata/textres.cfg- конфиг текстов- Снова
mission.cfg- метадата миссии - Ещё раз
mission.cfg- метадата миссии ui/minimap.lib- NRes с текстурами миникарты.messages.cfg- Tutorial messages
УРА НАКОНЕЦ-ТО data.tma
-
Из
.tmaберётся LAND строка (я её так назвал) -
DATA\\MAPS\\SC_3\\land1.wea -
DATA\\MAPS\\SC_3\\land2.wea -
BuildDat.lst- Behaviour will use these schemes to Build Fortification -
DATA\\MAPS\\SC_3\\land.map -
DATA\\MAPS\\SC_3\\land.msh -
effects.rlb
Цикл по кланам из .tma
-
MISSIONS\\SCRIPTS\\screampl.scr -
varset.var -
MISSIONS\\SCRIPTS\\varset.var -
MISSIONS\\SCRIPTS\\screampl.fml -
missions/single.01/sky.ske -
missions/single.01/sky.wea
Дальше начинаются объекты игры
"UNITS\\BUILDS\\BUNKER\\mbunk01.dat"- cp файл
Загрузка cp файлов
cp файл - схема. Он содержит дерево частей объекта.
cp файл читается в ArealMap.dll/CreateObjectFromScheme
В зависимости от типа объекта внутри схемы (байты 4..8) выбирается функция, с помощью которой загружается схема.
Функция выбирается на основе файла Comp.ini.
- Для ClassBuilding (0x80000000) - вызывается функция c классом 3 (по таблице ниже Building).
- Для всех остальных - функция с классом 4 (по таблице ниже Agent).
На основе файла Comp.ini и первом вызове внутри функции World3D.dll/CreateObject ремаппинг id:
| Class ID | ClassName | Function |
|---|---|---|
| 1 | Landscape | terrain.dll LoadLandscape |
| 2 | Agent | animesh.dll LoadAgent |
| 3 | Building | terrain.dll LoadBuilding |
| 4 | Agent | animesh.dll LoadAgent |
| 5 | Camera | terrain.dll LoadCamera |
| 7 | Atmospehere | terrain.dll CreateAtmosphere |
| 9 | Agent | animesh.dll LoadAgent |
| 10 | Agent | animesh.dll LoadAgent |
| 11 | Research | misload.dll LoadResearch |
| 12 | Agent | animesh.dll LoadAgent |
Будет дополняться по мере реверса.
Всем этим функциям передаётся nres_file_name, nres_entry_name, 0, player_id
fr FORT файл
Всегда 0x80 байт Содержит 2 ссылки на файлы:
.bas.ctl- вызываетсяLoadAgent
.msh
Загружается в AniMesh.dll/LoadAniMesh
- Тип 03 - это вершины (vertex)
- Тип 06 - это рёбра (edge)
- Тип 04 - скорее всего какие-то цвета RGBA или типа того
- Тип 12 - microtexture mapping
- Тип 0A
Не имеет фиксированной длины. Хранит какие-то строки в следующем формате. Игра обращается по индексу, пропуская суммарную длину и пропуская 4 байта на каждую строку (длина). т.е. буквально файл выглядит так 00 00 00 00 - пустая строка 03 00 00 00 - длина строки 1 73 74 72 00 - строка "str" + null terminator .. и повторяется до конца файла Кол-во элементов из NRes должно быть равно кол-ву строк в этом файле, хотя игра это не проверяет.
Тип 02 имеет заголовок 140 байт. Игра сначала читает из него первые 96 байт. А затем пропускает с начала 148 байт
.wea
Загружается в World3D.dll/LoadMatManager
.wea
Загружается в World3D.dll/LoadMatManager
Внутренняя система ID
1- IMesh2 ???4- IShader5- ITerrain6- IGameObject (0x138)8- ICamera9- Queue10- IControl0xb- IAnimation0xd- IMatManager0x10- unknown (implemented by Wizard in Wizard.dll, also by Hallway in ArealMap.dll)0x11- IBasement0x12- ICamera2 - BufferingCamera0x13- IEffectManager0x14- IPosition0x16- ILifeSystem0x17- IBuilding0x18- IMesh20x19- unknown (implemented by Wizard in Wizard.dll, also by Agent in AniMesh.dll)0x20- IJointMesh0x21- IShade0x24- IGameObject20x101- 3DRender0x201- IWizard0x202- IItemManager0x203- ICollManager0x301- IArealMap0x302- ISystemArealMap0x303- IHallway0x401- ISuperAI0x105- NResFile0x106- NResFileMetadata0x501- MissionData0x502- ResTree0x700- NetWatcher0x701- INetworkInterface0x10d- CreateVertexBufferData
Контакты
Вы можете связаться со мной в Telegram.