1 parent
1943996608
commit
f10b654953
34 files changed
+2099
-4576
No files matched your search
+74
-107
@@ -1,135 +1,102 @@
|
||||
# minecraftversion.h — MinecraftVersion и VersionLoader
|
||||
# minecraftversion.h
|
||||
|
||||
## Обзор
|
||||
`minecraftversion.h`, `minecraftversion.cpp`
|
||||
|
||||
Каждая версия Minecraft описывается файлом `versions/<id>/<id>.json` — в нём главный класс,
|
||||
аргументы запуска, список библиотек, индекс ресурсов и требуемая версия Java. Файлы образуют
|
||||
цепочку: профиль модлоадера наследуется от версии игры через поле `inheritsFrom`, а та, в свою
|
||||
очередь, может наследоваться дальше.
|
||||
Чтение описаний версий из `<gameDir>/versions/<id>/<id>.json` и всё, что с ними связано: правила
|
||||
Mojang, нативные библиотеки под текущую платформу, список установленного, удаление.
|
||||
|
||||
Заголовок `minecraftversion.h` даёт две вещи: структуры, описывающие версию в разобранном виде, и
|
||||
пространство имён `VersionLoader` — чтение, разворачивание цепочки наследования и работа с
|
||||
установленными версиями на диске.
|
||||
Профиль модлоадера обычно содержит только отличия от базовой версии и ссылается на неё через
|
||||
`inheritsFrom`. `VersionLoader::load()` проходит эту цепочку и сводит её в одну структуру
|
||||
`MinecraftVersion`, с которой уже работают [GameLauncher](GameLauncher.md) и
|
||||
[VersionInstaller](VersionInstaller.md).
|
||||
|
||||
Заголовок подключают [GameLauncher](GameLauncher.md) (собирает из версии командную строку),
|
||||
[VersionInstaller](VersionInstaller.md) (по списку библиотек понимает, что качать) и
|
||||
[LauncherBackend](LauncherBackend.md) (проверяет комплектность и удаляет версии).
|
||||
## MinecraftLibrary
|
||||
|
||||
## Типы
|
||||
Одна библиотека, к которой уже применены правила.
|
||||
|
||||
| Имя | Вид | Описание |
|
||||
|-----|-----|----------|
|
||||
| `MinecraftLibrary` | `struct` | Одна библиотека из `client.json` с уже разрешёнными правилами |
|
||||
| `MinecraftVersion` | `struct` | `client.json`, «схлопнутый» по всей цепочке `inheritsFrom` |
|
||||
| Поле | Что это |
|
||||
|------|---------|
|
||||
| `name` | Maven-координаты, например `org.lwjgl:lwjgl:3.3.1:natives-windows` |
|
||||
| `path` | путь относительно `libraries/` |
|
||||
| `url` | откуда качать; может быть пустым |
|
||||
| `sha1`, `size` | для проверки; могут отсутствовать |
|
||||
| `native` | распаковывается в `natives`, в classpath не идёт |
|
||||
| `extractExclude` | префиксы путей внутри jar, которые не распаковываются |
|
||||
|
||||
### MinecraftLibrary
|
||||
## MinecraftVersion
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| `name` | `QString` | Maven-координаты, например `org.lwjgl:lwjgl:3.3.1:natives-windows` |
|
||||
| `path` | `QString` | Путь относительно `.minecraft/libraries` |
|
||||
| `url` | `QString` | Откуда качать, если файла нет; может быть пустым — тогда файл должен уже лежать на месте |
|
||||
| `sha1` | `QString` | Контрольная сумма для проверки скачанного |
|
||||
| `size` | `qint64` | Размер в байтах; `0` — неизвестен |
|
||||
| `native` | `bool` | Библиотека распаковывается в `natives`, а не кладётся в classpath |
|
||||
| `extractExclude` | `QStringList` | Префиксы путей внутри архива, которые не распаковываются |
|
||||
| Поле | Что это |
|
||||
|------|---------|
|
||||
| `id` | имя папки в `versions/` |
|
||||
| `mainClass` | |
|
||||
| `type` | `release`, `snapshot` и т. д.; по умолчанию `release` |
|
||||
| `assetIndexId` | id индекса ресурсов |
|
||||
| `assetsKind` | поле `assets`: `legacy`, `pre-1.6` или тот же id |
|
||||
| `clientJarPath` | абсолютный путь к клиентскому jar; часто это jar родителя |
|
||||
| `javaMajor` | из `javaVersion.majorVersion`; по умолчанию 8 |
|
||||
| `jvmArgs`, `gameArgs` | с ещё не подставленными `${...}` |
|
||||
| `libraries` | |
|
||||
| `loggingArgument`, `loggingConfigPath` | аргумент log4j и путь к его xml в `assets/log_configs` |
|
||||
| `supportsQuickPlay` | среди аргументов игры есть `quickPlayMultiplayer` (1.20+) |
|
||||
| `hasCustomResolutionArgs` | описание само передаёт `resolution_width` |
|
||||
|
||||
### MinecraftVersion
|
||||
`isValid()` возвращает `true`, если заданы `id` и `mainClass`.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| `id` | `QString` | Имя папки в `versions`, оно же значение аргумента `--version` |
|
||||
| `mainClass` | `QString` | Главный класс, который запускает java |
|
||||
| `type` | `QString` | `release`, `snapshot` или `modified`; идёт в `--versionType` |
|
||||
| `assetIndexId` | `QString` | Идентификатор индекса ресурсов для `--assetIndex` |
|
||||
| `assetsKind` | `QString` | Поле `assets` версии: `legacy`, `pre-1.6` либо тот же идентификатор |
|
||||
| `clientJarPath` | `QString` | Абсолютный путь к `<id>.jar`; может лежать у родительской версии |
|
||||
| `javaMajor` | `int` | Требуемая мажорная версия Java; по умолчанию `8` |
|
||||
| `jvmArgs` | `QStringList` | Аргументы JVM ещё с неподставленными подстановками вида `${...}` |
|
||||
| `gameArgs` | `QStringList` | Аргументы игры, тоже с неподставленными подстановками |
|
||||
| `libraries` | `QList<MinecraftLibrary>` | Библиотеки версии с уже применёнными правилами |
|
||||
| `loggingArgument` | `QString` | Аргумент вида `-Dlog4j.configurationFile=${path}` |
|
||||
| `loggingConfigPath` | `QString` | Абсолютный путь к xml-конфигурации журнала; пуст, если конфигурации нет |
|
||||
| `supportsQuickPlay` | `bool` | Версия 1.20 и новее понимает `--quickPlayMultiplayer` — так лаунчер подключается к серверу сразу при запуске |
|
||||
| `hasCustomResolutionArgs` | `bool` | Версия принимает аргументы размера окна |
|
||||
## Как сводится цепочка
|
||||
|
||||
Метод `isValid()` возвращает `true`, когда заполнены и `id`, и `mainClass`: именно этим проверяется
|
||||
успешность чтения версии.
|
||||
`load(gameDir, versionId, features, &error)` идёт от запрошенной версии к родителям по
|
||||
`inheritsFrom`. Ограничения: не больше 10 звеньев, без циклов. Если файл отсутствует или не
|
||||
разбирается, это ошибка, и возвращается невалидный объект.
|
||||
|
||||
## Функции
|
||||
Дальше поля применяются от корня к потомку:
|
||||
|
||||
Пространство имён `VersionLoader`.
|
||||
- `mainClass`, `type`, `assets`, `assetIndex`, `javaVersion`, `logging` — потомок перекрывает
|
||||
родителя;
|
||||
- `minecraftArguments` (старый формат, одна строка) **заменяет** `gameArgs` целиком;
|
||||
- `arguments.jvm` и `arguments.game` (новый формат) **дописываются** к тому, что дал родитель.
|
||||
|
||||
#### QStringList installedVersions(const QString &gameDir)
|
||||
Библиотеки собираются в обратном порядке, от потомка к корню. Повторы убираются по ключу
|
||||
`группа:артефакт[:классификатор]`, без версии. Поэтому если Forge приносит свою версию библиотеки,
|
||||
она вытесняет ванильную.
|
||||
|
||||
Версии, реально установленные в `<gameDir>/versions`: есть и папка, и файл `<id>.json`. Одной
|
||||
только папки недостаточно — она остаётся после неудачной установки.
|
||||
Если среди JVM-аргументов нет `-cp`, значит это старая версия без блока `arguments.jvm`. Тогда
|
||||
добавляются аргументы, которые официальный лаунчер подставляет сам: `-Djava.library.path`, бренд и
|
||||
версия лаунчера, `-cp ${classpath}`.
|
||||
|
||||
#### QStringList dependentsOf(const QString &gameDir, const QString &versionId)
|
||||
Клиентский jar берётся первый найденный по цепочке, от потомка к корню. Если его нет нигде,
|
||||
указывается путь у корня. `GameLauncher::missingFiles()` потом скажет, что его не хватает.
|
||||
|
||||
Установленные профили, у которых `inheritsFrom` равен `versionId`. Без базовой версии они не
|
||||
запустятся, поэтому список показывается пользователю перед удалением версии.
|
||||
`features` нужен для правил вида `"features": {"has_custom_resolution": true}`. Бэкенд передаёт
|
||||
`has_custom_resolution`, если в настройках задан размер окна.
|
||||
|
||||
#### qint64 installedSize(const QString &gameDir, const QString &versionId)
|
||||
## Правила и натив
|
||||
|
||||
Размер `<gameDir>/versions/<id>` в байтах; `0`, если папки нет. Используется в предупреждении об
|
||||
удалении — версия весит десятки мегабайт, и стоит показать, сколько освободится.
|
||||
`rulesAllow(rules, features)` реализует алгоритм Mojang: правила проверяются по порядку,
|
||||
действует последнее совпавшее; пустой список означает «разрешено». Правило совпадает, если подошли
|
||||
`features`, `os.name`, `os.arch` и регулярное выражение `os.version` (сверяется с
|
||||
`QSysInfo::productVersion()`).
|
||||
|
||||
#### bool remove(const QString &gameDir, const QString &versionId, QString \*error)
|
||||
Нативные библиотеки встречаются в двух форматах:
|
||||
|
||||
Сносит `<gameDir>/versions/<id>`. Отсутствие папки считается успехом. При неудаче возвращает
|
||||
`false` и заполняет `error`.
|
||||
- старый: блок `natives` с классификатором под ОС, `${arch}` заменяется на `32` или `64`;
|
||||
- новый (LWJGL 3.3+): отдельные библиотеки с классификатором `natives-<ос>[-<арх>]`.
|
||||
|
||||
Библиотеки и ресурсы в `libraries/` и `assets/` не трогаются: они общие для всех версий.
|
||||
`pickNativesForCurrentArch()` оставляет для каждого артефакта один классификатор. Лучше всего
|
||||
точный (`nativeClassifier()`, например `natives-macos-arm64`), потом общий для ОС
|
||||
(`natives-macos`), потом какой попадётся.
|
||||
|
||||
#### MinecraftVersion load(const QString &gameDir, const QString &versionId, const QSet<QString> &features, QString \*error)
|
||||
`osName()` возвращает `windows`, `osx` или `linux`. `osArch()` возвращает архитектуру из
|
||||
`QSysInfo`, причём `i386` и `i686` сводятся к `x86`.
|
||||
|
||||
Читает версию и разворачивает всю цепочку `inheritsFrom` в один объект. Параметр `features` —
|
||||
набор включённых возможностей, влияющих на применение правил (например, запрошен ли пользовательский
|
||||
размер окна).
|
||||
## Установленные версии
|
||||
|
||||
При ошибке возвращает объект, у которого `isValid()` даёт `false`, и заполняет `error`.
|
||||
|
||||
#### bool rulesAllow(const QJsonArray &rules, const QSet<QString> &features = {})
|
||||
|
||||
Стандартный алгоритм Mojang для блоков `rules`: правила применяются по порядку, побеждает последнее
|
||||
совпавшее. Используется и для библиотек, и для аргументов запуска.
|
||||
|
||||
#### QString nativeClassifier()
|
||||
|
||||
Классификатор нативных библиотек для текущей машины: `natives-windows`, `natives-macos-arm64`,
|
||||
`natives-linux` и подобные. По нему из списка библиотек отбираются те, что нужно распаковать.
|
||||
|
||||
#### QString osName()
|
||||
|
||||
Имя операционной системы в терминах Mojang — оно подставляется в правила и аргументы.
|
||||
|
||||
#### QString osArch()
|
||||
|
||||
Архитектура в терминах Mojang.
|
||||
|
||||
## Зависимости
|
||||
|
||||
Подключает `QJsonArray`, `QList`, `QSet`, `QString` и `QStringList` — только Qt Core. От классов
|
||||
проекта не зависит.
|
||||
|
||||
## Пример использования
|
||||
|
||||
```cpp
|
||||
QString error;
|
||||
const MinecraftVersion version = VersionLoader::load(gameDir, versionId, features, &error);
|
||||
if (!version.isValid()) {
|
||||
emit launchError(error);
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList classpath;
|
||||
for (const MinecraftLibrary &library : version.libraries) {
|
||||
if (!library.native)
|
||||
classpath << gameDir + "/libraries/" + library.path;
|
||||
}
|
||||
classpath << version.clientJarPath;
|
||||
```
|
||||
- `installedVersions(gameDir)` — подпапки `versions/`, в которых есть `<id>.json`, по алфавиту.
|
||||
- `dependentsOf(gameDir, id)` — установленные профили с `inheritsFrom == id`. Без базовой версии они
|
||||
не запустятся, поэтому их перечисляют в предупреждении об удалении.
|
||||
- `installedSize(gameDir, id)` — размер папки в байтах.
|
||||
- `remove(gameDir, id, &error)` — удаляет `versions/<id>`. Сначала проверяет, что id не пустой,
|
||||
не начинается с точки и не содержит слэшей, а итоговый путь лежит внутри `versions/`. Если папки
|
||||
нет, это не ошибка.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in new issue
Block a user