new builds menu and modloaders implementation
This commit is contained in:
+59
-30
@@ -64,6 +64,11 @@ bool isSafeRelativeSegment(const QString &value)
|
||||
return !value.contains(u'/') && isSafeRelativePath(value);
|
||||
}
|
||||
|
||||
QString versionJsonPath(const QString &gameDir, const QString &id)
|
||||
{
|
||||
return gameDir + QStringLiteral("/versions/") + id + u'/' + id + QStringLiteral(".json");
|
||||
}
|
||||
|
||||
bool isTransient(QNetworkReply::NetworkError error, int httpStatus)
|
||||
{
|
||||
if (httpStatus == 429 || httpStatus >= 500)
|
||||
@@ -234,20 +239,34 @@ void VersionInstaller::resolveManifestEntry()
|
||||
return;
|
||||
|
||||
if (!ok) {
|
||||
QFile local(versionJsonPath(m_gameDir, id));
|
||||
if (local.open(QIODevice::ReadOnly)) {
|
||||
adoptVersionJson(local.readAll(), /*alreadySaved=*/true);
|
||||
return;
|
||||
}
|
||||
failInstall(warning.isEmpty() ? tr("Список версий Mojang недоступен") : warning);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto entry = m_manifest->find(id);
|
||||
if (!entry) {
|
||||
// Обычно это вручную вписанный id сборки — сообщение не должно
|
||||
// выглядеть как сетевая ошибка.
|
||||
failInstall(tr("Версия «%1» отсутствует в манифесте Mojang — "
|
||||
"установить её автоматически нельзя")
|
||||
.arg(id));
|
||||
if (entry) {
|
||||
fetchVersionJson(entry->url, entry->sha1);
|
||||
return;
|
||||
}
|
||||
fetchVersionJson(entry->url, entry->sha1);
|
||||
|
||||
// Версии нет в манифесте, но описание могло уже лечь на диск: так
|
||||
// ставятся сборки модлоадеров, чьи id Mojang не знает.
|
||||
QFile local(versionJsonPath(m_gameDir, id));
|
||||
if (local.open(QIODevice::ReadOnly)) {
|
||||
adoptVersionJson(local.readAll(), /*alreadySaved=*/true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Иначе это вручную вписанный id сборки — сообщение не должно
|
||||
// выглядеть как сетевая ошибка.
|
||||
failInstall(tr("Версия «%1» отсутствует в манифесте Mojang — "
|
||||
"установить её автоматически нельзя")
|
||||
.arg(id));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -283,12 +302,23 @@ void VersionInstaller::fetchVersionJson(const QUrl &url, const QString &expected
|
||||
}
|
||||
}
|
||||
|
||||
m_versionJson = QJsonDocument::fromJson(payload).object();
|
||||
if (m_versionJson.isEmpty()) {
|
||||
failInstall(tr("Описание версии «%1» не удалось разобрать").arg(id));
|
||||
return;
|
||||
}
|
||||
adoptVersionJson(payload, /*alreadySaved=*/false);
|
||||
});
|
||||
}
|
||||
|
||||
// Общий хвост для описания версии, откуда бы оно ни пришло: из сети или уже
|
||||
// лежащим на диске (сборки модлоадеров кладут его туда сами).
|
||||
void VersionInstaller::adoptVersionJson(const QByteArray &payload, bool alreadySaved)
|
||||
{
|
||||
const QString id = m_versionId;
|
||||
|
||||
m_versionJson = QJsonDocument::fromJson(payload).object();
|
||||
if (m_versionJson.isEmpty()) {
|
||||
failInstall(tr("Описание версии «%1» не удалось разобрать").arg(id));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!alreadySaved) {
|
||||
const QString directory = m_gameDir + QStringLiteral("/versions/") + id;
|
||||
if (!QDir().mkpath(directory)) {
|
||||
failInstall(tr("Не удалось создать %1").arg(QDir::toNativeSeparators(directory)));
|
||||
@@ -302,28 +332,27 @@ void VersionInstaller::fetchVersionJson(const QUrl &url, const QString &expected
|
||||
failInstall(tr("Не удалось сохранить описание версии «%1»").arg(id));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Ванильные версии ничего не наследуют, но сборка могла бы — тогда
|
||||
// сначала ставим родителя, а потом возвращаемся к этой версии.
|
||||
const QString parentId = m_versionJson.value(QStringLiteral("inheritsFrom")).toString();
|
||||
if (!parentId.isEmpty() && isSafeRelativeSegment(parentId)
|
||||
&& !QFile::exists(m_gameDir + QStringLiteral("/versions/") + parentId + u'/' + parentId
|
||||
+ QStringLiteral(".json"))) {
|
||||
if (m_inheritDepth >= kMaxInheritDepth) {
|
||||
failInstall(tr("Слишком длинная цепочка inheritsFrom у версии «%1»").arg(id));
|
||||
return;
|
||||
}
|
||||
++m_inheritDepth;
|
||||
m_pendingInstalls.prepend({m_gameDir, id});
|
||||
m_pendingInstalls.prepend({m_gameDir, parentId});
|
||||
abandonCurrent();
|
||||
// Ванильные версии ничего не наследуют, но сборка могла бы — тогда
|
||||
// сначала ставим родителя, а потом возвращаемся к этой версии.
|
||||
const QString parentId = m_versionJson.value(QStringLiteral("inheritsFrom")).toString();
|
||||
if (!parentId.isEmpty() && isSafeRelativeSegment(parentId)
|
||||
&& !QFile::exists(versionJsonPath(m_gameDir, parentId))) {
|
||||
if (m_inheritDepth >= kMaxInheritDepth) {
|
||||
failInstall(tr("Слишком длинная цепочка inheritsFrom у версии «%1»").arg(id));
|
||||
return;
|
||||
}
|
||||
++m_inheritDepth;
|
||||
m_pendingInstalls.prepend({m_gameDir, id});
|
||||
m_pendingInstalls.prepend({m_gameDir, parentId});
|
||||
abandonCurrent();
|
||||
return;
|
||||
}
|
||||
|
||||
m_inheritDepth = 0;
|
||||
if (prepareTasks())
|
||||
pump();
|
||||
});
|
||||
m_inheritDepth = 0;
|
||||
if (prepareTasks())
|
||||
pump();
|
||||
}
|
||||
|
||||
// ── Составление списка файлов ──────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user