Learn · frameworks

Что такое Mixin? Объяснение внедрения байт-кода

Mixin — это библиотека для внедрения байт-кода, которая позволяет модам изменять скомпилированные классы Minecraft во время загрузки. Вот как работает внедрение и почему каждому современному моду она необходима.

TRtrolPublished 6 min read

Что такое Mixin в Minecraft?

Mixin — это библиотека для внедрения байт-кода, которая позволяет моду изменять скомпилированные классы Minecraft во время загрузки, не затрагивая при этом исходный код. Мод пишет небольшой класс, который указывает: «вставить этот код в эту точку в этом игровом методе», и Mixin вплетает этот код в байт-код в тот момент, когда JVM загружает целевой класс. Fabric использует его в качестве основного механизма моддинга.

Коротко говоря: Minecraft распространяется в виде скомпилированного Java. Mixin рассматривает эти скомпилированные классы как поверхность, на которой можно строить, и редактирует их в памяти до того, как игра запустит хотя бы один кадр.

Как работает внедрение байт-кода Mixin?

Mixin работает в промежутке между компиляцией и выполнением. Игровой класс уже скомпилирован, но JVM ещё не загрузила его. Это и есть окно, которое использует Mixin. Мод передает загрузчику класс Mixin, аннотированный для нацеливания на реальный игровой класс, и когда этот игровой класс загружается, Mixin переписывает его байт-код на лету, чтобы включить код мода.

Аннотации — это весь секрет. Они не описывают, как выглядит игровой файл построчно. Они описывают куда вам нужно попасть: на вершину метода, к возврату, к конкретному вызову внутри него, к локальной переменной. Mixin находит это место в байт-коде и вшивает ваши инструкции вокруг него.

Это необходимо, потому что Minecraft никогда не создавался для расширения. Для большинства изменений, которые хотят внести моды, отсутствует официальный API плагинов. Mixin — это ответ на эту проблему: если игра не предоставляет вам точку входа, вы вырезаете её сами в скомпилированном коде.

Почему моды используют Mixin вместо непосредственного редактирования игры?

Два фактора определяют всю аргументацию: совместимость и выживание после обновлений.

Если редактировать исходный код игры напрямую, вам придётся распространять полную модифицированную копию Minecraft. Никто другой не сможет строить на основе вашего форка, и он сломается сразу после обновления игры. Mixin-патчи небольшие и точечные, что позволяет десяткам модов одновременно изменять одну и ту же игру, не распространяя при этом полную копию.

ПодходСовмещает работу с другими модамиВыживает после обновления игрыРаспространяется как
Ручное редактирование скомпилированной игрыНет, побеждает один форкНет, ломается при любом измененииПолный модифицированный jar
Внедрение MixinДа, патчи накладываютсяЧасто, если метод сохранилсяНесколько небольших классов

Вторая колонка — это тихая суперспособность. Поскольку Mixin говорит "внедрить здесь" вместо "файл выглядит именно так", многие Mixin-патчи продолжают работать в разных версиях без каких-либо изменений. Это разница между описанием пункта назначения и запоминанием карты.

Как Mixin вписывается в Fabric?

Ткань построена на Mixin, точка. Загрузчик читает конфигурацию mixin каждого мода, собирает классы mixin, указанные в этой конфигурации, и передает их Mixin для применения во время загрузки классов. Вам не нужно вручную настраивать что-либо из этого; объявление ваших mixin-ов в конфигурации — это вся интеграция.

Типичный мод для Fabric состоит в основном из собственных обычных классов, плюс небольшой набор mixin-ов, которые перехватывают лишь те игровые методы, которые ему действительно нужно изменить. Реальная логика мода содержится в обычном коде. Mixin-ы — это лишь тонкий слой, который захватывает управление в нужные моменты.

Какие наиболее распространенные точки внедрения Mixin?

Тип внедрения, который вы выбираете, определяет, насколько агрессивным будет патч и насколько хорошо он будет взаимодействовать с другими модами. Более мягкие изменения безопаснее и устойчивее к обновлениям. Более тяжелые изменения дают вам больше контроля, но за счет хрупкости.

АннотацияЧто она делаетКогда стоит использовать
@InjectЗапускает ваш код в выбранной точке внутри целевого методаПо умолчанию; наименее инвазивный, наиболее устойчивый к обновлениям
@RedirectЗаменяет один конкретный вызов метода внутри целевогоЗаменяет один вызов без переписывания метода
@ModifyArgИзменяет аргумент, передаваемый в вызов внутри целевогоНемного меняет одно значение, поступающее в вызов
@ModifyVariableПереписывает локальную переменную в середине методаКорректирует состояние, которое метод уже вычислил
@OverwriteЗаменяет весь методКрайняя мера; конфликтует с чем-либо еще, что к нему прикасается

@Inject — это основной инструмент, потому что он узкий и вежливый. Он вставляется в точное место и оставляет остальную часть метода нетронутой, что и является причиной того, что он, как правило, выживает при обновлениях и редко конфликтует с другими модами. @Overwrite находится на другом конце: он уничтожает весь метод, поэтому любой другой мод, который также хочет этот метод, теряет. Хорошие Mixin намеренно стараются оставить небольшой след.

Чистая точка введения — ещё одна причина, по которой удаление мода происходит мгновенно. Ничего не было записано в ваши файлы, поэтому удаление мода удаляет все изменения вместе с ним.

Почему Mixin важен для серьезного клиента

Это фундамент, на котором построен Terminus. Премиальный утилитарный клиент выживает или погибает в зависимости от того, насколько чисто он интегрируется в игру, и Mixin делает это возможным, не отправляя изуродованную копию Minecraft. Узкие точки внедрения поддерживают совместимость клиента с уже установленными модами и остаются работоспособными при обновлениях игры, не ломаясь после выхода патча. Понимание Mixin – самый быстрый способ увидеть, почему хорошо разработанный клиент ощущается как часть игры, а не как хрупкое дополнение.

Часто задаваемые вопросы

Получить Terminus

Built on clean Mixin hooks, not a hacked-up jar.