cleanups
This commit is contained in:
+4
-54
@@ -27,15 +27,12 @@
|
||||
namespace {
|
||||
|
||||
constexpr int kTransferTimeoutMs = 30000;
|
||||
// Установщик Forge после распаковки ещё патчит клиентский jar: на медленной
|
||||
// машине это несколько минут. Обрываем только совсем зависший процесс.
|
||||
constexpr int kInstallerTimeoutMs = 15 * 60 * 1000;
|
||||
constexpr int kLogTailLines = 12;
|
||||
|
||||
const QString kFabricProfile = QStringLiteral("https://meta.fabricmc.net/v2/versions/loader/");
|
||||
const QString kQuiltProfile = QStringLiteral("https://meta.quiltmc.org/v3/versions/loader/");
|
||||
|
||||
// Тот же запрет, что у VersionInstaller: id версии становится именем каталога.
|
||||
bool isSafeSegment(const QString &value)
|
||||
{
|
||||
if (value.isEmpty() || value.contains(u'/') || value.contains(u'\\') || value.contains(u':'))
|
||||
@@ -48,7 +45,7 @@ QString versionJsonPath(const QString &gameDir, const QString &id)
|
||||
return gameDir + QStringLiteral("/versions/") + id + u'/' + id + QStringLiteral(".json");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
}
|
||||
|
||||
ModLoaderInstaller::ModLoaderInstaller(ModLoaderVersionService *meta,
|
||||
VersionInstaller *versionInstaller,
|
||||
@@ -58,8 +55,6 @@ ModLoaderInstaller::ModLoaderInstaller(ModLoaderVersionService *meta,
|
||||
, m_versionInstaller(versionInstaller)
|
||||
, m_network(new QNetworkAccessManager(this))
|
||||
{
|
||||
// Последний шаг обоих путей одинаков: VersionInstaller дотягивает всё, чего
|
||||
// не хватает получившемуся профилю.
|
||||
connect(m_versionInstaller, &VersionInstaller::finished, this, [this](const QString &id) {
|
||||
if (m_awaitingVersionId.isEmpty() || id != m_awaitingVersionId)
|
||||
return;
|
||||
@@ -96,7 +91,7 @@ ModLoaderInstaller::~ModLoaderInstaller()
|
||||
double ModLoaderInstaller::fraction() const
|
||||
{
|
||||
if (m_bytesTotal <= 0)
|
||||
return -1.0; // панель нарисует «…»
|
||||
return -1.0;
|
||||
return double(m_bytesDone) / double(m_bytesTotal);
|
||||
}
|
||||
|
||||
@@ -131,9 +126,6 @@ void ModLoaderInstaller::install(const QString &gameDir,
|
||||
emit started(m_label);
|
||||
setStage(Loc::text("loader.progress.preparing").arg(loaderTitle(loader)));
|
||||
|
||||
// Список версий нужен и для ссылки на installer.jar, и для точного id
|
||||
// профиля. После перезапуска лаунчера он ещё не прочитан с диска, поэтому
|
||||
// спрашиваем его до всего остального: попадание в кэш обойдётся без сети.
|
||||
m_meta->ensureLoaded(loader, m_gameVersion, [this, loader](bool ok, const QString &warning) {
|
||||
if (!m_running || m_canceling)
|
||||
return;
|
||||
@@ -142,9 +134,6 @@ void ModLoaderInstaller::install(const QString &gameDir,
|
||||
: warning);
|
||||
return;
|
||||
}
|
||||
// Любой лоадер — надстройка над ванильной версией: и профиль Fabric с его
|
||||
// inheritsFrom, и патч клиентского jar у Forge упрутся в недокачанную базу.
|
||||
// Поэтому шлюз один на всех и стоит до выбора ветки.
|
||||
ensureBaseVersion([this, loader] {
|
||||
if (loader == ModLoader::Fabric || loader == ModLoader::Quilt)
|
||||
beginFabricLike();
|
||||
@@ -172,7 +161,7 @@ void ModLoaderInstaller::cancel()
|
||||
removeVersionsAddedByInstaller();
|
||||
if (!m_awaitingVersionId.isEmpty()) {
|
||||
m_versionInstaller->cancel();
|
||||
return; // финал придёт из VersionInstaller::canceled
|
||||
return;
|
||||
}
|
||||
|
||||
const QString label = m_label;
|
||||
@@ -180,8 +169,6 @@ void ModLoaderInstaller::cancel()
|
||||
emit canceled(label);
|
||||
}
|
||||
|
||||
// ── Fabric и Quilt ─────────────────────────────────────────────────────────
|
||||
|
||||
void ModLoaderInstaller::beginFabricLike()
|
||||
{
|
||||
const auto entry = m_meta->find(m_loader, m_gameVersion, m_loaderVersion);
|
||||
@@ -227,8 +214,6 @@ void ModLoaderInstaller::beginFabricLike()
|
||||
const QString id = root.value(QStringLiteral("id")).toString();
|
||||
const QString inherits = root.value(QStringLiteral("inheritsFrom")).toString();
|
||||
|
||||
// Описание приходит из сети и превращается в путь на диске — проверяем
|
||||
// и id, и то, что версия действительно наследует выбранную ванильную.
|
||||
if (id.isEmpty() || !isSafeSegment(id)) {
|
||||
fail(Loc::text("loader.error.descriptionBadId")
|
||||
.arg(loaderTitle(m_loader)));
|
||||
@@ -260,8 +245,6 @@ void ModLoaderInstaller::beginFabricLike()
|
||||
});
|
||||
}
|
||||
|
||||
// ── Forge и NeoForge ───────────────────────────────────────────────────────
|
||||
|
||||
void ModLoaderInstaller::beginInstallerJar()
|
||||
{
|
||||
const auto entry = m_meta->find(m_loader, m_gameVersion, m_loaderVersion);
|
||||
@@ -274,16 +257,11 @@ void ModLoaderInstaller::beginInstallerJar()
|
||||
fail(Loc::text("loader.error.installerBadUrl").arg(loaderTitle(m_loader)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Ванильную версию к этому моменту уже проверил ensureBaseVersion из install().
|
||||
downloadInstaller(entry->installerUrl, [this](const QString &path) { runInstaller(path); });
|
||||
}
|
||||
|
||||
void ModLoaderInstaller::ensureBaseVersion(std::function<void()> next)
|
||||
{
|
||||
// Наличие versions/<mc>/<mc>.json ничего не значит: VersionInstaller кладёт его
|
||||
// до загрузки файлов, так что оборванная установка оставляет ровно такой след.
|
||||
// Проверяем тем же, чем пользуются приёмка VersionInstaller и запуск игры.
|
||||
QString loadError;
|
||||
const MinecraftVersion installed =
|
||||
VersionLoader::load(m_gameDir, m_gameVersion, {}, &loadError);
|
||||
@@ -379,9 +357,6 @@ void ModLoaderInstaller::downloadInstaller(const QUrl &url, std::function<void(c
|
||||
});
|
||||
}
|
||||
|
||||
// Без launcher_profiles.json установщик Forge и NeoForge завершается с
|
||||
// сообщением про испорченный профиль лаунчера. Свои профили мы там не держим,
|
||||
// поэтому достаточно заглушки.
|
||||
bool ModLoaderInstaller::writeLauncherProfilesStub()
|
||||
{
|
||||
const QString path = m_gameDir + QStringLiteral("/launcher_profiles.json");
|
||||
@@ -419,8 +394,6 @@ void ModLoaderInstaller::runInstaller(const QString &installerPath)
|
||||
return;
|
||||
}
|
||||
|
||||
// Постобработка установщика гоняет те же классы, что и сама игра, поэтому
|
||||
// требования к Java берём у ванильной версии.
|
||||
QString loadError;
|
||||
const MinecraftVersion base = VersionLoader::load(m_gameDir, m_gameVersion, {}, &loadError);
|
||||
const int requiredMajor = base.isValid() ? base.javaMajor : 8;
|
||||
@@ -436,9 +409,6 @@ void ModLoaderInstaller::runInstaller(const QString &installerPath)
|
||||
|
||||
m_versionsBefore = VersionLoader::installedVersions(m_gameDir);
|
||||
m_installerStarted = true;
|
||||
|
||||
// Весь вывод установщика уходит в файл: в интерфейс попадает только хвост,
|
||||
// а разбираться с «Processor failed» по двенадцати строкам невозможно.
|
||||
m_installerLogPath = LauncherPaths::loaderDownloadDir() + u'/' + loaderKey(m_loader) + u'-'
|
||||
+ QString(m_loaderVersion).replace(u'/', u'_')
|
||||
+ QStringLiteral("-install.log");
|
||||
@@ -451,7 +421,6 @@ void ModLoaderInstaller::runInstaller(const QString &installerPath)
|
||||
|
||||
setStage(Loc::text("loader.progress.installing").arg(loaderTitle(m_loader)));
|
||||
m_currentFile = Loc::text("loader.progress.installerRunning");
|
||||
// Прогресс установщика неизвестен: панель покажет «…».
|
||||
m_bytesDone = 0;
|
||||
m_bytesTotal = 0;
|
||||
emit progressChanged();
|
||||
@@ -462,9 +431,6 @@ void ModLoaderInstaller::runInstaller(const QString &installerPath)
|
||||
QStringLiteral("--installClient"), QDir::toNativeSeparators(m_gameDir)});
|
||||
m_process->setWorkingDirectory(LauncherPaths::loaderDownloadDir());
|
||||
m_process->setProcessChannelMode(QProcess::MergedChannels);
|
||||
|
||||
// Установщик сверяет sha1 всего, что собрал сам, а на системах с zlib-ng
|
||||
// сжатие получается другое — без подмены он падает на любой версии игры.
|
||||
QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
|
||||
QString zlibNote;
|
||||
m_zlibNgUnpatched = !ZlibReference::applyTo(environment, &zlibNote);
|
||||
@@ -483,7 +449,6 @@ void ModLoaderInstaller::runInstaller(const QString &installerPath)
|
||||
appendInstallerLog(text);
|
||||
emit log(text);
|
||||
}
|
||||
// Хвоста хватает, чтобы показать причину отказа; весь лог не нужен.
|
||||
while (m_installerLog.size() > kLogTailLines)
|
||||
m_installerLog.removeFirst();
|
||||
});
|
||||
@@ -493,7 +458,7 @@ void ModLoaderInstaller::runInstaller(const QString &installerPath)
|
||||
});
|
||||
connect(m_process, &QProcess::errorOccurred, this, [this](QProcess::ProcessError error) {
|
||||
if (m_canceling || error == QProcess::Crashed)
|
||||
return; // Crashed придёт ещё и в finished
|
||||
return;
|
||||
fail(Loc::text("loader.error.installerStartFailed")
|
||||
.arg(loaderTitle(m_loader), m_process->errorString()));
|
||||
});
|
||||
@@ -505,7 +470,6 @@ void ModLoaderInstaller::runInstaller(const QString &installerPath)
|
||||
return;
|
||||
}
|
||||
|
||||
// Совсем зависший установщик не должен блокировать лаунчер навсегда.
|
||||
QTimer::singleShot(kInstallerTimeoutMs, this, [this] {
|
||||
if (m_process && m_process->state() != QProcess::NotRunning) {
|
||||
m_process->kill();
|
||||
@@ -541,13 +505,8 @@ void ModLoaderInstaller::handleInstallerFinished(int exitCode, bool crashed)
|
||||
return;
|
||||
}
|
||||
|
||||
// Какой профиль появился — выясняем разницей: id у Forge разные по эпохам
|
||||
// (1.20.1-forge-47.4.0, 1.12.2-forge-14.23.5.2859, neoforge-21.1.66).
|
||||
QStringList added = versionsAddedByInstaller();
|
||||
if (added.isEmpty()) {
|
||||
// Разницы нет, если профиль лежал в versions ещё до запуска: переустановка
|
||||
// поверх или остаток прошлой попытки. Тогда ищем его среди наследников
|
||||
// выбранной ванильной версии.
|
||||
const QStringList dependents = VersionLoader::dependentsOf(m_gameDir, m_gameVersion);
|
||||
for (const QString &id : dependents) {
|
||||
if (id.contains(m_loaderVersion))
|
||||
@@ -566,16 +525,12 @@ void ModLoaderInstaller::handleInstallerFinished(int exitCode, bool crashed)
|
||||
return;
|
||||
}
|
||||
if (added.size() > 1) {
|
||||
// Берём тот, где встречается версия лоадера: остальные — попутно
|
||||
// доустановленные зависимости.
|
||||
const auto match = std::find_if(added.cbegin(), added.cend(), [this](const QString &id) {
|
||||
return id.contains(m_loaderVersion);
|
||||
});
|
||||
added = {match != added.cend() ? *match : added.first()};
|
||||
}
|
||||
|
||||
// Профиль на месте — дальше его судьба в руках VersionInstaller, мусором он
|
||||
// больше не считается.
|
||||
m_installerStarted = false;
|
||||
m_versionsBefore.clear();
|
||||
handOffToVersionInstaller(added.first());
|
||||
@@ -597,9 +552,6 @@ QStringList ModLoaderInstaller::versionsAddedByInstaller() const
|
||||
|
||||
void ModLoaderInstaller::removeVersionsAddedByInstaller()
|
||||
{
|
||||
// Forge пишет versions/<id>/<id>.json до запуска процессоров, поэтому после
|
||||
// неудачи остаётся профиль-призрак: в списке версий он выглядит установленным,
|
||||
// а следующей попытке мешает — разница по versions у неё выйдет пустой.
|
||||
const QStringList added = versionsAddedByInstaller();
|
||||
for (const QString &id : added) {
|
||||
QString error;
|
||||
@@ -643,8 +595,6 @@ void ModLoaderInstaller::closeInstallerLog()
|
||||
m_installerLogFile = nullptr;
|
||||
}
|
||||
|
||||
// ── Общий хвост ────────────────────────────────────────────────────────────
|
||||
|
||||
void ModLoaderInstaller::handOffToVersionInstaller(const QString &versionId)
|
||||
{
|
||||
m_awaitingVersionId = versionId;
|
||||
|
||||
Reference in New Issue
Block a user