Инструментарий разработчика: Конфигурация IDE и системные зависимости .NET
Скомпилированный мод скопирован в папку игры, Pathfinder: Wrath of the Righteous запущен, но ничего не происходит. В логах Unity Mod Manager (UMM) нет ни ошибок, ни предупреждений — игра просто проигнорировала файл. Причина кроется не в логике C#-кода, а в фундаментальном несовпадении сред выполнения. Бинарный файл собран с параметрами, которые игровой движок не способен прочитать.
Анатомия среды выполнения WotR
Pathfinder: Wrath of the Righteous базируется на движке Unity версии 2020.3. За выполнение скриптов и серверной логики отвечает бэкенд Mono, который жестко привязан к стандарту .NET Framework 4.7.2.
Экосистема .NET разделена на две несовместимые на бинарном уровне ветви:
- .NET Framework (версии до 4.8) — монолитная архитектура, на которой работает большинство игр на Unity прошлых лет.
- .NET Core / .NET 5+ — современная кроссплатформенная архитектура.
Если при создании проекта использовать современный .NET 8, компилятор создаст библиотеку с метаданными, непонятными среде выполнения WotR. Движок не найдет ожидаемых сигнатур старого стандарта и молча прервет загрузку мода. Задача разработчика — заставить современную IDE работать по правилам устаревшего .NET Framework 4.7.2.
Настройка рабочей среды в JetBrains Rider (Windows 11)
Для разработки в ОС Windows 11 с использованием JetBrains Rider наличия самой IDE недостаточно. Операционной системе требуется пакет разработчика (Developer Pack) для целевой версии фреймворка.
Среда выполнения (Runtime) позволяет только запускать готовые программы. Пакет разработчика содержит эталонные сборки (Reference Assemblies) и заголовочные файлы, необходимые Rider для проверки синтаксиса и компиляции. Если пакет для 4.7.2 отсутствует в системе, Rider не предложит эту версию в диалоге создания проекта. Скачать .NET Framework 4.7.2 Developer Pack необходимо с официального сайта Microsoft.
Инициализация проекта
Мод для WotR — это динамически подключаемая библиотека (DLL), встраиваемая в адресное пространство игры загрузчиком UMM. В коде отсутствует стандартная точка входа static void Main().
Процесс создания базового репозитория в JetBrains Rider:
- Выберите New Solution.
- В левом меню выберите шаблон Class Library.
- В поле Framework строго укажите .NET Framework 4.7.2. Игнорируйте любые шаблоны с пометкой .NET, .NET Core или .NET Standard.
- Задайте имя проекта без пробелов, используя PascalCase (например,
WotrHelloMod). Это имя станет названием итогового DLL-файла и корневым пространством имен.
Эталонная конфигурация .csproj
Вместо ручного переключения параметров через графический интерфейс Rider (свойства сборки, целевую платформу, копирование локальных файлов), профессиональный моддинг требует прямого редактирования файла конфигурации проекта — .csproj.
Современный подход использует SDK-style формат файла. Он лаконичен, скрывает дефолтные настройки MSBuild и автоматически управляет рутинными процессами. Чтобы открыть его в Rider, дважды кликните по названию проекта в окне Solution Explorer.
Ниже представлен эталонный листинг .csproj для базового мода. Замените содержимое вашего файла этим кодом.
<Project Sdk="Microsoft.NET.Sdk">
<!-- Блок базовых свойств компиляции -->
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<AssemblyName>WotrHelloMod</AssemblyName>
<RootNamespace>WotrHelloMod</RootNamespace>
<LangVersion>latest</LangVersion>
<!-- Жесткая фиксация архитектуры -->
<PlatformTarget>x64</PlatformTarget>
<!-- Настройки генерации отладочной информации -->
<DebugSymbols>true</DebugSymbols>
<DebugType>portable</DebugType>
<Optimize>false</Optimize>
</PropertyGroup>
<!-- Блок подключения игровых зависимостей -->
<ItemGroup>
<Reference Include="Assembly-CSharp">
<!-- Путь к оригинальной библиотеке игры -->
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Pathfinder Second Adventure\Wrath_Data\Managed\Assembly-CSharp.dll</HintPath>
<!-- Запрет на копирование библиотеки в папку мода -->
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Pathfinder Second Adventure\Wrath_Data\Managed\UnityEngine.dll</HintPath>
<Private>False</Private>
</Reference>
<!-- Библиотека загрузчика модов -->
<Reference Include="UnityModManager">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Pathfinder Second Adventure\UnityModManager\UnityModManager.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
</Project>
Разбор параметров: Целевая архитектура (x64)
Строка <PlatformTarget>x64</PlatformTarget> отвечает за архитектуру итогового бинарного файла.
Pathfinder: WotR — ресурсоемкая игра. 32-битный процесс в Windows ограничен адресным пространством в байт (ровно 4 ГБ оперативной памяти). Для современных RPG с тысячами блюпринтов и тяжелыми ассетами этого критически мало, поэтому движок скомпилирован исключительно под 64-битную архитектуру.
По умолчанию Rider использует значение AnyCPU. При такой настройке JIT-компилятор (Just-In-Time) среды выполнения сам решает, как развернуть код в памяти. Однако мод тесно взаимодействует с нативными библиотеками Unity, написанными на C++. Использование AnyCPU часто приводит к конфликтам при линковке памяти.
Если компилятор создаст 32-битную DLL (), при попытке внедрения в 64-битный процесс WotR загрузчик выбросит фатальное исключение BadImageFormatException. Жесткая фиксация <PlatformTarget>x64</PlatformTarget> гарантирует побайтовое соответствие вашей DLL адресному пространству игры.
Золотое правило зависимостей: Тег Private
Блок <ItemGroup> содержит ссылки (References) на оригинальные библиотеки. Чтобы мод мог изменить характеристики оружия или добавить реплику, компилятору необходимо знать структуру классов WotR. Главная библиотека с логикой игры — Assembly-CSharp.dll, логика движка — UnityEngine.dll, а API загрузчика — UnityModManager.dll.
Критический элемент конфигурации — тег <Private>False</Private>. В графическом интерфейсе IDE этот параметр называется Copy Local (Копировать локально).
По умолчанию при добавлении ссылки на стороннюю библиотеку IDE устанавливает этот параметр в True. Логика стандартной разработки: «взять этот DLL-файл и скопировать его в папку с готовым проектом, чтобы программа гарантированно нашла свои зависимости при запуске на другом компьютере».
В контексте моддинга копирование игровых библиотек должно быть строго отключено.
Ваш мод загружается внутрь уже работающей игры. В изолированной области оперативной памяти (AppDomain) уже загружены все оригинальные DLL. Если мод принесет в своей папке собственные копии этих гигантских файлов (размер Assembly-CSharp.dll превышает 40 МБ), загрузчик попытается поместить их в память второй раз.
Следствия дублирования библиотек в памяти:
- Конфликт пространств имен. Система не понимает, из какой версии файла инстанцировать класс.
- Ошибки приведения типов. Объект
UnitEntityData, созданный игрой из оригинальной DLL, не будет равен объектуUnitEntityData, который ожидает ваш мод из скопированной DLL. ВозникаетInvalidCastException. - Мгновенный краш. Игра зависает на стартовом экране с полосой загрузки.
Тег <Private>False</Private> сообщает Rider: «Используй эти файлы исключительно для проверки синтаксиса и автодополнения кода во время разработки, но не прикрепляй их к итоговому артефакту сборки».
Подготовка к публикации на GitHub
Для создания качественного базового репозитория жестко закодированные пути в <HintPath> (например, C:\Program Files (x86)\...) являются плохой практикой. Если другой разработчик клонирует ваш репозиторий, а игра у него установлена на диске D:\Games, проект не скомпилируется.
Для решения этой проблемы пути к зависимостям заменяются на переменные окружения или относительные пути. В WotR-моддинге стандартом де-факто стало использование системной переменной, например $(WOTR_PATH).
Модифицированный блок зависимости будет выглядеть так:
<Reference Include="Assembly-CSharp">
<HintPath>$(WOTR_PATH)\Wrath_Data\Managed\Assembly-CSharp.dll</HintPath>
<Private>False</Private>
</Reference>
Перед компиляцией достаточно добавить переменную WOTR_PATH в настройки Windows, указав путь к корневой папке игры. Это делает ваш .csproj универсальным и готовым к командной разработке.
Конфигурации сборки: Влияние на Harmony-патчи
В верхней панели Rider находится переключатель конфигураций сборки. В эталонном .csproj параметры <DebugSymbols>, <DebugType> и <Optimize> настроены для режима отладки (Debug).
| Характеристика | Debug (Отладка) | Release (Релиз) |
|---|---|---|
| Оптимизация кода | Отключена (<Optimize>false</Optimize>). |
Включена (<Optimize>true</Optimize>). JIT-компилятор перестраивает IL-код. |
| Генерация PDB | Создается полный .pdb файл (Program Database). |
Файл не создается или создается в урезанном виде. |
| Влияние на Harmony | Патчи работают стабильно. | Высокий риск отказа патчей из-за Inlining-а. |
Проблема Inlining (Встраивания методов):
В режиме Release компилятор стремится ускорить выполнение кода. Если метод небольшой, JIT-компилятор может применить оптимизацию Inlining — он берет тело метода и встраивает его напрямую в место вызова, уничтожая сам факт вызова оригинального метода в памяти.
Библиотека Harmony, которая является стандартом для изменения механик WotR, работает путем перехвата адресов методов в оперативной памяти. Если метод был «встроен» компилятором, его адрес исчезает. Harmony рапортует об успешном патче, но ваш код никогда не выполняется. Именно поэтому на этапе разработки и тестирования механик тег <Optimize>false</Optimize> абсолютно необходим.
Важность PDB-файла:
Когда в логике мода возникает ошибка (например, NullReferenceException), Unity Mod Manager перехватывает ее и пишет в лог. Если рядом с WotrHelloMod.dll в папке мода находится файл WotrHelloMod.pdb, менеджер сможет расшифровать стек вызовов и указать точный номер строки в вашем C#-коде. Формат <DebugType>portable</DebugType> является кроссплатформенным стандартом, который корректно считывается парсером логов UMM.
Настроенный таким образом проект генерирует пустую, но архитектурно безупречную библиотеку. Среда разработки синхронизирована с движком Unity, зависимости изолированы, а репозиторий готов к версионированию. База заложена.