documentation rewrite

Signed-off-by: galeon <dertiellis@gmail.com>
This commit is contained in:
galeon committed 2026-10-11 22:32:13 +03:00
1 parent 1943996608
commit f10b654953
34 files changed
+2099 -4576

No files matched your search

+40 -53
View File
@@ -1,75 +1,62 @@
# zlibreference.h — ZlibReference
# zlibreference.h
## Обзор
`zlibreference.h`, `zlibreference.cpp`
`Minecraft_launcher` умеет ставить модлоадеры Forge и NeoForge, а их установщики — это Java-программы,
которые собирают часть jar-файлов прямо на машине пользователя и сверяют sha1 каждого собранного
файла с эталоном из `install_profile.json`.
Обход одной конкретной проблемы на Linux: Forge и NeoForge не ставятся на системах, где вместо
zlib стоит zlib-ng.
Эталон посчитан на обычном zlib. Дистрибутивы вроде CachyOS и Fedora подставляют вместо него
zlib-ng: сжатие корректное, но побайтово другое — поэтому установка падает на любой версии игры
сообщением «Processor failed, invalid outputs». Сменить Java не выйдет: сборки OpenJDK под Linux
берут `libz.so.1` из системы.
## В чём проблема
`ZlibReference` — обход этой проблемы. Рядом с лаунчером лежит собранный обычный zlib, и процессу
установщика он подсовывается через `LD_PRELOAD`. Системный zlib-ng при этом остаётся на месте:
подмена живёт ровно один процесс.
Установщики Forge и NeoForge собирают часть jar прямо на машине пользователя и сверяют sha1
каждого собранного файла с эталоном из `install_profile.json`. Эталон посчитан на обычном zlib.
CachyOS, Fedora и некоторые другие дистрибутивы ставят вместо него zlib-ng в режиме совместимости.
Он сжимает корректно, но результат побайтово другой. Поэтому установка падает на любой версии игры
с сообщением `Processor failed, invalid outputs`.
Пространство имён используется установщиком модлоадеров при подготовке окружения дочернего
процесса Java.
Другая Java не помогает: сборки OpenJDK под Linux берут `libz.so.1` из системы.
## Пространства имён
## Что сделано
`ZlibReference` группирует три функции: проверку системной библиотеки, поиск собранного эталона и
подготовку окружения процесса. Состояния нет.
В репозитории лежат исходники zlib 1.3.1 (каталог `zlib/`). На Linux CMake собирает из них цель
`launcher_zlib_reference` (`libz.so.1`). В дереве сборки она лежит в `<папка бинарника>/zlib/`, при
установке — в `<prefix>/lib/BiLauncher/`. Сам лаунчер с ней не линкуется. Библиотека
подкладывается через `LD_PRELOAD` только процессу установщика, системный zlib-ng не трогается.
Исходники лежат в репозитории, а не скачиваются при сборке, по двум причинам: сборка не зависит от
сети, и версия зафиксирована. От версии зависит побайтовый результат сжатия.
## Функции
#### bool systemIsZlibNg()
На Windows и macOS все три функции ничего не делают: `systemIsZlibNg()` возвращает `false`,
`bundledPath()` пустую строку, `applyTo()` — `true`.
Отвечает на вопрос, окажется ли `libz.so.1`, который достанется процессу java, библиотекой zlib-ng.
От ответа зависит, нужна ли подмена вообще: на системе с обычным zlib она бессмысленна.
### systemIsZlibNg()
#### QString bundledPath()
Открывает `libz.so.1` через `dlopen`, то есть ту же библиотеку, которую загрузчик выдаст процессу
java, и смотрит, есть ли `zlib-ng` в строке `zlibVersion()`. Результат вычисляется один раз за
запуск.
Путь к собранному рядом эталонному `libz.so.1` или пустая строка, если его нет. Библиотека
собирается целью `launcher_zlib_reference` в `CMakeLists.txt` из исходников каталога `zlib/`,
которые лежат в репозитории, чтобы сборка не зависела от сети, а версия была зафиксирована — от
неё зависит побайтовый результат сжатия. Собирается только на Linux: на Windows и macOS проблемы
подмены системного zlib нет.
### bundledPath()
#### bool applyTo(QProcessEnvironment &env, QString *note = nullptr)
Ищет эталонную библиотеку по порядку:
Дописывает `LD_PRELOAD` в переданное окружение, если подмена нужна. Изменяет `env` на месте.
1. `<applicationDirPath>/zlib/libz.so.1` — запуск из дерева сборки;
2. `<applicationDirPath>/../lib/BiLauncher/libz.so.1` — установленный пакет, tar.gz и AppImage;
3. `LAUNCHER_ZLIB_INSTALL_DIR/libz.so.1` — путь, заданный при конфигурации CMake.
Возвращает `true`, когда окружение готово, — в том числе в случае, когда подменять нечего:
система с обычным zlib или платформа, где вопрос не стоит. `false` означает, что подмена нужна, но
эталонной библиотеки нет на месте.
Второй вариант рассчитан на `CMAKE_INSTALL_LIBDIR=lib`. Поэтому CI на Ubuntu передаёт его явно,
иначе библиотека легла бы в `lib/x86_64-linux-gnu`.
Необязательный параметр `note` заполняется строкой, пригодной и для журнала, и для текста ошибки:
она объясняет, была ли подмена применена и почему.
### applyTo(env, &note)
## Зависимости
- zlib-ng в системе нет — подменять нечего, возвращает `true`, `note` пуст.
- zlib-ng есть, эталон найден — дописывает его путь в начало `LD_PRELOAD` (чужое содержимое
переменной сохраняется), возвращает `true`, в `note` пишет, что подставлено.
- zlib-ng есть, эталона нет — возвращает `false`, в `note` пишет предупреждение.
Подключает `QString`; `QProcessEnvironment` объявлен вперёд и используется только по ссылке.
Реализация опирается на макрос `LAUNCHER_ZLIB_INSTALL_DIR`, который `CMakeLists.txt` определяет на
Linux — это путь установки библиотеки в системе, помимо каталога рядом с исполняемым файлом.
## Пример использования
```cpp
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString note;
if (!ZlibReference::applyTo(env, &note)) {
emit failed(note);
return;
}
QProcess installer;
installer.setProcessEnvironment(env);
installer.start(javaPath, arguments);
```
[ModLoaderInstaller](ModLoaderInstaller.md) пишет `note` в журнал установщика. Если `applyTo()`
вернула `false`, а установщик упал с ошибкой контрольных сумм, к ошибке добавляется прямая
подсказка про zlib-ng.
---