Год работы за один вечер
Или полный 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 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 — каша из пересекающихся плоскостей. Опять.
Причина выяснилась позже: Polys это те же самые CSG brush inputs. Исходные формы. Чертежи, не само "здание". Те же данные, что давал T3D экспорт из редактора. Финальная геометрия хранится в объекте Model — скомпилированное BSP–дерево узлов.
Код работает, данные не те.
BSP–дерево — правильный источник
Переключился на Model. Внутри массив Nodes, каждый узел содержит пул вершин, вершины ссылаются на Points – позиции в мировом пространстве.
Цепочка:
Claude Code последовательно разбирал бинарные структуры и каждый раз что–то новое мешало получить нормальный результат.
Структура FBspNode в версии 76:
После: 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–геометрии.
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 с поиском, чтобы удобнее было навигироваться.
Что получилось
- 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