aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt23
-rw-r--r--MultiMC.cpp15
-rw-r--r--MultiMC.h6
-rw-r--r--changelog.yaml4
-rw-r--r--gui/ConsoleWindow.cpp40
-rw-r--r--gui/ConsoleWindow.h7
-rw-r--r--gui/MainWindow.cpp93
-rw-r--r--gui/MainWindow.h15
-rw-r--r--gui/dialogs/SettingsDialog.cpp4
-rw-r--r--gui/widgets/IconLabel.cpp30
-rw-r--r--gui/widgets/IconLabel.h26
-rw-r--r--gui/widgets/LineSeparator.cpp37
-rw-r--r--gui/widgets/LineSeparator.h18
-rw-r--r--gui/widgets/ServerStatus.cpp115
-rw-r--r--gui/widgets/ServerStatus.h34
-rw-r--r--logic/BaseInstance.h2
-rw-r--r--logic/LegacyInstance.cpp12
-rw-r--r--logic/LegacyInstance.h2
-rw-r--r--logic/MinecraftProcess.cpp2
-rw-r--r--logic/MinecraftProcess.h19
-rw-r--r--logic/OneSixInstance.cpp13
-rw-r--r--logic/OneSixInstance.h2
-rw-r--r--logic/status/StatusChecker.cpp23
-rw-r--r--logic/status/StatusChecker.h11
-rw-r--r--resources/multimc/16x16/status-bad.pngbin0 -> 643 bytes
-rw-r--r--resources/multimc/16x16/status-good.pngbin0 -> 714 bytes
-rw-r--r--resources/multimc/22x22/status-bad.pngbin0 -> 968 bytes
-rw-r--r--resources/multimc/22x22/status-good.pngbin0 -> 994 bytes
-rw-r--r--resources/multimc/24x24/status-bad.pngbin0 -> 1102 bytes
-rw-r--r--resources/multimc/24x24/status-good.pngbin0 -> 1066 bytes
-rw-r--r--resources/multimc/32x32/status-bad.pngbin0 -> 1422 bytes
-rw-r--r--resources/multimc/32x32/status-good.pngbin0 -> 1400 bytes
-rw-r--r--resources/multimc/48x48/status-bad.pngbin0 -> 2389 bytes
-rw-r--r--resources/multimc/48x48/status-good.pngbin0 -> 2248 bytes
-rw-r--r--resources/multimc/64x64/status-bad.pngbin0 -> 2827 bytes
-rw-r--r--resources/multimc/64x64/status-good.pngbin0 -> 2954 bytes
-rw-r--r--resources/multimc/multimc.qrc16
-rw-r--r--resources/multimc/scalable/status-bad.svg142
-rw-r--r--resources/multimc/scalable/status-good.svg201
-rw-r--r--resources/sources/status-bad.svg262
-rw-r--r--resources/sources/status-good.svg293
-rw-r--r--resources/sources/status-terrible.svg262
-rw-r--r--translations/CMakeLists.txt2
43 files changed, 757 insertions, 974 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2d25fc6b..531f7342 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -104,7 +104,7 @@ set(MultiMC_NEWS_RSS_URL "http://multimc.org/rss.xml" CACHE STRING "URL to fetch
######## Set version numbers ########
set(MultiMC_VERSION_MAJOR 0)
set(MultiMC_VERSION_MINOR 3)
-set(MultiMC_VERSION_HOTFIX 4)
+set(MultiMC_VERSION_HOTFIX 5)
# Build number
set(MultiMC_VERSION_BUILD -1 CACHE STRING "Build number. -1 for no build number.")
@@ -335,16 +335,23 @@ SET(MULTIMC_SOURCES
gui/dialogs/NotificationDialog.cpp
# GUI - widgets
- gui/widgets/Common.h
gui/widgets/Common.cpp
- gui/widgets/ModListView.h
- gui/widgets/ModListView.cpp
- gui/widgets/VersionListView.h
- gui/widgets/VersionListView.cpp
- gui/widgets/LabeledToolButton.h
+ gui/widgets/Common.h
+ gui/widgets/IconLabel.cpp
+ gui/widgets/IconLabel.h
gui/widgets/LabeledToolButton.cpp
- gui/widgets/MCModInfoFrame.h
+ gui/widgets/LabeledToolButton.h
+ gui/widgets/LineSeparator.cpp
+ gui/widgets/LineSeparator.h
gui/widgets/MCModInfoFrame.cpp
+ gui/widgets/MCModInfoFrame.h
+ gui/widgets/ModListView.cpp
+ gui/widgets/ModListView.h
+ gui/widgets/ServerStatus.cpp
+ gui/widgets/ServerStatus.h
+ gui/widgets/VersionListView.cpp
+ gui/widgets/VersionListView.h
+
# GUI - instance group view
gui/groupview/Group.cpp
diff --git a/MultiMC.cpp b/MultiMC.cpp
index dc878a32..bdebe181 100644
--- a/MultiMC.cpp
+++ b/MultiMC.cpp
@@ -161,6 +161,17 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override)
#endif
}
+ // static data paths... mostly just for translations
+ #ifdef Q_OS_LINUX
+ QDir foo(PathCombine(binPath, ".."));
+ staticDataPath = foo.absolutePath();
+ #elif defined(Q_OS_WIN32)
+ staticDataPath = binPath;
+ #elif defined(Q_OS_MAC)
+ QDir foo(PathCombine(rootPath, "Contents/Resources"));
+ staticDataPath = foo.absolutePath();
+ #endif
+
// init the logger
initLogger();
@@ -179,6 +190,7 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override)
}
QLOG_INFO() << "Binary path : " << binPath;
QLOG_INFO() << "Application root path : " << rootPath;
+ QLOG_INFO() << "Static data path : " << staticDataPath;
// load settings
initGlobalSettings();
@@ -287,7 +299,8 @@ void MultiMC::initTranslations()
}
m_mmc_translator.reset(new QTranslator());
- if (m_mmc_translator->load("mmc_" + locale.bcp47Name(), MMC->root() + "/translations"))
+ if (m_mmc_translator->load("mmc_" + locale.bcp47Name(),
+ MMC->staticData() + "/translations"))
{
QLOG_DEBUG() << "Loading MMC Language File for"
<< locale.bcp47Name().toLocal8Bit().constData() << "...";
diff --git a/MultiMC.h b/MultiMC.h
index 2455cbb4..0fd60b7d 100644
--- a/MultiMC.h
+++ b/MultiMC.h
@@ -150,6 +150,11 @@ public:
*/
bool openJsonEditor(const QString &filename);
+ /// this is the static data. it stores things that don't move.
+ const QString &staticData()
+ {
+ return staticDataPath;
+ }
/// this is the root of the 'installation'. Used for automatic updates
const QString &root()
{
@@ -218,6 +223,7 @@ private:
UpdateFlags m_updateOnExitFlags = None;
QString rootPath;
+ QString staticDataPath;
QString binPath;
QString dataPath;
QString origcwdPath;
diff --git a/changelog.yaml b/changelog.yaml
index f850d6d2..7fb75534 100644
--- a/changelog.yaml
+++ b/changelog.yaml
@@ -72,3 +72,7 @@
- Add french translation
- Download and cache FML libs for legacy versions
- Update the OS X icon
+ - Fix FTB libraries not being used properly
+0.3.5
+ - More versions are now selectable when changing instance versions
+ - Fix for Forge/FML changing its mcmod.info metadata format
diff --git a/gui/ConsoleWindow.cpp b/gui/ConsoleWindow.cpp
index 18a617e0..ac3752c5 100644
--- a/gui/ConsoleWindow.cpp
+++ b/gui/ConsoleWindow.cpp
@@ -24,9 +24,11 @@
#include <gui/Platform.h>
#include <gui/dialogs/CustomMessageBox.h>
#include <gui/dialogs/ProgressDialog.h>
+#include "dialogs/ScreenshotDialog.h"
#include "logic/net/PasteUpload.h"
#include "logic/icons/IconList.h"
+#include <logic/screenshots/ScreenshotList.h>
ConsoleWindow::ConsoleWindow(MinecraftProcess *mcproc, QWidget *parent)
: QMainWindow(parent), ui(new Ui::ConsoleWindow), proc(mcproc)
@@ -35,14 +37,12 @@ ConsoleWindow::ConsoleWindow(MinecraftProcess *mcproc, QWidget *parent)
ui->setupUi(this);
connect(mcproc, SIGNAL(log(QString, MessageLevel::Enum)), this,
SLOT(write(QString, MessageLevel::Enum)));
- connect(mcproc, SIGNAL(ended(BaseInstance *, int, QProcess::ExitStatus)), this,
- SLOT(onEnded(BaseInstance *, int, QProcess::ExitStatus)));
- connect(mcproc, SIGNAL(prelaunch_failed(BaseInstance *, int, QProcess::ExitStatus)), this,
- SLOT(onEnded(BaseInstance *, int, QProcess::ExitStatus)));
- connect(mcproc, SIGNAL(launch_failed(BaseInstance *)), this,
- SLOT(onLaunchFailed(BaseInstance *)));
-
- connect(ui->btnScreenshots, &QPushButton::clicked, this, &ConsoleWindow::uploadScreenshots);
+ connect(mcproc, SIGNAL(ended(InstancePtr, int, QProcess::ExitStatus)), this,
+ SLOT(onEnded(InstancePtr, int, QProcess::ExitStatus)));
+ connect(mcproc, SIGNAL(prelaunch_failed(InstancePtr, int, QProcess::ExitStatus)), this,
+ SLOT(onEnded(InstancePtr, int, QProcess::ExitStatus)));
+ connect(mcproc, SIGNAL(launch_failed(InstancePtr)), this,
+ SLOT(onLaunchFailed(InstancePtr)));
restoreState(
QByteArray::fromBase64(MMC->settings()->get("ConsoleWindowState").toByteArray()));
@@ -172,6 +172,26 @@ void ConsoleWindow::on_closeButton_clicked()
close();
}
+void ConsoleWindow::on_btnScreenshots_clicked()
+{
+ ScreenshotList *list = new ScreenshotList(proc->instance());
+ Task *task = list->load();
+ ProgressDialog prog(this);
+ prog.exec(task);
+ if (!task->successful())
+ {
+ CustomMessageBox::selectable(this, tr("Failed to load screenshots!"),
+ task->failReason(), QMessageBox::Warning)->exec();
+ return;
+ }
+ ScreenshotDialog dialog(list, this);
+ if (dialog.exec() == ScreenshotDialog::Accepted)
+ {
+ CustomMessageBox::selectable(this, tr("Done uploading!"), dialog.message(),
+ QMessageBox::Information)->exec();
+ }
+}
+
void ConsoleWindow::setMayClose(bool mayclose)
{
if(mayclose)
@@ -242,7 +262,7 @@ void ConsoleWindow::on_btnKillMinecraft_clicked()
ui->btnKillMinecraft->setEnabled(true);
}
-void ConsoleWindow::onEnded(BaseInstance *instance, int code, QProcess::ExitStatus status)
+void ConsoleWindow::onEnded(InstancePtr instance, int code, QProcess::ExitStatus status)
{
bool peacefulExit = code == 0 && status != QProcess::CrashExit;
ui->btnKillMinecraft->setEnabled(false);
@@ -274,7 +294,7 @@ void ConsoleWindow::onEnded(BaseInstance *instance, int code, QProcess::ExitStat
}
}
-void ConsoleWindow::onLaunchFailed(BaseInstance *instance)
+void ConsoleWindow::onLaunchFailed(InstancePtr instance)
{
ui->btnKillMinecraft->setEnabled(false);
diff --git a/gui/ConsoleWindow.h b/gui/ConsoleWindow.h
index e21da33c..17c64392 100644
--- a/gui/ConsoleWindow.h
+++ b/gui/ConsoleWindow.h
@@ -51,7 +51,6 @@ private:
signals:
void isClosing();
- void uploadScreenshots();
public
slots:
@@ -71,9 +70,11 @@ slots:
private
slots:
void on_closeButton_clicked();
+ void on_btnScreenshots_clicked();
void on_btnKillMinecraft_clicked();
- void onEnded(BaseInstance *instance, int code, QProcess::ExitStatus status);
- void onLaunchFailed(BaseInstance *instance);
+
+ void onEnded(InstancePtr instance, int code, QProcess::ExitStatus status);
+ void onLaunchFailed(InstancePtr instance);
// FIXME: add handlers for the other MinecraftProcess signals (pre/post launch command
// failures)
diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp
index f437f8a3..5ba05b2a 100644
--- a/gui/MainWindow.cpp
+++ b/gui/MainWindow.cpp
@@ -47,6 +47,7 @@
#include "gui/Platform.h"
#include "gui/widgets/LabeledToolButton.h"
+#include "widgets/ServerStatus.h"
#include "gui/dialogs/SettingsDialog.h"
#include "gui/dialogs/NewInstanceDialog.h"
@@ -63,8 +64,8 @@
#include "gui/dialogs/AccountSelectDialog.h"
#include "gui/dialogs/UpdateDialog.h"
#include "gui/dialogs/EditAccountDialog.h"
-#include "gui/dialogs/ScreenshotDialog.h"
#include "gui/dialogs/NotificationDialog.h"
+#include "dialogs/ScreenshotDialog.h"
#include "gui/ConsoleWindow.h"
@@ -216,29 +217,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
connect(MMC->instances().get(), SIGNAL(dataIsInvalid()), SLOT(selectionBad()));
m_statusLeft = new QLabel(tr("No instance selected"), this);
- m_statusRight = new QLabel(tr("No status available"), this);
- m_statusRefresh = new QToolButton(this);
- m_statusRefresh->setCheckable(true);
- m_statusRefresh->setToolButtonStyle(Qt::ToolButtonIconOnly);
- m_statusRefresh->setIcon(QIcon::fromTheme("refresh"));
-
+ m_statusRight = new ServerStatus(this);
statusBar()->addPermanentWidget(m_statusLeft, 1);
statusBar()->addPermanentWidget(m_statusRight, 0);
- statusBar()->addPermanentWidget(m_statusRefresh, 0);
-
- // Start status checker
- {
- connect(MMC->statusChecker().get(), &StatusChecker::statusLoaded, this,
- &MainWindow::updateStatusUI);
- connect(MMC->statusChecker().get(), &StatusChecker::statusLoadingFailed, this,
- &MainWindow::updateStatusFailedUI);
-
- connect(m_statusRefresh, &QAbstractButton::clicked, this, &MainWindow::reloadStatus);
- connect(&statusTimer, &QTimer::timeout, this, &MainWindow::reloadStatus);
- statusTimer.setSingleShot(true);
-
- reloadStatus();
- }
// Add "manage accounts" button, right align
QWidget *spacer = new QWidget();
@@ -620,60 +601,6 @@ void MainWindow::updateNewsLabel()
}
}
-static QString convertStatus(const QString &status)
-{
- QString ret = "?";
-
- if (status == "green")
- ret = "↑";
- else if (status == "yellow")
- ret = "-";
- else if (status == "red")
- ret = "↓";
-
- return "<span style=\"font-size:11pt; font-weight:600;\">" + ret + "</span>";
-}
-
-void MainWindow::reloadStatus()
-{
- m_statusRefresh->setChecked(true);
- MMC->statusChecker()->reloadStatus();
- // updateStatusUI();
-}
-
-static QString makeStatusString(const QMap<QString, QString> statuses)
-{
- QString status = "";
- status += "Web: " + convertStatus(statuses["minecraft.net"]);
- status += " Account: " + convertStatus(statuses["account.mojang.com"]);
- status += " Skins: " + convertStatus(statuses["skins.minecraft.net"]);
- status += " Auth: " + convertStatus(statuses["authserver.mojang.com"]);
- status += " Session: " + convertStatus(statuses["sessionserver.mojang.com"]);
-
- return status;
-}
-
-void MainWindow::updateStatusUI()
-{
- auto statusChecker = MMC->statusChecker();
- auto statuses = statusChecker->getStatusEntries();
-
- QString status = makeStatusString(statuses);
- m_statusRefresh->setChecked(false);
-
- m_statusRight->setText(status);
-
- statusTimer.start(60 * 1000);
-}
-
-void MainWindow::updateStatusFailedUI()
-{
- m_statusRight->setText(makeStatusString(QMap<QString, QString>()));
- m_statusRefresh->setChecked(false);
-
- statusTimer.start(60 * 1000);
-}
-
void MainWindow::updateAvailable(QString repo, QString versionName, int versionId)
{
UpdateDialog dlg;
@@ -1317,15 +1244,19 @@ void MainWindow::launchInstance(InstancePtr instance, AuthSessionPtr session, Ba
Q_ASSERT_X(instance != NULL, "launchInstance", "instance is NULL");
Q_ASSERT_X(session.get() != nullptr, "launchInstance", "session is NULL");
- proc = instance->prepareForLaunch(session);
- if (!proc)
+ QString launchScript;
+
+ if(!instance->prepareForLaunch(session, launchScript))
return;
+ MinecraftProcess *proc = new MinecraftProcess(instance);
+ proc->setLaunchScript(launchScript);
+ proc->setWorkdir(instance->minecraftRoot());
+
this->hide();
console = new ConsoleWindow(proc);
connect(console, SIGNAL(isClosing()), this, SLOT(instanceEnded()));
- connect(console, &ConsoleWindow::uploadScreenshots, this, &MainWindow::on_actionScreenshots_triggered);
proc->setLogin(session);
proc->arm();
@@ -1347,7 +1278,7 @@ void MainWindow::launchInstance(InstancePtr instance, AuthSessionPtr session, Ba
dialog.setLabelText(tr("Waiting for profiler..."));
connect(&dialog, &QProgressDialog::canceled, profilerInstance, &BaseProfiler::abortProfiling);
dialog.show();
- connect(profilerInstance, &BaseProfiler::readyToLaunch, [&dialog, this](const QString &message)
+ connect(profilerInstance, &BaseProfiler::readyToLaunch, [&dialog, this, proc](const QString &message)
{
dialog.accept();
QMessageBox msg;
@@ -1360,7 +1291,7 @@ void MainWindow::launchInstance(InstancePtr instance, AuthSessionPtr session, Ba
msg.exec();
proc->launch();
});
- connect(profilerInstance, &BaseProfiler::abortLaunch, [&dialog, this](const QString &message)
+ connect(profilerInstance, &BaseProfiler::abortLaunch, [&dialog, this, proc](const QString &message)
{
dialog.accept();
QMessageBox msg;
diff --git a/gui/MainWindow.h b/gui/MainWindow.h
index d610a87d..69cf11b0 100644
--- a/gui/MainWindow.h
+++ b/gui/MainWindow.h
@@ -111,6 +111,8 @@ slots:
void on_actionEditInstNotes_triggered();
+ void on_actionScreenshots_triggered();
+
/*!
* Launches the currently selected instance with the default account.
* If no default account is selected, prompts the user to pick an account.
@@ -144,8 +146,6 @@ slots:
void showInstanceContextMenu(const QPoint &);
- void on_actionScreenshots_triggered();
-
void updateToolsMenu();
void skinJobFinished();
@@ -171,12 +171,6 @@ slots:
void updateNewsLabel();
- void updateStatusUI();
-
- void updateStatusFailedUI();
-
- void reloadStatus();
-
/*!
* Runs the DownloadUpdateTask and installs updates.
*/
@@ -206,12 +200,9 @@ private:
Task *m_versionLoadTask;
QLabel *m_statusLeft;
- QLabel *m_statusRight;
- QToolButton *m_statusRefresh;
+ class ServerStatus *m_statusRight;
QMenu *accountMenu;
QToolButton *accountMenuButton;
QAction *manageAccountsAction;
-
- QTimer statusTimer;
};
diff --git a/gui/dialogs/SettingsDialog.cpp b/gui/dialogs/SettingsDialog.cpp
index 7ec48336..2dd19077 100644
--- a/gui/dialogs/SettingsDialog.cpp
+++ b/gui/dialogs/SettingsDialog.cpp
@@ -407,8 +407,8 @@ void SettingsDialog::loadSettings(SettingsObject *s)
// Language
ui->languageBox->clear();
ui->languageBox->addItem(tr("English"), QLocale(QLocale::English));
- foreach(const QString & lang,
- QDir(MMC->root() + "/translations").entryList(QStringList() << "*.qm", QDir::Files))
+ foreach(const QString & lang, QDir(MMC->staticData() + "/translations")
+ .entryList(QStringList() << "*.qm", QDir::Files))
{
QLocale locale(lang.section(QRegExp("[_\.]"), 1));
ui->languageBox->addItem(QLocale::languageToString(locale.language()), locale);
diff --git a/gui/widgets/IconLabel.cpp b/gui/widgets/IconLabel.cpp
new file mode 100644
index 00000000..1bfe8dc9
--- /dev/null
+++ b/gui/widgets/IconLabel.cpp
@@ -0,0 +1,30 @@
+#include "IconLabel.h"
+
+#include <QStyle>
+#include <QStyleOption>
+#include <QLayout>
+#include <QPainter>
+#include <QRect>
+
+IconLabel::IconLabel(QWidget *parent, QIcon icon, QSize size)
+ : QWidget(parent), m_icon(icon), m_size(size)
+{
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+}
+
+QSize IconLabel::sizeHint() const
+{
+ return m_size;
+}
+
+void IconLabel::setIcon(QIcon icon)
+{
+ m_icon = icon;
+ update();
+}
+
+void IconLabel::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ m_icon.paint(&p, contentsRect());
+}
diff --git a/gui/widgets/IconLabel.h b/gui/widgets/IconLabel.h
new file mode 100644
index 00000000..a2f1eef3
--- /dev/null
+++ b/gui/widgets/IconLabel.h
@@ -0,0 +1,26 @@
+#pragma once
+#include <QWidget>
+#include <QIcon>
+
+class QStyleOption;
+
+/**
+ * This is a trivial widget that paints a QIcon of the specified size.
+ */
+class IconLabel : public QWidget
+{
+ Q_OBJECT
+
+public:
+ /// Create a line separator. orientation is the orientation of the line.
+ explicit IconLabel(QWidget *parent, QIcon icon, QSize size);
+
+ virtual QSize sizeHint() const;
+ virtual void paintEvent(QPaintEvent *);
+
+ void setIcon(QIcon icon);
+
+private:
+ QSize m_size;
+ QIcon m_icon;
+};
diff --git a/gui/widgets/LineSeparator.cpp b/gui/widgets/LineSeparator.cpp
new file mode 100644
index 00000000..f4ee173d
--- /dev/null
+++ b/gui/widgets/LineSeparator.cpp
@@ -0,0 +1,37 @@
+#include "LineSeparator.h"
+
+#include <QStyle>
+#include <QStyleOption>
+#include <QLayout>
+#include <QPainter>
+
+void LineSeparator::initStyleOption(QStyleOption *option) const
+{
+ option->initFrom(this);
+ // in a horizontal layout, the line is vertical (and vice versa)
+ if (m_orientation == Qt::Vertical)
+ option->state |= QStyle::State_Horizontal;
+}
+
+LineSeparator::LineSeparator(QWidget *parent, Qt::Orientation orientation)
+ : QWidget(parent), m_orientation(orientation)
+{
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+}
+
+QSize LineSeparator::sizeHint() const
+{
+ QStyleOption opt;
+ initStyleOption(&opt);
+ const int extent =
+ style()->pixelMetric(QStyle::PM_ToolBarSeparatorExtent, &opt, parentWidget());
+ return QSize(extent, extent);
+}
+
+void LineSeparator::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ QStyleOption opt;
+ initStyleOption(&opt);
+ style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &opt, &p, parentWidget());
+}
diff --git a/gui/widgets/LineSeparator.h b/gui/widgets/LineSeparator.h
new file mode 100644
index 00000000..376f2056
--- /dev/null
+++ b/gui/widgets/LineSeparator.h
@@ -0,0 +1,18 @@
+#pragma once
+#include <QWidget>
+
+class QStyleOption;
+
+class LineSeparator : public QWidget
+{
+ Q_OBJECT
+
+public:
+ /// Create a line separator. orientation is the orientation of the line.
+ explicit LineSeparator(QWidget *parent, Qt::Orientation orientation = Qt::Vertical);
+ QSize sizeHint() const;
+ void paintEvent(QPaintEvent *);
+ void initStyleOption(QStyleOption *option) const;
+private:
+ Qt::Orientation m_orientation = Qt::Vertical;
+};
diff --git a/gui/widgets/ServerStatus.cpp b/gui/widgets/ServerStatus.cpp
new file mode 100644
index 00000000..e540a301
--- /dev/null
+++ b/gui/widgets/ServerStatus.cpp
@@ -0,0 +1,115 @@
+#include "ServerStatus.h"
+#include "LineSeparator.h"
+#include "IconLabel.h"
+#include "logic/status/StatusChecker.h"
+
+#include "MultiMC.h"
+
+#include <QHBoxLayout>
+#include <QFrame>
+#include <QLabel>
+#include <QMap>
+#include <QToolButton>
+#include <QAction>
+
+ServerStatus::ServerStatus(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f)
+{
+ layout = new QHBoxLayout(this);
+ layout->setContentsMargins(0, 0, 0, 0);
+ goodIcon = QIcon::fromTheme("status-good");
+ badIcon = QIcon::fromTheme("status-bad");
+
+ addStatus("minecraft.net", tr("Web"));
+ addLine();
+ addStatus("account.mojang.com", tr("Account"));
+ addLine();
+ addStatus("skins.minecraft.net", tr("Skins"));
+ addLine();
+ addStatus("authserver.mojang.com", tr("Auth"));
+ addLine();
+ addStatus("sessionserver.mojang.com", tr("Session"));
+
+ m_statusRefresh = new QToolButton(this);
+ m_statusRefresh->setCheckable(true);
+ m_statusRefresh->setToolButtonStyle(Qt::ToolButtonIconOnly);
+ m_statusRefresh->setIcon(QIcon::fromTheme("refresh"));
+ layout->addWidget(m_statusRefresh);
+
+ setLayout(layout);
+
+ // Start status checker
+ {
+ auto reloader = MMC->statusChecker().get();
+ connect(reloader, &StatusChecker::statusChanged, this, &ServerStatus::StatusChanged);
+ connect(reloader, &StatusChecker::statusLoading, this, &ServerStatus::StatusReloading);
+ connect(m_statusRefresh, &QAbstractButton::clicked, this, &ServerStatus::reloadStatus);
+ MMC->statusChecker()->startTimer(60000);
+ reloadStatus();
+ }
+}
+
+ServerStatus::~ServerStatus()
+{
+}
+
+void ServerStatus::reloadStatus()
+{
+ MMC->statusChecker()->reloadStatus();
+}
+
+void ServerStatus::addLine()
+{
+ layout->addWidget(new LineSeparator(this));
+}
+
+void ServerStatus::addStatus(QString key, QString name)
+{
+ {
+ auto label = new IconLabel(this, badIcon, QSize(16, 16));
+ label->setToolTip(key);
+ serverLabels[key] = label;
+ layout->addWidget(label);
+ }
+ {
+ auto label = new QLabel(this);
+ label->setText(name);
+ label->setToolTip(key);
+ layout->addWidget(label);
+ }
+}
+
+void ServerStatus::setStatus(QString key, bool value)
+{
+ if (!serverLabels.contains(key))
+ return;
+ IconLabel *label = serverLabels[key];
+ label->setIcon(value ? goodIcon : badIcon);
+}
+
+void ServerStatus::StatusChanged(const QMap<QString, QString> statusEntries)
+{
+ auto convertStatus = [&](QString status)->bool
+ {
+ if (status == "green")
+ return true;
+ else if (status == "yellow")
+ return false;
+ else if (status == "red")
+ return false;
+ return false;
+ }
+ ;
+ auto iter = statusEntries.begin();
+ while (iter != statusEntries.end())
+ {
+ QString key = iter.key();
+ bool value = convertStatus(iter.value());
+ setStatus(key, value);
+ iter++;
+ }
+}
+
+void ServerStatus::StatusReloading(bool is_reloading)
+{
+ m_statusRefresh->setChecked(is_reloading);
+}
diff --git a/gui/widgets/ServerStatus.h b/gui/widgets/ServerStatus.h
new file mode 100644
index 00000000..2244031b
--- /dev/null
+++ b/gui/widgets/ServerStatus.h
@@ -0,0 +1,34 @@
+#pragma once
+#include <QString>
+#include <QWidget>
+#include <QMap>
+#include <QIcon>
+#include <memory>
+
+class IconLabel;
+class QToolButton;
+class QHBoxLayout;
+
+class ServerStatus: public QWidget
+{
+ Q_OBJECT
+public:
+ explicit ServerStatus(QWidget *parent = nullptr, Qt::WindowFlags f = 0);
+ virtual ~ServerStatus();
+ ;
+public slots:
+ void reloadStatus();
+ void StatusChanged(const QMap<QString, QString> statuses);
+ void StatusReloading(bool is_reloading);
+
+private: /* methods */
+ void addLine();
+ void addStatus(QString key, QString name);
+ void setStatus(QString key, bool value);
+private: /* data */
+ QHBoxLayout * layout = nullptr;
+ QToolButton *m_statusRefresh = nullptr;
+ QMap<QString, IconLabel *> serverLabels;
+ QIcon goodIcon;
+ QIcon badIcon;
+};
diff --git a/logic/BaseInstance.h b/logic/BaseInstance.h
index d38ae409..16791592 100644
--- a/logic/BaseInstance.h
+++ b/logic/BaseInstance.h
@@ -163,7 +163,7 @@ public:
virtual std::shared_ptr<Task> doUpdate() = 0;
/// returns a valid minecraft process, ready for launch with the given account.
- virtual MinecraftProcess *prepareForLaunch(AuthSessionPtr account) = 0;
+ virtual bool prepareForLaunch(AuthSessionPtr account, QString & launchScript) = 0;
/// do any necessary cleanups after the instance finishes. also runs before
/// 'prepareForLaunch'
diff --git a/logic/LegacyInstance.cpp b/logic/LegacyInstance.cpp
index d06b8827..6648e059 100644
--- a/logic/LegacyInstance.cpp
+++ b/