Skip to content

Commit

Permalink
UltimMC: Restructure local accounts working
Browse files Browse the repository at this point in the history
  • Loading branch information
Neptune650 committed Mar 6, 2024
1 parent 82df3ac commit b4bb083
Show file tree
Hide file tree
Showing 14 changed files with 219 additions and 45 deletions.
4 changes: 4 additions & 0 deletions launcher/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ set(MINECRAFT_SOURCES
minecraft/auth/flows/Mojang.h
minecraft/auth/flows/MSA.cpp
minecraft/auth/flows/MSA.h
minecraft/auth/flows/Local.cpp
minecraft/auth/flows/Local.h

minecraft/auth/steps/EntitlementsStep.cpp
minecraft/auth/steps/EntitlementsStep.h
Expand All @@ -254,6 +256,8 @@ set(MINECRAFT_SOURCES
minecraft/auth/steps/XboxUserStep.h
minecraft/auth/steps/YggdrasilStep.cpp
minecraft/auth/steps/YggdrasilStep.h
minecraft/auth/steps/LocalStep.cpp
minecraft/auth/steps/LocalStep.h

minecraft/gameoptions/GameOptions.h
minecraft/gameoptions/GameOptions.cpp
Expand Down
78 changes: 77 additions & 1 deletion launcher/LaunchController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,89 @@ void LaunchController::login() {
m_session->wants_online = m_online;
m_accountToUse->fillSession(m_session);

if (m_accountToUse->accountType() == AccountType::Local) {
launchInstance();
return;
}

switch(m_accountToUse->accountState()) {
case AccountState::Offline: {
m_session->wants_online = false;
// NOTE: fallthrough is intentional
}
case AccountState::Online: {
launchInstance();
if(!m_session->wants_online) {
QString usedname;
if(m_offlineName.isEmpty()) {
// we ask the user for a player name
bool ok = false;
QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
usedname = lastOfflinePlayerName.isEmpty() ? m_session->player_name : lastOfflinePlayerName;
QString name = QInputDialog::getText(
m_parentWidget,
tr("Player name"),
tr("Choose your offline mode player name."),
QLineEdit::Normal,
usedname,
&ok
);
if (!ok)
{
tryagain = false;
break;
}
if (name.length())
{
usedname = name;
APPLICATION->settings()->set("LastOfflinePlayerName", usedname);
}
}
else {
usedname = m_offlineName;
}

m_session->MakeOffline(usedname);
// offline flavored game from here :3
}
if(m_accountToUse->ownsMinecraft()) {
if(!m_accountToUse->hasProfile()) {
// Now handle setting up a profile name here...
ProfileSetupDialog dialog(m_accountToUse, m_parentWidget);
if (dialog.exec() == QDialog::Accepted)
{
tryagain = true;
continue;
}
else
{
emitFailed(tr("Received undetermined session status during login."));
return;
}
}
// we own Minecraft, there is a profile, it's all ready to go!
launchInstance();
return;
}
else {
// play demo ?
QMessageBox box(m_parentWidget);
box.setWindowTitle(tr("Play demo?"));
box.setText(tr("This account does not own Minecraft.\nYou need to purchase the game first to play it.\n\nDo you want to play the demo?"));
box.setIcon(QMessageBox::Warning);
auto demoButton = box.addButton(tr("Play Demo"), QMessageBox::ButtonRole::YesRole);
auto cancelButton = box.addButton(tr("Cancel"), QMessageBox::ButtonRole::NoRole);
box.setDefaultButton(cancelButton);

box.exec();
if(box.clickedButton() == demoButton) {
// play demo here
m_session->MakeDemo();
launchInstance();
}
else {
emitFailed(tr("Launch cancelled - account does not own Minecraft."));
}
}
return;
}
case AccountState::Errored:
Expand Down
18 changes: 13 additions & 5 deletions launcher/minecraft/auth/AccountData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,11 @@ bool AccountData::resumeStateFromV3(QJsonObject data) {
if(typeS == "MSA") {
type = AccountType::MSA;
provider = AuthProviders::lookup("MSA");
} else {
} else if (typeS == "Mojang") {
type = AccountType::Mojang;
provider = AuthProviders::lookup("Mojang");
} else {
type = AccountType::Local;
provider = AuthProviders::lookup(typeS);
}

Expand Down Expand Up @@ -349,7 +352,7 @@ bool AccountData::resumeStateFromV3(QJsonObject data) {
QJsonObject AccountData::saveState() const {
QJsonObject output;
if(type == AccountType::Mojang) {
output["type"] = provider->id();
output["type"] = "Mojang";
if(legacy) {
output["legacy"] = true;
}
Expand All @@ -366,6 +369,8 @@ QJsonObject AccountData::saveState() const {
tokenToJSONV3(output, userToken, "utoken");
tokenToJSONV3(output, xboxApiToken, "xrp-main");
tokenToJSONV3(output, mojangservicesToken, "xrp-mc");
} else if (type == AccountType::Local) {
output["type"] = "Local";
}

tokenToJSONV3(output, yggdrasilToken, "ygg");
Expand All @@ -386,14 +391,14 @@ QString AccountData::accessToken() const {
}

QString AccountData::clientToken() const {
if(type != AccountType::Mojang) {
if(type == AccountType::MSA) {
return QString();
}
return yggdrasilToken.extra["clientToken"].toString();
}

void AccountData::setClientToken(QString clientToken) {
if(type != AccountType::Mojang) {
if(type == AccountType::MSA) {
return;
}
yggdrasilToken.extra["clientToken"] = clientToken;
Expand All @@ -407,7 +412,7 @@ void AccountData::generateClientTokenIfMissing() {
}

void AccountData::invalidateClientToken() {
if(type != AccountType::Mojang) {
if(type == AccountType::MSA) {
return;
}
yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegExp("[{-}]"));
Expand All @@ -432,6 +437,9 @@ QString AccountData::accountDisplayString() const {
case AccountType::Mojang: {
return userName();
}
case Account::Type: {
return "<Local>";
}
case AccountType::MSA: {
if(xboxApiToken.extra.contains("gtg")) {
return xboxApiToken.extra["gtg"].toString();
Expand Down
3 changes: 2 additions & 1 deletion launcher/minecraft/auth/AccountData.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ struct MinecraftProfile {

enum class AccountType {
MSA,
Mojang
Mojang,
Local
};

enum class AccountState {
Expand Down
37 changes: 33 additions & 4 deletions launcher/minecraft/auth/MinecraftAccount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@
#include "AuthProviders.h"
#include "flows/MSA.h"
#include "flows/Mojang.h"
#include "flows/Local.h"

MinecraftAccount::MinecraftAccount(QObject* parent) : QObject(parent) {
data.internalId = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
}


MinecraftAccountPtr MinecraftAccount::loadFromJsonV2(const QJsonObject& json) {
MinecraftAccountPtr account(new MinecraftAccount());
if(account->data.resumeStateFromV2(json)) {
Expand All @@ -58,7 +60,23 @@ MinecraftAccountPtr MinecraftAccount::createFromUsername(const QString &username
account->data.type = AccountType::Mojang;
account->data.yggdrasilToken.extra["userName"] = username;
account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
account->data.minecraftProfile.id = account->data.internalId;
return account;
}

MinecraftAccountPtr MinecraftAccount::createLocal(const QString &username)
{
MinecraftAccountPtr account = new MinecraftAccount();
account->data.type = AccountType::Local;
account->data.yggdrasilToken.token = "0";
account->data.yggdrasilToken.validity = Katabasis::Validity::Certain;
account->data.yggdrasilToken.issueInstant = QDateTime::currentDateTimeUtc();
account->data.yggdrasilToken.extra["userName"] = username;
account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
account->data.minecraftEntitlement.ownsMinecraft = true;
account->data.minecraftEntitlement.canPlayMinecraft = true;
account->data.minecraftProfile.id = uuidFromUsername(username).toString().remove(QRegularExpression("[{}-]"));
account->data.minecraftProfile.name = username;
account->data.minecraftProfile.validity = Katabasis::Validity::Certain;
return account;
}

Expand Down Expand Up @@ -113,16 +131,27 @@ shared_qobject_ptr<AccountTask> MinecraftAccount::loginMSA() {
return m_currentTask;
}

shared_qobject_ptr<AccountTask> MinecraftAccount::loginLocal() {
Q_ASSERT(m_currentTask.get() == nullptr);

m_currentTask.reset(new LocalLogin(&data));
connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded()));
connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString)));
emit activityChanged(true);
return m_currentTask;
}

shared_qobject_ptr<AccountTask> MinecraftAccount::refresh() {
if(m_currentTask) {
return m_currentTask;
}

if(data.type == AccountType::MSA) {
if (data.type == AccountType::MSA) {
m_currentTask.reset(new MSASilent(&data));
}
else {
} else if (data.type == AccountType::Mojang) {
m_currentTask.reset(new MojangRefresh(&data));
} else {
m_currentTask.reset(new LocalRefresh(&data));
}

connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded()));
Expand Down
6 changes: 6 additions & 0 deletions launcher/minecraft/auth/MinecraftAccount.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ class MinecraftAccount :

shared_qobject_ptr<AccountTask> loginMSA();

shared_qobject_ptr<AccountTask> loginLocal();

shared_qobject_ptr<AccountTask> refresh();

shared_qobject_ptr<AccountTask> currentTask();
Expand Down Expand Up @@ -161,6 +163,10 @@ class MinecraftAccount :
return "msa";
}
break;
case AccountType::Local: {
return "local";
}
break;
default: {
return "unknown";
}
Expand Down
13 changes: 13 additions & 0 deletions launcher/minecraft/auth/flows/Local.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "Local.h"

#include "minecraft/auth/steps/LocalStep.h"

LocalRefresh::LocalRefresh(AccountData* data, QObject* parent) : AuthFlow(data, parent)
{
m_steps.append(makeShared<LocalStep>(m_data));
}

LocalLogin::LocalLogin(AccountData* data, QObject* parent) : AuthFlow(data, parent)
{
m_steps.append(makeShared<LocalStep>(m_data));
}
14 changes: 14 additions & 0 deletions launcher/minecraft/auth/flows/Local.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once
#include "AuthFlow.h"

class LocalRefresh : public AuthFlow {
Q_OBJECT
public:
explicit LocalRefresh(AccountData* data, QObject* parent = 0);
};

class LocalLogin : public AuthFlow {
Q_OBJECT
public:
explicit LocalLogin(AccountData* data, QObject* parent = 0);
};
21 changes: 21 additions & 0 deletions launcher/minecraft/auth/steps/LocalStep.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "LocalStep.h"

#include "Application.h"

LocalStep::LocalStep(AccountData* data) : AuthStep(data) {}
LocalStep::~LocalStep() noexcept = default;

QString LocalStep::describe()
{
return tr("Creating local account.");
}

void LocalStep::rehydrate()
{
// NOOP
}

void LocalStep::perform()
{
emit finished(AccountTaskState::STATE_WORKING, tr("Created local account."));
}
19 changes: 19 additions & 0 deletions launcher/minecraft/auth/steps/LocalStep.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once
#include <QObject>

#include "QObjectPtr.h"
#include "minecraft/auth/AuthStep.h"

#include <katabasis/DeviceFlow.h>

class LocalStep : public AuthStep {
Q_OBJECT
public:
explicit LocalStep(AccountData* data);
virtual ~LocalStep() noexcept;

void perform() override;
void rehydrate() override;

QString describe() override;
};
15 changes: 6 additions & 9 deletions launcher/minecraft/auth/steps/MinecraftProfileStep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ void MinecraftProfileStep::onRequestDone(
#ifndef NDEBUG
qDebug() << data;
#endif
/*
if (error == QNetworkReply::ContentNotFoundError) {
// NOTE: Succeed even if we do not have a profile. This is a valid account state.
if(m_data->type == AccountType::Mojang) {
Expand Down Expand Up @@ -70,23 +69,21 @@ void MinecraftProfileStep::onRequestDone(
tr("Minecraft Java profile acquisition failed.")
);
return;
}*/
/*if(!Parsers::parseMinecraftProfile(data, m_data->minecraftProfile)) {
}
if(!Parsers::parseMinecraftProfile(data, m_data->minecraftProfile)) {
m_data->minecraftProfile = MinecraftProfile();
emit finished(
AccountTaskState::STATE_FAILED_SOFT,
tr("Minecraft Java profile response could not be parsed")
);
return;
}*/
}

if(m_data->type == AccountType::Mojang) {
//auto validProfile = m_data->minecraftProfile.validity == Katabasis::Validity::Certain;
// IDK if this should be modified or not but still just to be sure
m_data->minecraftEntitlement.canPlayMinecraft = true;
m_data->minecraftEntitlement.ownsMinecraft = true;
auto validProfile = m_data->minecraftProfile.validity == Katabasis::Validity::Certain;
m_data->minecraftEntitlement.canPlayMinecraft = validProfile;
m_data->minecraftEntitlement.ownsMinecraft = validProfile;
}

emit finished(
AccountTaskState::STATE_WORKING,
tr("Minecraft Java profile acquisition succeeded.")
Expand Down
Loading

0 comments on commit b4bb083

Please sign in to comment.