Table of Contents

Патчинг кода игры

В этом руководстве вы научитесь патчить код игры.

Что такое патчи?

Патчи - это способ изменить поведение игры без прямого изменения исходного кода. В контексте WorldMachineLoader, патчи позволяют модам изменять или дополнять поведение методов игры с помощью аннотации/атрибута [GamePatch].

Как работают патчи?

Система патчей в WML основана на атрибутах и отражении (reflection). При запуске загрузчика:

  1. Все методы, помеченные атрибутом [GamePatch], обнаруживаются автоматически.
  2. Эти методы обрабатываются классом PatchManager в загрузчике и применяются к соответствующим методам игры.
  3. Патчи могут быть приватными и публичными, но они ДОЛЖНЫ быть статичными.
  4. Каждый патч применяется один раз, и только при загрузке.

Как узнать что именно надо запатчить?

Для определения того, какие части кода игры необходимо патчить, потребуется использовать декомпилятор. По очевидным причинам, выкладывать исходный код игры публично КАТЕГОРИЧЕСКИ запрещено. Так что вы сами должны воспользоваться декомпилятором по типу ILSpy (рекомендую), dnSpy, или встроенный декомпилятор в Visual Studio 2022. С его помощью можно проанализировать исходный код игры, выявить нужные участки для модификации и подготовить соответствующие патчи.

Что можно патчить?

  • Любые публичные/приватные методы классов игры.
  • Статические и нестатические методы.
  • Один и тот же метод может быть пропатчен несколькими модами.

Пример простого патча

using OneShotMG;

public class MyMod : IMod
{
    [GamePatch(typeof(Game1), "Initialize", PatchType.Prefix)]
    public static void GameInit_Patch()
    {
        Console.WriteLine("Game starts to initialize!");
    }
}

В данном примере мы патчим метод Initialize класса Game1 с типом патча Prefix. Теперь давайте рассмотрим существующие типы патчей.

Типы патчей

На данный момент существует 4 типа патчей: Prefix, Postfix, Transpiler и Finalizer. Давайте поговорим о том, что делает каждый тип.

  1. Prefix:
    • Выполняется до оригинального метода. Позволяет изменить входные аргументы или отменить вызов оригинального, вернув false.
  2. Postfix:
    • Выполняется после оригинального метода. Даёт доступ к возвращаемому значению и позволяет его изменить перед передачей дальше.
  3. Transpiler:
    • Изменяет IL-код метода. Позволяет вставлять, удалять или заменять инструкции на низком уровне.
  4. Finalizer:
    • Вызывается после выполнения оригинала и всех Postfix. Может обрабатывать исключения, возникшие в оригинальном методе, и выполнять финализирующие действия.

Скорее всего, для создания мода вам пригодятся только Prefix, Postfix, и иногда Finalizer.

Патчинг метода с аргументами

Патчинг метода с аргументами происходит немного иначе. Так как у метода могут быть перегрузки, при создании патча с атрибутом [GamePatch] добавляется ещё один аргумент - argumentTypes. Даже если у метода нет перегрузок, argumentTypes всё равно нужно указывать.

[GamePatch(typeof(TWMFilesystem), "CreateWallpaperFile", PatchType.Prefix, typeof(string))]
public static void CreateWallpaperFile_Patch(string wallpaperId)
{
    Console.WriteLine($"Wallpaper ID: {wallpaperId}");
}

В данном примере мы патчим метод CreateWallpaperFile класса TWMFilesystem, который имеет аргумент типа string.