Технический разбор
В этом разделе представлен детальный разбор технических параметров, используемых при работе лаунчера и ServerWrapper для запуска Minecraft, а так же проблем связанных с различными версиями Minecraft и сторонним ПО
Загрузка классов в Minecraft
Для того что бы игру можно было модифицировать, проекты с поддержкой модов пишут и используют библиотеки предоставляющие возможность трансформации классов при загрузке - это необходимо что бы менять поведение игры с помощью модов. На текущий момент есть несколько видов таких библиотек, к каждой из которых нужен свой подход:
launchwrapper
- устарел и не используется так как не поддерживает Java 9+. Он использует простую систему с указанием твиков(аргумент--tweakClass
) которые будут вызваны при запуске и которые добавляют свои трансформеры(классы модифицирующие классы Minecraft). Патч заключается в добавлении классов лаунчера в исключенияRetroFuturaBootstrap
(RFB) - обновленная версияlaunchwrapper
от проекта GTNH для версии 1.7.10 поддерживающая Java 9+ и включающая в себя набор трансформеров для исправления старого легаси кода для работы на актуальных версиях Java. Принцип патча аналогичен - классы лаунчера необходимо добавить в исключенияFoundation
- аналогичныйRetroFuturaBootstrap
проект дляCleanroom
и версии Minecraft 1.12.2. Патч аналогиченRetroFuturaBootstrap
FabricLoader
- механизм поддержки модов отFabric
и работающий на актуальных версиях Java. В отличии от предыдущих не имеет списка исключений и изолирует себя от внешнего мира наследуясь от PlatformClassLoader вместо SystemClassLoader. Патч заключается в делегировании загрузки классов лаунчера SystemClassLoader- Forge 1.16.5
modloader
- проект призванный заменитьlaunchwrapper
в версиях Forge с 1.13 до 1.17/1.18. Патч заключается в испоавлении в нескольких местах родительского ClassLoader и вызовов ServiceLoader - Forge/NeoForge 1.18+ - это набор библиотек
bootstraplauncher
/securejarhandler
/modloader
от cpw пришедший в версии Forge/NeoForge 1.18+ и добавляющий использование модульной системы Java 9+ в загрузку классовbootstraplauncher
подготавливаетBOOT
слой(ModuleLayer) в котором находится он сам и необходимые ему библиотекиsecurejarhandler
реализует загрузчик классов для модульной системыmodloader
реализует оставшуюся логику загрузки модов Forge и создает слоиGAME
иSERVICE
- Патч заключается в добавлении поддержки загрузки классов лаунчера в
securejarhandler
из SystemClassLoader, а так же создании цепочки благодаря которой authlib сможет получить доступ к классам лаунчера и выполнять необходимые ей запросы
Тип LAUNCHER без moduleConf
- Выполняется резолвинг
classpath
: если это директория в classpath включается всё её содержимое - Создается загрузчик классов основанный на URLClassLoader и ему передается полученный
classpath
- Выполняется загрузка библиотек из секции
natives
- Выполняется получение класса и выполнение
compatClasses
с использованием загрузчика классов созданного на предыдущем этапе - Выполняется MainClass
Тип MODULE или LAUNCHER с moduleConf
- Выполняется резолвинг
classpath
: если это директория в classpath включается всё её содержимое - Выполняется резолвинг
modulepath
из секции moduleConf: если это директория в modulepath включается всё её содержимое - Создается ModuleLayer из classpath и modulepath
- Если включена опция
enableHacks
выполняется создание Lookup позволяющего работать с любыми закрытыми/приватными полями без ограничений со стороны Java - Обрабатываются секции
opens
/exports
/reads
разрешая доступ определенным модулям к закрытым частям других модулей. Если модуль к которому нужно разрешить доступ является системным, то с помощью Lookup созданном на предыдущем этапе выполняется создание контроллера для получения доступа - Выполняется загрузка библиотек из секции
natives
- Выполняется получение класса и выполнение
compatClasses
с использованием созданного ModuleLayer - Разрешается доступ к
mainmodule
из лаунчера - Вызывается MainClass
Тип SYSTEM_ARGS
- Выполняется загрузка библиотек из секции
natives
- Выполняется получение класса и выполнение
compatClasses
с использованием SystemClassLoader - Вызывается MainClass
Для чего нужны патчи
Патчи нужны потому что большинство актуальных загрузчиков модов стараются изолироваться от изначального окружения, поскольку несовершенство ванильных лаунчеров и их профилей не позволяют реализовать ту процедуру запуска которую хотят разработчики Forge/Fabric. Цель патчей - дать доступ классам authlib к классам лаунчера находящимся в SystemClassLoader, тогда как загрузчики модов стараются изолироваться от SystemClassLoader. Это справедливо для лаунчера и стандартного режима работы ServerWrapper, так как в этих случаях первым запускаются именно они, настраивают соеденение с лаунчсервером, а лаунчер так же получает аргументы, токены и верифицирует файлы.
Inline режим ServerWrapper
Новый inline режим работы ServerWrapper основан на идее что нам не обязательно загружаться раньше сервера и запускать его, пусть сервер загрузит нас в том же контексте что и authlib - в таком случае authlib без проблем получит доступ к классам. Authlib когда ей впервые необходимо обратится к API лаунчера вызовет класс указанный в launcher.authlib.inlineClass
- так ServerWrapper сможет провести инициализацуию и установить связь с лаунчсервером
CompatClasses
Эта функция возникла из необходимости выыполнить какие то специфичные для клиента действия до MainClass в контексте в котором выполняется MainClass. Лаунчер вызовет все классы указанные в compatClasses до вызова MainClass
FileSystemFixer
Это один из примеров compatClasses используемый для исправления проблемы отсутствия UnionFileSystemProvider при запуске Forge 1.18+. При запуске он добавит провайдеры типа FileSystemProvider из своего текущего контекста в приватный кеш FileSystemProvider Java, исправляя таким образом эту ошибку.