Год работы за один вечер

Или полный reverse engineering Harry Potter 2001

Год работы за один вечер

Предисловие

Меня зовут Саня. Я уже больше 9 лет в геймдеве, достаточно долго работал в Ubisoft и не только. Я левел-квест-гейм дизайнер, напрямую с кодом никогда связан не был. Программировать не умел, да и особо не планировал.

Но примерно полгода назад, я начал замечать что границы между "я могу это сделать" и "это не для меня" стали как-то размываться. Сайт? Могу. iOS апп? Тоже. Спасибо ИИ. Сделать что-то, чего я вообще не понимаю технически? Ну… как минимум, попробовать можно.

Мой друг делает ремейк Harry Potter and the Philosopher's Stone 2001 года, а это одна из моих любимых игр детства, наравне с Героями 3 и GTA San Andreas, между прочим.

Ремейк – очень тяжелый труд: игра старая, исходников нет. Другу необходимо вытаскивать геометрию, сцены, скрипты для того, чтобы в точности повторить на современном движке. Воссоздавать это руками – месяцы работы и куча головной боли...

Друг говорит: "Может, можно как-то вытащить геометрию, с помощью твоего, этого, ИИ?"

Я ответил: «Ничего не обещаю – но попробую. У меня есть команда».

Моя команда

Нас по факту трое.

Я – ставлю задачи, тестирую инструменты руками, принимаю решения. Всё что касается «открыть, посмотреть, попробовать» – эт я.

Клавдик – AI–агент, это Clawdbot (OpenClaw). Просто враппер AI, который стоит на компе, может запускать скрипты и доступен в телеге. Консультирует, формулирует промпты, координирует. Сам код пишет только иногда, справляется не всегда хорошо.

Claude Code – отдельные сессии на Opus 4.6. Получает задачу, пыхтит, делает. Короче, единственный кто из нас троих работает.

Пайплайн – я обозначаю цель → Клавдик разбирает её, дает варианты решения, я выбираю, что делаем, даю задачу Claude Code → Claude Code делает → смотрю что получилось → идём дальше.

Часть 1: анализ

Итого, значит, задача: получить геометрию из игры 2001 года. Сходу такие варианты:

  • Umodel
  • риперы
  • редакторы модов
  • парсинг бинарников

Основная проблема: игра не переиздавалась, исходники не публиковались, инструменты разработки пойди найди – Unreal Engine 1. На форумах модеров есть какие-то редакторы, надо искать, копаться, никакой конкретики сходу нет.

Часть 2: попытки достать геометрию

Попытка 1 — Claude Code копает бинарники

Первым делом решаю загрузить Claude Code таском, который он может делать на фоне – парсинг бинарников. Попросил Клавдика написать промпт и отдал его в Claude.

Задача – разобрать бинарный формат .unr файлов напрямую. Байт за байтом. Единственная документация: исходники Unreal Tournament 99, которые Epic когда-то частично опубликовала. Но HP1 использует пакетную версию 76, а UT99 – версию 68. Форматы похожи но не идентичны. А в бинарных файлах это критично, 0101010100101010.

Claude за работой
Claude за работой

Оставляю Claude Code работать в окошке терминала, пусть сам разбирается, пока иду обсуждать с Клавдиком следующие варианты.

Попытка 2 — Umodel: извлечение ассетов из .unr через готовый инструмент

Umodel – классика для распаковки Unreal Engine пакетов. Поддерживает кучу версий движка, умеет доставать меши, текстуры, анимации.

Скачал, поставил на комп. Скормил туда .unr файлы уровней.

Результат: карты не открываются.

Открылся только этот бро
Открылся только этот бро

Для UE1 он умеет доставать статические меши и текстуры, но BSP геометрию уровней нет. Она хранится принципиально иначе и Umodel про неё просто не знает.

Попытка 3 — Ninja Ripper перехват геометрии из запущенной игры

Работает это так: запускаешь игру, цепляешь Ninja Ripper, он перехватывает DirectX draw calls и сохраняет меши. Звучит просто.

На практике всё оказалось сложнее. Бесплатная версия Ripper'а сначала вообще отказалась работать — раз десять менял настройки: DirectX-враппер, параметры инъекции, способ запуска. В итоге добился хоть какого-то вывода, но результат так и не собрался в адекватную геометрию.

Попытка 4 — экспорт уровней через редактор модов

UW_HUB – фанатский dev kit для Harry Potter 1/2/3. Это готовая среда для модинга. Уровни открываются, все видно, но можно ли из него экспортнуть геометрию?

Попробовал, T3D экспортировался. Клавдик написал конвертер t3d2obj.py. Открываю результат в Blender. Мусорка.

Мусорка
Мусорка

Геометрия есть, некоторые формы узнаваемые. Но всё завалено субтрактивными брашами – CSG Subtract. Это дыры в стенах, проёмы, арки. T3D содержит исходные CSG кисти до компиляции.

При этом Claude Code уже выдает какие-то успехи, поэтому решаю дропнуть этот вариант.

Попытка 5 — Ninja Ripper на редакторе

Пока Claude Code итерирует, я пробую Ninja Ripper прям в UW_HUB. Раз редактор показывает правильную геометрию в 3D–вьюпорте, может снять её риппером прям оттуда?

Тут тоже одни проблемы. Десяток крашей. Результата – нет.

один из многих
один из многих

Проблема в том, что UW_HUB рендерит через OpenGL. Ninja Ripper работает только с DirectX. Попытка переключить UW_HUB на D3D рендер тут же крашила редактор. Неудивительно, учитывая что инструменту тысяча лет, скорее удивительно, что он вообще запускался.

Четыре попытки, четыре разных инструмента, пока ноль рабочей геометрии. Возвращаюсь к Claude Code.

Попытка 1(продолжение) — Claude Code копает бинарники

Всё это время пока я возился с доисторическим наследием геймдева — Claude Code на фоне молча копал бинарники напрямую. Что-то делает и делает, думает и думает.

Год работы за один вечер

Дальше за разделителем много технических подробностей. Но если коротко: полтора часа, 20 скриптов, ~4700 строк кода — и он разобрал формат с нуля. Просто превратил бинарные файлы в узнаваемую геометрию, которую я мог открыть в Blender.

Много технических подробностей

Разбираем структуру пакета

UE1 пакет устроен как база данных. Три таблицы: Name Table, Import Table, Export Table. Каждый объект — бинарный блок данных по своему смещению.

Claude Code написал парсер и убедился что таблицы читаются правильно — нашёл имена классов, акторов, мешей.

Дальше возня с Compact Index — формат хранения чисел в UE1. Переменная длина от 1 до 5 байт со специфичной битовой упаковкой. Документация UT99 описывает его одним образом, а в версии 76 биты расставлены иначе.

Год работы за один вечер

Когда Compact Index парсится неправильно — все смещения съезжают и дальше только мусор. Несколько итераций ушло только на то чтобы подобрать правильную раскладку битов.

Первые меши

Первая попытка вытащить геометрию: найти в Export Table объекты типа Polys и распарсить структуры FPoly — многоугольники.

Claude Code написал parse_bsp.py. Результат: chess_bsp.obj — 1250 полигонов. Я открыл в Blender — каша из пересекающихся плоскостей. Опять.

chess_level_<b>clean</b> (!)
chess_level_clean (!)

Причина выяснилась позже: Polys это те же самые CSG brush inputs. Исходные формы. Чертежи, не само "здание". Те же данные, что давал T3D экспорт из редактора. Финальная геометрия хранится в объекте Model — скомпилированное BSP–дерево узлов.

Код работает, данные не те.

BSP–дерево — правильный источник

Переключился на Model. Внутри массив Nodes, каждый узел содержит пул вершин, вершины ссылаются на Points – позиции в мировом пространстве.

Цепочка:

Node.iVertPool → Verts[pool+i].pVertex → Points[pVertex]

Claude Code последовательно разбирал бинарные структуры и каждый раз что–то новое мешало получить нормальный результат.

Структура FBspNode в версии 76:

FPlane (16 байт) + ZoneMask (uint64, 8 байт) + NodeFlags (uint8) + 7 × CompactIndex + iZone[2] (uint8) + NumVertices (uint8) + iLeaf[2] (int32)

После: FBspSurf. В документации UT99 описано 8 полей. В версии 76 их оказалось 10. Два лишних: INT32 unknown1 и CompactIndex unknown2. Без них все смещения после первых нескольких структур съезжают и дальше мусор.

это не Хогвартс
это не Хогвартс

Чтобы найти эти скрытые поля Claude Code делал hex-дампы, считал байты, сравнивал значения с ожидаемыми диапазонами. Раз за разом.

Всего на реверс-инжиниринг ушло около полутора часов. За это время: 20 Python-скриптов, ~4700 строк: парсеры, дебаг-утилиты, зонды отдельных структур.

Геометрия! Но зеркальная

Первый рабочий экспорт BSP-дерева: уровень с шахматами (Lev5_Chess.unr), 1734 полигона. Я открываю в Blender: колонны, лестницы, арки, шахматное поле. Впервые за весь вечер узнаваемая геометрия.

Но зеркально отражённая по одной оси.

Причина тупейшая: при конвертации координат из UE1 в OBJ-формат стоял лишний минус перед одной из осей. Убрали минус – всё встало на место.

Я в этот момент в полном шоке, что у меня есть хоть какая-то адекватная геометрия на руках. Буквально за 5 минут до этого, я спрашивал у Клавдика: "А какой шанс, что у нас вообще что-нибудь получится?". И вдруг – получилось!

я не верю
я не верю

Но впереди еще остальные карты.

39 из 41 карты за один прогон

Дальше автоматизация. Каждая из 41 карты хранит Model на разных смещениях, хардкодить нельзя.

Claude Code написал алгоритм автодетекции: парсим Export Table, находим самый большой Model, сканируем первые 2000 байт, ищем массив единичных векторов — нормали, их длина всегда ~1.0. Следующий массив — координаты точек, длина вектора > 10. Двойная валидация, дальше Nodes → Surfs → Verts последовательно. Плюс фильтрация невидимых поверхностей и порталов.

Результат: 39 из 41 карты экспортированы. Два провала: Entry.unr и startup.unr видимо это экраны меню, там нет BSP–геометрии.

на скрине 38, но 39 карту мы достали через пару минут
на скрине 38, но 39 карту мы достали через пару минут

39 OBJ-файлов, 41.9 MB геометрии.

Самый большой уровень: стелс-секция с плащом-невидимкой: 13 648 граней, 66 076 вершин.

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

На выходе — 39 OBJ-файлов, все уровни из игры, готовые к импорту. Стены подземелий. Лестницы Хогвартса. Коридоры, комнаты, арки — всё на месте. Не CSG-кисти, не мусор, а настоящая, скомпилированная BSP-геометрия. Та самая, которую Umodel не знает, Ninja Ripper не смог мне помочь перехватить, а UW_HUB выдавал только в виде мусорки.

Я не верю, пишу другу: "Ты знаешь, что только что произошло?". Он тоже в шоке.

в шоке
в шоке

Часть 3: А что, если…

BSP-геометрия – это форма уровней. Стены, пол, лестницы. Уже сэкономил другу месяц-другой работы. Но, раз получилось достать геометрию, может получится достать механики?

Для этого нужен UnrealScript – скриптовый язык Unreal Engine 1. Весь геймплей HP1 прописан в .u пакетах в виде байткода.

Клавдик начал прикидывать архитектуру кастомного декомпилятора, но сначала качнул мне UT Package Tool, этот тул уже умеет декомпилировать UnrealScript. Проблема в том, что декомпилировать и экспортировать скрипты из него можно, но по одному. Обрабатывать 1700 файлов руками – такой себе прикол.

за качество скрина извиняюсь
за качество скрина извиняюсь

Поэтому я опять возвращаюсь в Claude Code, даю задачу: все скрипты надо декомпилировать. Хорошо он уже шарил за процесс, после того как с картами разбирался, это сильно ускорило работу. В итоге минут за 5 все скрипты прогнал. 120к строк кода, ~1700 файлов.

Что внутри

По сути весь код игры.

  • Harry.uc, 68 KB. Полный контроллер игрока: 17 состояний, движение, прыжки, взаимодействие с объектами.
  • BossQuirrel.uc, 31 KB. Финальный босс. Квиррелл/Волдеморт. Две фазы, 80 HP.
  • ChessBoard.uc, 19 KB. Логика волшебных шахмат: Сетка 8×8, AI пешек и… сортировка пузырьком для выбора хода – 2001 год как никак.
  • И еще ~1697 файлов

Теперь у меня есть 120 000 строк кода с описанием механик. Эх, вот бы существовал работник, который может за раз прочитать тысячи строк, держать их в голове, проанализировать и собрать нормальную документацию…

А, точно!

Итак, за 1 минуту Claude собрал MECHANICS.md: 896 строк, 35 KB, 16 разделов.

Каждое заклинание с точными значениями урона и скорости снаряда, каждый враг с паттернами атак, все параметры движения Гарри, HUD, система сохранений. Полный справочник механик короче. Заодно я попросил его сделать мне html viewer с поиском, чтобы удобнее было навигироваться.

сделать html – cамая простая задача за вечер
сделать html – cамая простая задача за вечер

Что получилось

  • Python-скриптов реверс-инжиниринга | 20 файлов, ~4700 строк
  • Карт HP1 в OBJ-формате | 39 файлов, 41.9 MB
  • Декомпилированных скриптов | 1700 файлов, ~120 000 строк
  • Mechanics Bible | 896 строк, 16 разделов

Сколько бы это заняло у человека

Много.

Допустим, берем разработчика с опытом в реверсе: C/C++, hex-дампы, бинарные форматы. Без специфических знаний UE1 v76, которые мало у кого есть. Занимается по вечерам.

Compact Index. Нетривиальная битовая структура, правильный вариант для v76 не очевиден. Дни экспериментов с hex-редактором.

Два скрытых поля в FBspSurf. Их нет в документации UT99. Без них все смещения съезжают и ты видишь мусор. Понять что проблема в лишних полях, а не в ошибке парсинга: часы или дни слепого сравнения hex-дампов.

Автодетекция Model для 41 карты. Алгоритм эвристического поиска по длине векторов – это ещё придумать надо.

Документация на основе 120 000 строк. Просто код. Прочитать всё, удержать структуру, вычленить механики и описать текстом. Проблема не только в объёме: человек не держит в голове 1700 файлов одновременно. Итерации, заметки, кросс-референсы. Месяц–полтора только на это.

Реалистичная оценка: несколько месяцев – год, в зависимости от знакомства с экосистемой UE1.

Claude Code сделал это за полтора часа. Со всеми итерациями, отладкой и слепыми ветками. Человек за hex-редактором устаёт к третьему часу, к пятому теряет концентрацию, к десятому сомневается что вообще правильно зашёл.

Зачем я это написал

Не для того чтобы сказать «AI заменит программистов». Вообще не про это.

Да, вероятно был более простой вариант решения. Возможно какой-то из платных инструментов экспортировал бы всё разом. Но я не искал идеальный путь – я искал рабочий. И я его нашёл. Заодно сэкономил другу месяц работы.

И с этим помог AI. Не потому что он умнее, а потому что реверс-инжиниринг бинарного формата это тысячи мелких итераций где нужно держать в голове одновременно структуру пакета, битовую раскладку, смещения массивов и результаты предыдущих тестов. Человек это может, но медленно и с потерями.

Я не программист-реверсер. Я квестдизайнер. Раньше это означало что задачи вроде этой ко мне отношения не имеют. Всегда была разница между «у меня есть идея» и «я могу это реализовать», и для не-технаря она была почти непреодолима. Сейчас этот гэп схлопывается. Теперь я верю, что возможно почти всё, главное правильно сформулировать задачу – а дальше итерировать, тестировать, улучшать.

39 карт. 120 000 строк кода. Полная документация механик. Один вечер.

you can just do things

56
16
1
1