6.4 KiB
VersionInstaller
versioninstaller.h, versioninstaller.cpp
Ставит версию игры в .minecraft: описание версии, клиентский jar, библиотеки, индекс ресурсов,
сами ресурсы и конфиг логирования. Одновременно ставится одна версия, остальные ждут в очереди.
Всё работает в GUI-потоке на асинхронной сети.
Экземпляр держит LauncherBackend. Ещё им пользуется ModLoaderInstaller: перед установкой модлоадера нужно поставить базовую версию, а после установки докачать библиотеки нового профиля.
Интерфейс
install(gameDir, versionId)— поставить в очередь. Если эта версия уже ставится или ждёт, ничего не происходит. Если id содержит слэши,.или.., сразу приходитfailed.cancel()— отменить текущую установку и очистить очередь.isRunning(),isQueued(id),versionId().- Для панели прогресса:
stage(),currentFile(),bytesDone(),bytesTotal(),fraction()(от 0 до 1; −1, если общий объём неизвестен).
Сигналы: started(id), progressChanged() (не чаще раза в 100 мс), finished(id),
failed(id, message), canceled(id).
started испускается один раз на всю серию установок из очереди. finished испускается для
каждой версии.
Как идёт установка
- Описание версии. У VersionManifestService берётся ссылка на
<id>.json, файл скачивается, sha1 сверяется с манифестом, и файл сохраняется вversions/<id>/. Если версии в манифесте нет (профиль модлоадера) или сеть недоступна, берётся файл, который уже лежит на диске. Если нет и его, установка падает. - Родитель. Если в описании есть
inheritsFrom, а родителя на диске нет, текущая версия уступает место: в начало очереди встают сначала родитель, потом она сама. Глубина цепочки — до 10 звеньев. - Список файлов.
VersionLoader::load()сводит цепочку, и из результата составляется список: клиентский jar, все библиотеки, индекс ресурсов и конфиг логов. Ссылки не поhttpsи библиотеки без адреса пропускаются с предупреждением. - Загрузка. До 8 файлов одновременно. Каждый пишется потоком в
QSaveFile, sha1 считается на ходу. При временной ошибке (таймаут, обрыв, HTTP 429 или 5xx) и при несовпадении хеша файл ставится обратно в начало очереди с паузой 400 мс, потом 800 мс. После третьей неудачи установка падает. Другие ошибки сразу её прерывают. Таймаут на файл 30 секунд. - Ресурсы. Как только индекс ресурсов на диске, он разворачивается в задачи на загрузку из
resources.download.minecraft.net/<xx>/<hash>. До этого момента в общем объёме учитываетсяtotalSizeиз описания версии, а потом он заменяется точной суммой. - Старые ресурсы. У версий до 1.6 (
virtual,map_to_resources,assets=legacyилиpre-1.6) игра ищет ресурсы не вassets/objects, а в обычной папке с именами файлов. Они копируются вassets/virtual/legacy/или вresources/по 64 файла за такт таймера, чтобы окно не подвисало. - Проверка.
GameLauncher::missingFiles(). Если чего-то нет, это ошибка.
Уже скачанные файлы
Существующий файл считается целым, если его размер совпадает с ожидаемым (или размер неизвестен).
Хеш не пересчитывается: перехеширование сотен мегабайт ресурсов при каждой установке обходится
дороже, чем редкий битый файл. Для будущей кнопки «Проверить файлы» есть флаг m_verifyExisting,
сейчас он всегда false.
Пропуск файлов идёт пачками по 256 за такт. Иначе установка версии, у которой уже есть все ресурсы, повесила бы окно на перебор десятков тысяч записей.
Ошибки и отмена
При ошибке все активные загрузки обрываются, недописанные файлы откатываются (QSaveFile), а
очередь очищается: остальные версии из неё тоже не поставятся. К тексту ошибки добавляются до
трёх накопленных предупреждений.
Отмена обрывает активные запросы и ждёт, пока все они вернутся. Только после этого приходит
canceled. Пока отмена не закончилась, install() отвечает отказом.
Деструктор блокирует сигналы и отменяет установку.
При создании этого документа использовался ИИ.