1. Инструменты реверс-инжиниринга: Сравнение и настройка dnSpy и ILSpy
Инструменты реверс-инжиниринга: Сравнение и настройка dnSpy и ILSpy
Пятьдесят гигабайт ассетов, текстур и звуков формируют визуальную оболочку Pathfinder: Wrath of the Righteous, но истинные правила игры — формулы урона, логика искусственного интеллекта, условия квестов — заперты в единственном файле размером около 80 мегабайт. Этот файл называется Assembly-CSharp.dll. Вы не можете открыть его в обычном текстовом редакторе, а без понимания того, как работают оригинальные механики, создание модификаций сводится к слепому копированию чужого кода. Чтобы получить доступ к исходной логике (Ground Truth), необходимо перевести машиночитаемый формат обратно в человекочитаемый код.
Иллюзия компиляции: Почему код Unity открыт как книга
Разработка игр на движке Unity (особенно старых версий, использующих Mono-бэкенд) имеет фундаментальную особенность. Когда программисты Owlcat Games писали код на C# и нажимали кнопку сборки, компилятор не переводил текст напрямую в нули и единицы, понятные процессору. Вместо этого код транслировался в промежуточный язык — CIL (Common Intermediate Language, часто называемый просто IL).
IL — это низкоуровневый набор инструкций, который сохраняет колоссальное количество метаданных об исходном коде. Внутри Assembly-CSharp.dll хранятся точные названия всех классов, методов, полей, а также структура их взаимосвязей. При запуске игры среда выполнения (в нашем случае Mono) считывает эти IL-инструкции и на лету компилирует их в машинный код с помощью JIT-компилятора (Just-In-Time).
Декомпилятор выполняет обратный процесс. Он читает IL-инструкции и метаданные, применяет паттерны распознавания и восстанавливает исходный C#-код.
!Процесс трансляции и потери данных при декомпиляции
Результат декомпиляции не является побайтовой копией того, что писали разработчики. Комментарии удаляются на этапе компиляции, а имена локальных переменных внутри методов часто теряются (если к сборке не приложен файл отладочных символов .pdb). Однако архитектура, логика ветвлений и математические операции восстанавливаются с точностью до 99%. Для моддера этого более чем достаточно, чтобы понять, как работает любая механика, и написать для неё Harmony-патч.
Выбор инструмента: dnSpy против ILSpy
В арсенале реверс-инженера .NET есть два главных инструмента. Исторически сложилось так, что моддеры начинают использовать один из них и игнорируют второй. Это стратегическая ошибка. dnSpy и ILSpy — не взаимоисключающие конкуренты, а инструменты с разной специализацией.
ILSpy: Аналитик и реставратор
ILSpy — это активно развивающийся open-source проект. Его главное преимущество заключается в современном движке декомпиляции. Язык C# постоянно эволюционирует: появляются локальные функции, switch-выражения, сложные паттерны сопоставления. ILSpy умеет распознавать эти современные конструкции в IL-коде и восстанавливать их в лаконичный, легко читаемый C#.Особенно ярко это проявляется при работе с асинхронным кодом и корутинами (coroutines), которые в Unity используются повсеместно. На уровне IL корутина превращается в сложную конечную автоматную машину (state machine) с десятками переходов. ILSpy распознает этот паттерн и сворачивает его обратно в аккуратный метод с операторами yield return.
Вердикт: ILSpy используется для чтения кода, статического анализа и поиска связей. Это ваша основная библиотека.
dnSpy (и dnSpyEx): Хирург и отладчик
Оригинальный dnSpy был заброшен автором, но сообщество поддерживает форк под названием dnSpyEx. Движок декомпиляции dnSpy безнадежно устарел. Он часто не справляется с современным синтаксисом C#, выдавая полотна нечитаемого спагетти-кода при попытке разобрать генераторы или асинхронные методы.Однако у dnSpy есть две киллер-фичи, которых нет у ILSpy:
Вердикт: dnSpy используется исключительно для динамического анализа (отладки) и точечных инъекций при прототипировании.
Подготовка среды: Загрузка Assembly-CSharp.dll
Первый шаг к изучению анатомии игры — правильная загрузка библиотек в декомпилятор.
Assembly-CSharp.dll в WotR весит около 80 МБ. В развернутом виде, с построенными индексами и абстрактными синтаксическими деревьями, декомпилятору потребуется более 2 ГБ оперативной памяти. Если вы запустите 32-битную версию инструмента, процесс упрется в архитектурный лимит выделения памяти (около байт) и упадет с ошибкой OutOfMemoryException. Всегда используйте 64-битные версии (ILSpy.exe или dnSpy.exe, а не их x86 аналоги).Pathfinder Wrath Of The Righteous\Wrath_Data\Managed\Assembly-CSharp.dll.UnityEngine.CoreModule.dll), если они лежат в той же папке Managed. Если вы скопируете Assembly-CSharp.dll на рабочий стол и откроете оттуда, декомпилятор не найдет зависимости. Многие типы будут подсвечены красным, а статический анализ сломается. Всегда открывайте DLL прямо из папки игры.Статический анализ: Искусство навигации по коду
Читать 80 мегабайт кода сверху вниз бессмысленно. Реверс-инжиниринг — это движение от известного к неизвестному.
Поиск по строкам и типам
Самый простой способ найти механику — искать текстовые константы. Если в игре есть способность "Cleave", логично нажатьCtrl+F в ILSpy и искать тип или член класса с таким именем. Декомпиляторы позволяют фильтровать поиск: искать только классы (Types), только методы (Members) или только константы (Constants).Инструмент Analyzer (Анализатор)
Поиск по имени дает вам конкретный класс, напримерRuleDealDamage, который отвечает за применение урона. Но как узнать, кто вызывает этот урон? Когда он применяется? Для этого используется Анализатор (вызывается правой кнопкой мыши по классу или методу -> Analyze).!Дерево зависимостей в окне Analyzer
Анализатор строит граф зависимостей на основе IL-инструкций. Ключевые узлы графа:
HP и хотите узнать, где игра отнимает здоровье, вы смотрите узел "Assigned By", который покажет все места в коде, где в это поле записывается новое значение.Архитектура данных: Введение в BlueprintCatalog
Исследуя код WotR, вы быстро заметите паттерн: логика отделена от данных. Классы вроде RuleDealDamage содержат только математику (как вычесть броню из атаки). Но где хранятся сами параметры? Сколько базового урона наносит огненный шар? Какой радиус у ауры паладина?
Вся база данных игры построена на системе Блюпринтов (Blueprints). Блюпринт — это сериализованный объект данных, наследник SimpleBlueprint. При запуске игры тысячи блюпринтов загружаются в оперативную память и помещаются в глобальный реестр — BlueprintCatalog.
В ILSpy вы можете найти статический класс Kingmaker.Blueprints.ResourcesLibrary. Это сердце системы данных. Метод TryGetBlueprint<T>(string assetId) — это то, как игра извлекает данные. Каждый блюпринт имеет уникальный идентификатор (Asset ID, он же GUID), представляющий собой 32-значную строку.
Если вы хотите изменить параметры заклинания, вам не нужно патчить код через Harmony. Вам нужно найти блюпринт этого заклинания в BlueprintCatalog и изменить его поля. Но как узнать GUID конкретного заклинания среди десятков тысяч других? Здесь статический анализ бессилен, и в дело вступает динамический поиск.
Мост между игрой и кодом: ToyBox Search 'n Pick
Для поиска конкретных данных (Ground Truth) моддеры используют инструмент, созданный самим сообществом — мод ToyBox. Это швейцарский нож, который имеет доступ к рантайму игры.
Вкладка Search 'n Pick в ToyBox — это интерфейс прямого доступа к BlueprintCatalog.
BlueprintAbility) и его GUID (например, 4ac47ddb9fa1eaf43a1b6809980cfbd2).Получив эту информацию, алгоритм действий замыкается:
BlueprintAbility, открываете ILSpy, находите этот класс и изучаете, какие поля в нем есть (урон, радиус, тип магии).Динамический анализ: Подключение отладчика dnSpy
Иногда статический анализ в ILSpy заходит в тупик. Код WotR активно использует интерфейсы, абстрактные классы и систему событий (Event Bus). Если вы анализируете метод OnEventAboutToTrigger, Анализатор может показать, что этот метод вызывается через абстрактный интерфейс IUnitSubscriber. Найти конкретное место вызова статически становится невозможно — связь формируется только во время выполнения игры.
В этот момент мы закрываем ILSpy и открываем dnSpy для динамического анализа.
!Подключение отладчика dnSpy к процессу Unity
Процесс перехвата управления:
Debug -> Attach to Process.Wrath.exe. Убедитесь, что тип отладчика установлен на Unity (Mono). Нажмите Attach.RuleDealDamage.OnTrigger).Теперь вернитесь в игру и совершите действие, которое должно вызвать этот код (ударьте противника). В ту же миллисекунду игра намертво зависнет. Окно dnSpy выйдет на передний план, а строка с точкой останова подсветится желтым.
Вы поймали игру за руку. В нижней панели Locals (Локальные переменные) вы увидите точное состояние оперативной памяти в этот момент: кто атакует, кто защищается, какие баффы висят на персонажах, чему равен бросок кубика. Вы можете выполнять код пошагово (клавиша F10), наблюдая, как игра проходит по ветвлениям if/else. Это абсолютный Ground Truth — вы видите не то, как код должен работать, а то, как он работает прямо сейчас.
Комбинируя статический анализ архитектуры в ILSpy, поиск данных через ToyBox и динамическую отладку в dnSpy, вы получаете полный контроль над движком. Любая механика становится прозрачной, а поиск места для внедрения вашей модификации превращается из угадывания в точную инженерную задачу.