aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--launcher/CMakeLists.txt2
-rw-r--r--launcher/LaunchController.cpp31
-rw-r--r--launcher/LaunchController.h32
-rw-r--r--launcher/Launcher.cpp141
-rw-r--r--launcher/Launcher.h6
-rw-r--r--launcher/LauncherMessage.cpp31
-rw-r--r--launcher/LauncherMessage.h13
-rw-r--r--launcher/minecraft/auth/AccountList.cpp10
-rw-r--r--launcher/minecraft/auth/AccountList.h1
-rw-r--r--launcher/minecraft/launch/MinecraftServerTarget.cpp1
-rw-r--r--libraries/LocalPeer/include/LocalPeer.h4
-rw-r--r--libraries/LocalPeer/src/LocalPeer.cpp7
12 files changed, 195 insertions, 84 deletions
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index 691ff004..eba8f8a1 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -565,6 +565,8 @@ SET(LAUNCHER_SOURCES
Launcher.cpp
UpdateController.cpp
UpdateController.h
+ LauncherMessage.h
+ LauncherMessage.cpp
# GUI - general utilities
DesktopServices.h
diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp
index a865caab..1c1e41e6 100644
--- a/launcher/LaunchController.cpp
+++ b/launcher/LaunchController.cpp
@@ -34,9 +34,11 @@ void LaunchController::executeTask()
login();
}
-// FIXME: minecraft specific
-void LaunchController::login() {
- JavaCommon::checkJVMArgs(m_instance->settings()->get("JvmArgs").toString(), m_parentWidget);
+void LaunchController::decideAccount()
+{
+ if(m_accountToUse) {
+ return;
+ }
// Find an account to use.
std::shared_ptr<AccountList> accounts = LAUNCHER->accounts();
@@ -60,8 +62,8 @@ void LaunchController::login() {
}
}
- MinecraftAccountPtr account = accounts->activeAccount();
- if (account.get() == nullptr)
+ m_accountToUse = accounts->activeAccount();
+ if (m_accountToUse == nullptr)
{
// If no default account is set, ask the user which one to use.
ProfileSelectDialog selectDialog(
@@ -73,16 +75,23 @@ void LaunchController::login() {
selectDialog.exec();
// Launch the instance with the selected account.
- account = selectDialog.selectedAccount();
+ m_accountToUse = selectDialog.selectedAccount();
// If the user said to use the account as default, do that.
- if (selectDialog.useAsGlobalDefault() && account.get() != nullptr) {
- accounts->setActiveAccount(account->profileId());
+ if (selectDialog.useAsGlobalDefault() && m_accountToUse) {
+ accounts->setActiveAccount(m_accountToUse->profileId());
}
}
+}
+
+
+void LaunchController::login() {
+ JavaCommon::checkJVMArgs(m_instance->settings()->get("JvmArgs").toString(), m_parentWidget);
+
+ decideAccount();
// if no account is selected, we bail
- if (!account.get())
+ if (!m_accountToUse)
{
emitFailed(tr("No account selected for launch."));
return;
@@ -102,10 +111,10 @@ void LaunchController::login() {
m_session->wants_online = m_online;
std::shared_ptr<AccountTask> task;
if(!password.isNull()) {
- task = account->login(m_session, password);
+ task = m_accountToUse->login(m_session, password);
}
else {
- task = account->refresh(m_session);
+ task = m_accountToUse->refresh(m_session);
}
if (task)
{
diff --git a/launcher/LaunchController.h b/launcher/LaunchController.h
index 5f177e00..7ed4b09e 100644
--- a/launcher/LaunchController.h
+++ b/launcher/LaunchController.h
@@ -4,6 +4,7 @@
#include <tools/BaseProfiler.h>
#include "minecraft/launch/MinecraftServerTarget.h"
+#include "minecraft/auth/MinecraftAccount.h"
class InstanceWindow;
class LaunchController: public Task
@@ -15,39 +16,45 @@ public:
LaunchController(QObject * parent = nullptr);
virtual ~LaunchController(){};
- void setInstance(InstancePtr instance)
- {
+ void setInstance(InstancePtr instance) {
m_instance = instance;
}
- InstancePtr instance()
- {
+
+ InstancePtr instance() {
return m_instance;
}
- void setOnline(bool online)
- {
+
+ void setOnline(bool online) {
m_online = online;
}
- void setProfiler(BaseProfilerFactory *profiler)
- {
+
+ void setProfiler(BaseProfilerFactory *profiler) {
m_profiler = profiler;
}
- void setParentWidget(QWidget * widget)
- {
+
+ void setParentWidget(QWidget * widget) {
m_parentWidget = widget;
}
- void setServerToJoin(MinecraftServerTargetPtr serverToJoin)
- {
+
+ void setServerToJoin(MinecraftServerTargetPtr serverToJoin) {
m_serverToJoin = std::move(serverToJoin);
}
+
+ void setAccountToUse(MinecraftAccountPtr accountToUse) {
+ m_accountToUse = std::move(accountToUse);
+ }
+
QString id()
{
return m_instance->id();
}
+
bool abort() override;
private:
void login();
void launchInstance();
+ void decideAccount();
private slots:
void readyForLaunch();
@@ -62,6 +69,7 @@ private:
InstancePtr m_instance;
QWidget * m_parentWidget = nullptr;
InstanceWindow *m_console = nullptr;
+ MinecraftAccountPtr m_accountToUse = nullptr;
AuthSessionPtr m_session;
shared_qobject_ptr<LaunchTask> m_launcher;
MinecraftServerTargetPtr m_serverToJoin;
diff --git a/launcher/Launcher.cpp b/launcher/Launcher.cpp
index 5036b7ff..a69fb8f3 100644
--- a/launcher/Launcher.cpp
+++ b/launcher/Launcher.cpp
@@ -23,6 +23,8 @@
#include "themes/BrightTheme.h"
#include "themes/CustomTheme.h"
+#include "LauncherMessage.h"
+
#include "setupwizard/SetupWizard.h"
#include "setupwizard/LanguageWizardPage.h"
#include "setupwizard/JavaWizardPage.h"
@@ -227,8 +229,7 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
// --dir
parser.addOption("dir");
parser.addShortOpt("dir", 'd');
- parser.addDocumentation("dir", "Use the supplied folder as application root instead of "
- "the binary location (use '.' for current)");
+ parser.addDocumentation("dir", "Use the supplied folder as application root instead of the binary location (use '.' for current)");
// --launch
parser.addOption("launch");
parser.addShortOpt("launch", 'l');
@@ -236,8 +237,11 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
// --server
parser.addOption("server");
parser.addShortOpt("server", 's');
- parser.addDocumentation("server", "Join the specified server on launch "
- "(only valid in combination with --launch)");
+ parser.addDocumentation("server", "Join the specified server on launch (only valid in combination with --launch)");
+ // --profile
+ parser.addOption("profile");
+ parser.addShortOpt("profile", 'a');
+ parser.addDocumentation("profile", "Use the account specified by its profile name (only valid in combination with --launch)");
// --alive
parser.addSwitch("alive");
parser.addDocumentation("alive", "Write a small '" + liveCheckFile + "' file after the launcher starts");
@@ -280,6 +284,7 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
}
m_instanceIdToLaunch = args["launch"].toString();
m_serverToJoin = args["server"].toString();
+ m_profileToUse = args["profile"].toString();
m_liveCheck = args["alive"].toBool();
m_zipToImport = args["import"].toUrl();
@@ -346,6 +351,13 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
return;
}
+ if(m_instanceIdToLaunch.isEmpty() && !m_profileToUse.isEmpty())
+ {
+ std::cerr << "--account can only be used in combination with --launch!" << std::endl;
+ m_status = Launcher::Failed;
+ return;
+ }
+
#if defined(Q_OS_MAC)
// move user data to new location if on macOS and it still exists in Contents/MacOS
QDir fi(applicationDirPath());
@@ -419,30 +431,38 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
// FIXME: you can run the same binaries with multiple data dirs and they won't clash. This could cause issues for updates.
m_peerInstance = new LocalPeer(this, appID);
connect(m_peerInstance, &LocalPeer::messageReceived, this, &Launcher::messageReceived);
- if(m_peerInstance->isClient())
- {
+ if(m_peerInstance->isClient()) {
int timeout = 2000;
if(m_instanceIdToLaunch.isEmpty())
{
- m_peerInstance->sendMessage("activate", timeout);
+ LauncherMessage activate;
+ activate.command = "activate";
+ m_peerInstance->sendMessage(activate.serialize(), timeout);
if(!m_zipToImport.isEmpty())
{
- m_peerInstance->sendMessage("import " + m_zipToImport.toString(), timeout);
+ LauncherMessage import;
+ import.command = "import";
+ import.args.insert("path", m_zipToImport.toString());
+ m_peerInstance->sendMessage(import.serialize(), timeout);
}
}
else
{
+ LauncherMessage launch;
+ launch.command = "launch";
+ launch.args["id"] = m_instanceIdToLaunch;
+
if(!m_serverToJoin.isEmpty())
{
- m_peerInstance->sendMessage(
- "launch-with-server " + m_instanceIdToLaunch + " " + m_serverToJoin, timeout);
+ launch.args["server"] = m_serverToJoin;
}
- else
+ if(!m_profileToUse.isEmpty())
{
- m_peerInstance->sendMessage("launch " + m_instanceIdToLaunch, timeout);
+ launch.args["profile"] = m_profileToUse;
}
+ m_peerInstance->sendMessage(launch.serialize(), timeout);
}
m_status = Launcher::Succeeded;
return;
@@ -977,18 +997,26 @@ void Launcher::performMainStartupAction()
if(inst)
{
MinecraftServerTargetPtr serverToJoin = nullptr;
+ MinecraftAccountPtr accountToUse = nullptr;
+ qDebug() << "<> Instance" << m_instanceIdToLaunch << "launching";
if(!m_serverToJoin.isEmpty())
{
+ // FIXME: validate the server string
serverToJoin.reset(new MinecraftServerTarget(MinecraftServerTarget::parse(m_serverToJoin)));
- qDebug() << "<> Instance" << m_instanceIdToLaunch << "launching with server" << m_serverToJoin;
+ qDebug() << " Launching with server" << m_serverToJoin;
}
- else
+
+ if(!m_profileToUse.isEmpty())
{
- qDebug() << "<> Instance" << m_instanceIdToLaunch << "launching";
+ accountToUse = accounts()->getAccountByProfileName(m_profileToUse);
+ if(!accountToUse) {
+ return;
+ }
+ qDebug() << " Launching with account" << m_profileToUse;
}
- launch(inst, true, nullptr, serverToJoin);
+ launch(inst, true, nullptr, serverToJoin, accountToUse);
return;
}
}
@@ -1032,7 +1060,7 @@ Launcher::~Launcher()
#endif
}
-void Launcher::messageReceived(const QString& message)
+void Launcher::messageReceived(const QByteArray& message)
{
if(status() != Initialized)
{
@@ -1040,7 +1068,10 @@ void Launcher::messageReceived(const QString& message)
return;
}
- QString command = message.section(' ', 0, 0);
+ LauncherMessage received;
+ received.parse(message);
+
+ auto & command = received.command;
if(command == "activate")
{
@@ -1048,52 +1079,54 @@ void Launcher::messageReceived(const QString& message)
}
else if(command == "import")
{
- QString arg = message.section(' ', 1);
- if(arg.isEmpty())
+ QString path = received.args["path"];
+ if(path.isEmpty())
{
qWarning() << "Received" << command << "message without a zip path/URL.";
return;
}
- m_mainWindow->droppedURLs({ QUrl(arg) });
+ m_mainWindow->droppedURLs({ QUrl(path) });
}
else if(command == "launch")
{
- QString arg = message.section(' ', 1);
- if(arg.isEmpty())
- {
- qWarning() << "Received" << command << "message without an instance ID.";
- return;
- }
- auto inst = instances()->getInstanceById(arg);
- if(inst)
- {
- launch(inst, true, nullptr);
+ QString id = received.args["id"];
+ QString server = received.args["server"];
+ QString profile = received.args["profile"];
+
+ InstancePtr instance;
+ if(!id.isEmpty()) {
+ instance = instances()->getInstanceById(id);
+ if(!instance) {
+ qWarning() << "Launch command requires an valid instance ID. " << id << "resolves to nothing.";
+ return;
+ }
}
- }
- else if(command == "launch-with-server")
- {
- QString instanceID = message.section(' ', 1, 1);
- QString serverToJoin = message.section(' ', 2, 2);
- if(instanceID.isEmpty())
- {
- qWarning() << "Received" << command << "message without an instance ID.";
+ else {
+ qWarning() << "Launch command called without an instance ID...";
return;
}
- if(serverToJoin.isEmpty())
- {
- qWarning() << "Received" << command << "message without a server to join.";
- return;
+
+ MinecraftServerTargetPtr serverObject = nullptr;
+ if(!server.isEmpty()) {
+ serverObject = std::make_shared<MinecraftServerTarget>(MinecraftServerTarget::parse(server));
}
- auto inst = instances()->getInstanceById(instanceID);
- if(inst)
- {
- launch(
- inst,
- true,
- nullptr,
- std::make_shared<MinecraftServerTarget>(MinecraftServerTarget::parse(serverToJoin))
- );
+
+ MinecraftAccountPtr accountObject;
+ if(!profile.isEmpty()) {
+ accountObject = accounts()->getAccountByProfileName(profile);
+ if(!accountObject) {
+ qWarning() << "Launch command requires the specified profile to be valid. " << profile << "does not resolve to any account.";
+ return;
+ }
}
+
+ launch(
+ instance,
+ true,
+ nullptr,
+ serverObject,
+ accountObject
+ );
}
else
{
@@ -1189,7 +1222,8 @@ bool Launcher::launch(
InstancePtr instance,
bool online,
BaseProfilerFactory *profiler,
- MinecraftServerTargetPtr serverToJoin
+ MinecraftServerTargetPtr serverToJoin,
+ MinecraftAccountPtr accountToUse
) {
if(m_updateRunning)
{
@@ -1212,6 +1246,7 @@ bool Launcher::launch(
controller->setOnline(online);
controller->setProfiler(profiler);
controller->setServerToJoin(serverToJoin);
+ controller->setAccountToUse(accountToUse);
if(window)
{
controller->setParentWidget(window);
diff --git a/launcher/Launcher.h b/launcher/Launcher.h
index f4a20122..8d97525f 100644
--- a/launcher/Launcher.h
+++ b/launcher/Launcher.h
@@ -156,13 +156,14 @@ public slots:
InstancePtr instance,
bool online = true,
BaseProfilerFactory *profiler = nullptr,
- MinecraftServerTargetPtr serverToJoin = nullptr
+ MinecraftServerTargetPtr serverToJoin = nullptr,
+ MinecraftAccountPtr accountToUse = nullptr
);
bool kill(InstancePtr instance);
private slots:
void on_windowClose();
- void messageReceived(const QString & message);
+ void messageReceived(const QByteArray & message);
void controllerSucceeded();
void controllerFailed(const QString & error);
void analyticsSettingChanged(const Setting &setting, QVariant value);
@@ -229,6 +230,7 @@ private:
public:
QString m_instanceIdToLaunch;
QString m_serverToJoin;
+ QString m_profileToUse;
bool m_liveCheck = false;
QUrl m_zipToImport;
std::unique_ptr<QFile> logFile;
diff --git a/launcher/LauncherMessage.cpp b/launcher/LauncherMessage.cpp
new file mode 100644
index 00000000..4cc56e22
--- /dev/null
+++ b/launcher/LauncherMessage.cpp
@@ -0,0 +1,31 @@
+#include "LauncherMessage.h"
+
+#include <QJsonDocument>
+#include <QJsonObject>
+
+void LauncherMessage::parse(const QByteArray & input) {
+ auto doc = QJsonDocument::fromBinaryData(input);
+ auto root = doc.object();
+
+ command = root.value("command").toString();
+ args.clear();
+
+ auto parsedArgs = root.value("args").toObject();
+ for(auto iter = parsedArgs.begin(); iter != parsedArgs.end(); iter++) {
+ args[iter.key()] = iter.value().toString();
+ }
+}
+
+QByteArray LauncherMessage::serialize() {
+ QJsonObject root;
+ root.insert("command", command);
+ QJsonObject outArgs;
+ for (auto iter = args.begin(); iter != args.end(); iter++) {
+ outArgs[iter.key()] = iter.value();
+ }
+ root.insert("args", outArgs);
+
+ QJsonDocument out;
+ out.setObject(root);
+ return out.toBinaryData();
+}
diff --git a/launcher/LauncherMessage.h b/launcher/LauncherMessage.h
new file mode 100644
index 00000000..024b16a5
--- /dev/null
+++ b/launcher/LauncherMessage.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <QString>
+#include <QMap>
+#include <QByteArray>
+
+struct LauncherMessage {
+ QString command;
+ QMap<QString, QString> args;
+
+ QByteArray serialize();
+ void parse(const QByteArray & input);
+};
diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp
index 76af0ac0..a76cac55 100644
--- a/launcher/minecraft/auth/AccountList.cpp
+++ b/launcher/minecraft/auth/AccountList.cpp
@@ -47,6 +47,16 @@ int AccountList::findAccountByProfileId(const QString& profileId) const {
return -1;
}
+MinecraftAccountPtr AccountList::getAccountByProfileName(const QString& profileName) const {
+ for (int i = 0; i < count(); i++) {
+ MinecraftAccountPtr account = at(i);
+ if (account->profileName() == profileName) {
+ return account;
+ }
+ }
+ return nullptr;
+}
+
const MinecraftAccountPtr AccountList::at(int i) const
{
return MinecraftAccountPtr(m_accounts.at(i));
diff --git a/launcher/minecraft/auth/AccountList.h b/launcher/minecraft/auth/AccountList.h
index ed08bb1d..e275eb17 100644
--- a/launcher/minecraft/auth/AccountList.h
+++ b/launcher/minecraft/auth/AccountList.h
@@ -62,6 +62,7 @@ public:
void addAccount(const MinecraftAccountPtr account);
void removeAccount(QModelIndex index);
int findAccountByProfileId(const QString &profileId) const;
+ MinecraftAccountPtr getAccountByProfileName(const QString &profileName) const;
/*!
* Sets the path to load/save the list file from/to.
diff --git a/launcher/minecraft/launch/MinecraftServerTarget.cpp b/launcher/minecraft/launch/MinecraftServerTarget.cpp
index 569273b6..0f98f356 100644
--- a/launcher/minecraft/launch/MinecraftServerTarget.cpp
+++ b/launcher/minecraft/launch/MinecraftServerTarget.cpp
@@ -17,6 +17,7 @@
#include <QStringList>
+// FIXME: the way this is written, it can't ever do any sort of validation and can accept total junk
MinecraftServerTarget MinecraftServerTarget::parse(const QString &fullAddress) {
QStringList split = fullAddress.split(":");
diff --git a/libraries/LocalPeer/include/LocalPeer.h b/libraries/LocalPeer/include/LocalPeer.h
index a24e4775..3619ed5d 100644
--- a/libraries/LocalPeer/include/LocalPeer.h
+++ b/libraries/LocalPeer/include/LocalPeer.h
@@ -83,11 +83,11 @@ public:
LocalPeer(QObject *parent, const ApplicationId &appId);
~LocalPeer();
bool isClient();
- bool sendMessage(const QString &message, int timeout);
+ bool sendMessage(const QByteArray &message, int timeout);
ApplicationId applicationId() const;
Q_SIGNALS:
- void messageReceived(const QString &message);
+ void messageReceived(const QByteArray &message);
protected Q_SLOTS:
void receiveConnection();
diff --git a/libraries/LocalPeer/src/LocalPeer.cpp b/libraries/LocalPeer/src/LocalPeer.cpp
index 129f3abc..cb218466 100644
--- a/libraries/LocalPeer/src/LocalPeer.cpp
+++ b/libraries/LocalPeer/src/LocalPeer.cpp
@@ -155,7 +155,7 @@ bool LocalPeer::isClient()
}
-bool LocalPeer::sendMessage(const QString &message, int timeout)
+bool LocalPeer::sendMessage(const QByteArray &message, int timeout)
{
if (!isClient())
return false;
@@ -177,7 +177,7 @@ bool LocalPeer::sendMessage(const QString &message, int timeout)
return false;
}
- QByteArray uMsg(message.toUtf8());
+ QByteArray uMsg(message);
QDataStream ds(&socket);
ds.writeBytes(uMsg.constData(), uMsg.size());
@@ -232,10 +232,9 @@ void LocalPeer::receiveConnection()
delete socket;
return;
}
- QString message(QString::fromUtf8(uMsg));
socket->write(ack, qstrlen(ack));
socket->waitForBytesWritten(1000);
socket->waitForDisconnected(1000); // make sure client reads ack
delete socket;
- emit messageReceived(message); //### (might take a long time to return)
+ emit messageReceived(uMsg); //### (might take a long time to return)
}