mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2026-06-29 01:54:20 +03:00
[Backport release-11.x] When auth is down, launch into offline mode (#5729)
This commit is contained in:
commit
8ae894c7b1
8 changed files with 38 additions and 9 deletions
|
|
@ -40,6 +40,7 @@
|
||||||
#include "minecraft/auth/AccountData.h"
|
#include "minecraft/auth/AccountData.h"
|
||||||
#include "minecraft/auth/AccountList.h"
|
#include "minecraft/auth/AccountList.h"
|
||||||
|
|
||||||
|
#include "net/NetUtils.h"
|
||||||
#include "ui/InstanceWindow.h"
|
#include "ui/InstanceWindow.h"
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
#include "ui/dialogs/MSALoginDialog.h"
|
#include "ui/dialogs/MSALoginDialog.h"
|
||||||
|
|
@ -225,13 +226,14 @@ bool LaunchController::askPlayDemo() const
|
||||||
return box.clickedButton() == demoButton;
|
return box.clickedButton() == demoButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString LaunchController::askOfflineName(const QString& playerName, bool* ok) const
|
QString LaunchController::askOfflineName(const QString& playerName, bool* ok)
|
||||||
{
|
{
|
||||||
if (ok != nullptr) {
|
if (ok != nullptr) {
|
||||||
*ok = false;
|
*ok = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString message;
|
QString title, message;
|
||||||
|
title = tr("Player name");
|
||||||
switch (m_actualLaunchMode) {
|
switch (m_actualLaunchMode) {
|
||||||
case LaunchMode::Normal:
|
case LaunchMode::Normal:
|
||||||
Q_ASSERT(false);
|
Q_ASSERT(false);
|
||||||
|
|
@ -241,7 +243,14 @@ QString LaunchController::askOfflineName(const QString& playerName, bool* ok) co
|
||||||
break;
|
break;
|
||||||
case LaunchMode::Offline:
|
case LaunchMode::Offline:
|
||||||
if (m_wantedLaunchMode == LaunchMode::Normal) {
|
if (m_wantedLaunchMode == LaunchMode::Normal) {
|
||||||
message = tr("You are not connected to the Internet, launching in offline mode\n\n");
|
auto netErr = m_accountToUse->accountData()->networkError;
|
||||||
|
if (Net::isServerError(netErr)) {
|
||||||
|
title = tr("Auth servers offline");
|
||||||
|
message = tr("The Minecraft authentication servers are currently unavailable, launching in offline mode.\n\n");
|
||||||
|
} else {
|
||||||
|
title = tr("No internet connection");
|
||||||
|
message = tr("You are not connected to the Internet, launching in offline mode.\n\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
message += tr("Choose your offline mode player name");
|
message += tr("Choose your offline mode player name");
|
||||||
break;
|
break;
|
||||||
|
|
@ -251,7 +260,7 @@ QString LaunchController::askOfflineName(const QString& playerName, bool* ok) co
|
||||||
QString usedname = lastOfflinePlayerName.isEmpty() ? playerName : lastOfflinePlayerName;
|
QString usedname = lastOfflinePlayerName.isEmpty() ? playerName : lastOfflinePlayerName;
|
||||||
|
|
||||||
ChooseOfflineNameDialog dialog(message, m_parentWidget);
|
ChooseOfflineNameDialog dialog(message, m_parentWidget);
|
||||||
dialog.setWindowTitle(tr("Player name"));
|
dialog.setWindowTitle(title);
|
||||||
dialog.setUsername(usedname);
|
dialog.setUsername(usedname);
|
||||||
if (dialog.exec() != QDialog::Accepted) {
|
if (dialog.exec() != QDialog::Accepted) {
|
||||||
return {};
|
return {};
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ class LaunchController : public Task {
|
||||||
void decideAccount();
|
void decideAccount();
|
||||||
LaunchDecision decideLaunchMode();
|
LaunchDecision decideLaunchMode();
|
||||||
bool askPlayDemo() const;
|
bool askPlayDemo() const;
|
||||||
QString askOfflineName(const QString& playerName, bool* ok = nullptr) const;
|
QString askOfflineName(const QString& playerName, bool* ok = nullptr);
|
||||||
bool reauthenticateAccount(const MinecraftAccountPtr& account, const QString& reason);
|
bool reauthenticateAccount(const MinecraftAccountPtr& account, const QString& reason);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
#include <QNetworkReply>
|
||||||
#include <QVariantMap>
|
#include <QVariantMap>
|
||||||
|
|
||||||
enum class Validity { None, Assumed, Certain };
|
enum class Validity { None, Assumed, Certain };
|
||||||
|
|
@ -118,5 +119,6 @@ struct AccountData {
|
||||||
// runtime only information (not saved with the account)
|
// runtime only information (not saved with the account)
|
||||||
QString internalId;
|
QString internalId;
|
||||||
QString errorString;
|
QString errorString;
|
||||||
|
QNetworkReply::NetworkError networkError = QNetworkReply::NoError;
|
||||||
AccountState accountState = AccountState::Unchecked;
|
AccountState accountState = AccountState::Unchecked;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -56,10 +56,11 @@ void LauncherLoginStep::onRequestDone(QByteArray* response)
|
||||||
qCDebug(authCredentials()) << *response;
|
qCDebug(authCredentials()) << *response;
|
||||||
if (m_request->error() != QNetworkReply::NoError) {
|
if (m_request->error() != QNetworkReply::NoError) {
|
||||||
qWarning() << "Reply error:" << m_request->error();
|
qWarning() << "Reply error:" << m_request->error();
|
||||||
if (Net::isApplicationError(m_request->error())) {
|
if (Net::isApplicationError(m_request->error()) && !Net::isServerError(m_request->error())) {
|
||||||
emit finished(AccountTaskState::STATE_FAILED_SOFT,
|
emit finished(AccountTaskState::STATE_FAILED_SOFT,
|
||||||
tr("Failed to get Minecraft access token: %1").arg(m_request->errorString()));
|
tr("Failed to get Minecraft access token: %1").arg(m_request->errorString()));
|
||||||
} else {
|
} else {
|
||||||
|
m_data->networkError = m_request->error();
|
||||||
emit finished(AccountTaskState::STATE_OFFLINE, tr("Failed to get Minecraft access token: %1").arg(m_request->errorString()));
|
emit finished(AccountTaskState::STATE_OFFLINE, tr("Failed to get Minecraft access token: %1").arg(m_request->errorString()));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -52,10 +52,11 @@ void MinecraftProfileStep::onRequestDone(QByteArray* response)
|
||||||
qWarning() << " Response:";
|
qWarning() << " Response:";
|
||||||
qWarning() << QString::fromUtf8(*response);
|
qWarning() << QString::fromUtf8(*response);
|
||||||
|
|
||||||
if (Net::isApplicationError(m_request->error())) {
|
if (Net::isApplicationError(m_request->error()) && !Net::isServerError(m_request->error())) {
|
||||||
emit finished(AccountTaskState::STATE_FAILED_SOFT,
|
emit finished(AccountTaskState::STATE_FAILED_SOFT,
|
||||||
tr("Minecraft Java profile acquisition failed: %1").arg(m_request->errorString()));
|
tr("Minecraft Java profile acquisition failed: %1").arg(m_request->errorString()));
|
||||||
} else {
|
} else {
|
||||||
|
m_data->networkError = m_request->error();
|
||||||
emit finished(AccountTaskState::STATE_OFFLINE,
|
emit finished(AccountTaskState::STATE_OFFLINE,
|
||||||
tr("Minecraft Java profile acquisition failed: %1").arg(m_request->errorString()));
|
tr("Minecraft Java profile acquisition failed: %1").arg(m_request->errorString()));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,13 +60,14 @@ void XboxAuthorizationStep::onRequestDone(QByteArray* response)
|
||||||
qCDebug(authCredentials()) << *response;
|
qCDebug(authCredentials()) << *response;
|
||||||
if (m_request->error() != QNetworkReply::NoError) {
|
if (m_request->error() != QNetworkReply::NoError) {
|
||||||
qWarning() << "Reply error:" << m_request->error();
|
qWarning() << "Reply error:" << m_request->error();
|
||||||
if (Net::isApplicationError(m_request->error())) {
|
if (Net::isApplicationError(m_request->error()) && !Net::isServerError(m_request->error())) {
|
||||||
if (processSTSError(*response)) {
|
if (processSTSError(*response)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emit finished(AccountTaskState::STATE_FAILED_SOFT,
|
emit finished(AccountTaskState::STATE_FAILED_SOFT,
|
||||||
tr("Unknown STS error for %1 services: %2").arg(m_authorizationKind, m_request->errorString()));
|
tr("Unknown STS error for %1 services: %2").arg(m_authorizationKind, m_request->errorString()));
|
||||||
} else {
|
} else {
|
||||||
|
m_data->networkError = m_request->error();
|
||||||
emit finished(AccountTaskState::STATE_OFFLINE,
|
emit finished(AccountTaskState::STATE_OFFLINE,
|
||||||
tr("Failed to get authorization for %1 services: %2").arg(m_authorizationKind, m_request->errorString()));
|
tr("Failed to get authorization for %1 services: %2").arg(m_authorizationKind, m_request->errorString()));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,9 +56,10 @@ void XboxUserStep::onRequestDone(QByteArray* response)
|
||||||
{
|
{
|
||||||
if (m_request->error() != QNetworkReply::NoError) {
|
if (m_request->error() != QNetworkReply::NoError) {
|
||||||
qWarning() << "Reply error:" << m_request->error();
|
qWarning() << "Reply error:" << m_request->error();
|
||||||
if (Net::isApplicationError(m_request->error())) {
|
if (Net::isApplicationError(m_request->error()) && !Net::isServerError(m_request->error())) {
|
||||||
emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Xbox user authentication failed: %1").arg(m_request->errorString()));
|
emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Xbox user authentication failed: %1").arg(m_request->errorString()));
|
||||||
} else {
|
} else {
|
||||||
|
m_data->networkError = m_request->error();
|
||||||
emit finished(AccountTaskState::STATE_OFFLINE, tr("Xbox user authentication failed: %1").arg(m_request->errorString()));
|
emit finished(AccountTaskState::STATE_OFFLINE, tr("Xbox user authentication failed: %1").arg(m_request->errorString()));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -40,4 +40,18 @@ inline bool isApplicationError(QNetworkReply::NetworkError x)
|
||||||
QNetworkReply::UnknownContentError };
|
QNetworkReply::UnknownContentError };
|
||||||
return errors.contains(x);
|
return errors.contains(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 500 class errors, see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/500
|
||||||
|
// microsoft may send these error codes when services (auth) are down.
|
||||||
|
// We treat this as a reason to launch in offline mode.
|
||||||
|
inline bool isServerError(QNetworkReply::NetworkError x)
|
||||||
|
{
|
||||||
|
static QSet<QNetworkReply::NetworkError> errors = { QNetworkReply::InternalServerError,
|
||||||
|
QNetworkReply::OperationNotImplementedError,
|
||||||
|
QNetworkReply::ServiceUnavailableError, // 503 | seen in logs in 2026
|
||||||
|
//QNetworkReply::GatewayTimeoutError, // 504 | seen in logs in 2024
|
||||||
|
// Qt doesn't have it mapped. Unknown covers it
|
||||||
|
QNetworkReply::UnknownServerError };
|
||||||
|
return errors.contains(x);
|
||||||
|
}
|
||||||
} // namespace Net
|
} // namespace Net
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue