summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AppSettings.cpp73
-rw-r--r--AppSettings.h29
-rw-r--r--AppVersion.cpp46
-rw-r--r--CMakeLists.txt30
-rw-r--r--MultiMC.cpp242
-rw-r--r--MultiMC.h76
-rw-r--r--MultiMC.pro47
-rw-r--r--MultiMCVersion.h (renamed from AppVersion.h)24
-rw-r--r--depends/classparser/src/javautils.cpp1
-rw-r--r--depends/settings/include/settingsobject.h10
-rw-r--r--depends/settings/src/settingsobject.cpp2
-rw-r--r--gui/IconPickerDialog.cpp15
-rw-r--r--gui/aboutdialog.cpp8
-rw-r--r--gui/mainwindow.cpp56
-rw-r--r--gui/mainwindow.h1
-rw-r--r--gui/newinstancedialog.cpp9
-rw-r--r--gui/settingsdialog.cpp8
-rw-r--r--logic/BaseInstance.cpp3
-rw-r--r--logic/InstanceLauncher.cpp74
-rw-r--r--logic/InstanceLauncher.h28
-rw-r--r--logic/LegacyInstance.cpp8
-rw-r--r--logic/LegacyUpdate.cpp18
-rw-r--r--logic/OneSixAssets.cpp29
-rw-r--r--logic/OneSixUpdate.cpp20
-rw-r--r--logic/lists/IconList.cpp (renamed from logic/IconListModel.cpp)27
-rw-r--r--logic/lists/IconList.h (renamed from logic/IconListModel.h)9
-rw-r--r--logic/lists/InstanceList.cpp11
-rw-r--r--logic/lists/LwjglVersionList.cpp6
-rw-r--r--logic/lists/MinecraftVersionList.cpp6
-rw-r--r--logic/net/ByteArrayDownload.cpp62
-rw-r--r--logic/net/ByteArrayDownload.h24
-rw-r--r--logic/net/CacheDownload.cpp122
-rw-r--r--logic/net/CacheDownload.h34
-rw-r--r--logic/net/Download.h54
-rw-r--r--logic/net/DownloadJob.cpp153
-rw-r--r--logic/net/DownloadJob.h95
-rw-r--r--logic/net/FileDownload.cpp111
-rw-r--r--logic/net/FileDownload.h35
-rw-r--r--logic/net/HttpMetaCache.cpp231
-rw-r--r--logic/net/HttpMetaCache.h57
-rw-r--r--logic/net/NetWorker.cpp30
-rw-r--r--logic/net/NetWorker.h31
-rw-r--r--logic/tasks/LoginTask.cpp8
-rw-r--r--main.cpp224
-rw-r--r--multimc_pragma.h49
45 files changed, 1321 insertions, 915 deletions
diff --git a/AppSettings.cpp b/AppSettings.cpp
deleted file mode 100644
index 8b0265eb..00000000
--- a/AppSettings.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Copyright 2013 MultiMC Contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "AppSettings.h"
-
-#include <setting.h>
-
-#include <QPoint>
-#include <QApplication>
-//#include <QColor>
-
-AppSettings::AppSettings(QObject *parent) :
- INISettingsObject(QApplication::applicationDirPath() + "/multimc.cfg",parent)
-{
- // Updates
- registerSetting(new Setting("UseDevBuilds", false));
- registerSetting(new Setting("AutoUpdate", true));
-
- // Folders
- registerSetting(new Setting("InstanceDir", "instances"));
- registerSetting(new Setting("CentralModsDir", "mods"));
- registerSetting(new Setting("LWJGLDir", "lwjgl"));
-
- // Console
- registerSetting(new Setting("ShowConsole", true));
- registerSetting(new Setting("AutoCloseConsole", true));
-
- // Toolbar settings
- registerSetting(new Setting("InstanceToolbarVisible", true));
- registerSetting(new Setting("InstanceToolbarPosition", QPoint()));
-
- // Console Colors
-// registerSetting(new Setting("SysMessageColor", QColor(Qt::blue)));
-// registerSetting(new Setting("StdOutColor", QColor(Qt::black)));
-// registerSetting(new Setting("StdErrColor", QColor(Qt::red)));
-
- // Window Size
- registerSetting(new Setting("LaunchMaximized", false));
- registerSetting(new Setting("MinecraftWinWidth", 854));
- registerSetting(new Setting("MinecraftWinHeight", 480));
-
- // Auto login
- registerSetting(new Setting("AutoLogin", false));
-
- // Memory
- registerSetting(new Setting("MinMemAlloc", 512));
- registerSetting(new Setting("MaxMemAlloc", 1024));
- registerSetting(new Setting("PermGen", 64));
-
- // Java Settings
- registerSetting(new Setting("JavaPath", "java"));
- registerSetting(new Setting("JvmArgs", ""));
-
- // Custom Commands
- registerSetting(new Setting("PreLaunchCommand", ""));
- registerSetting(new Setting("PostExitCommand", ""));
-
- // Misc
- registerSetting(new Setting("TheCat", false)); // The Cat
- registerSetting(new Setting("NoHide", false)); // Shall the main window hide on instance launch
-}
diff --git a/AppSettings.h b/AppSettings.h
deleted file mode 100644
index d8f21de1..00000000
--- a/AppSettings.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* Copyright 2013 MultiMC Contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <QObject>
-
-#include <inisettingsobject.h>
-
-class AppSettings : public INISettingsObject
-{
- Q_OBJECT
-public:
- explicit AppSettings(QObject *parent = 0);
-};
-
-
diff --git a/AppVersion.cpp b/AppVersion.cpp
deleted file mode 100644
index 86b00920..00000000
--- a/AppVersion.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Copyright 2013 MultiMC Contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "AppVersion.h"
-
-#include "config.h"
-
-AppVersion AppVersion::current(VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD);
-
-AppVersion::AppVersion(int major, int minor, int revision, int build, QObject *parent) :
- QObject(parent)
-{
- this->major = major;
- this->minor = minor;
- this->revision = revision;
- this->build = build;
-}
-
-AppVersion::AppVersion(const AppVersion& ver)
-{
- this->major = ver.major;
- this->minor = ver.minor;
- this->revision = ver.revision;
- this->build = ver.build;
-}
-
-QString AppVersion::toString() const
-{
- return QString("%1.%2.%3.%4").arg(
- QString::number(major),
- QString::number(minor),
- QString::number(revision),
- QString::number(build));
-}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8c9cf983..cbc3d842 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -147,9 +147,8 @@ ADD_DEFINITIONS(-DLIBGROUPVIEW_STATIC)
######## Headers ########
SET(MULTIMC_HEADERS
-multimc_pragma.h
-AppVersion.h
-AppSettings.h
+MultiMC.h
+MultiMCVersion.h
gui/mainwindow.h
gui/settingsdialog.h
@@ -181,9 +180,16 @@ logic/MinecraftProcess.h
logic/Mod.h
logic/ModList.h
+# Basic instance launcher for starting from terminal
+logic/InstanceLauncher.h
+
# network stuffs
+logic/net/Download.h
+logic/net/FileDownload.h
+logic/net/ByteArrayDownload.h
+logic/net/CacheDownload.h
logic/net/DownloadJob.h
-logic/net/NetWorker.h
+logic/net/HttpMetaCache.h
# legacy instances
logic/LegacyInstance.h
@@ -207,7 +213,7 @@ logic/lists/InstanceList.h
logic/lists/InstVersionList.h
logic/lists/MinecraftVersionList.h
logic/lists/LwjglVersionList.h
-logic/IconListModel.h
+logic/lists/IconList.h
# Tasks
logic/tasks/Task.h
@@ -217,9 +223,7 @@ logic/tasks/LoginTask.h
######## Sources ########
SET(MULTIMC_SOURCES
-main.cpp
-AppVersion.cpp
-AppSettings.cpp
+MultiMC.cpp
gui/mainwindow.cpp
gui/settingsdialog.cpp
@@ -248,9 +252,15 @@ logic/MinecraftProcess.cpp
logic/Mod.cpp
logic/ModList.cpp
+# Basic instance launcher for starting from terminal
+logic/InstanceLauncher.cpp
+
# network stuffs - to be moved into a depend lib ~_~
-logic/net/NetWorker.cpp
+logic/net/FileDownload.cpp
+logic/net/ByteArrayDownload.cpp
+logic/net/CacheDownload.cpp
logic/net/DownloadJob.cpp
+logic/net/HttpMetaCache.cpp
# legacy instances
logic/LegacyInstance.cpp
@@ -272,7 +282,7 @@ logic/lists/InstanceList.cpp
logic/lists/InstVersionList.cpp
logic/lists/MinecraftVersionList.cpp
logic/lists/LwjglVersionList.cpp
-logic/IconListModel.cpp
+logic/lists/IconList.cpp
# Tasks
logic/tasks/Task.cpp
diff --git a/MultiMC.cpp b/MultiMC.cpp
new file mode 100644
index 00000000..c93701b8
--- /dev/null
+++ b/MultiMC.cpp
@@ -0,0 +1,242 @@
+
+#include "MultiMC.h"
+#include <iostream>
+#include <QDir>
+#include <QNetworkAccessManager>
+
+#include "gui/mainwindow.h"
+#include "logic/lists/InstanceList.h"
+#include "logic/lists/IconList.h"
+#include "logic/InstanceLauncher.h"
+#include "logic/net/HttpMetaCache.h"
+
+
+#include "pathutils.h"
+#include "cmdutils.h"
+#include <inisettingsobject.h>
+#include <setting.h>
+
+#include "config.h"
+using namespace Util::Commandline;
+
+MultiMC::MultiMC ( int& argc, char** argv )
+ :QApplication ( argc, argv )
+{
+ setOrganizationName("Forkk");
+ setApplicationName("MultiMC 5");
+
+ // Print app header
+ std::cout << "MultiMC 5" << std::endl;
+ std::cout << "(c) 2013 MultiMC Contributors" << std::endl << std::endl;
+
+ // Commandline parsing
+ QHash<QString, QVariant> args;
+ {
+ Parser parser(FlagStyle::GNU, ArgumentStyle::SpaceAndEquals);
+
+ // --help
+ parser.addSwitch("help");
+ parser.addShortOpt("help", 'h');
+ parser.addDocumentation("help", "display this help and exit.");
+ // --version
+ parser.addSwitch("version");
+ parser.addShortOpt("version", 'V');
+ parser.addDocumentation("version", "display program version and exit.");
+ // --dir
+ parser.addOption("dir", applicationDirPath());
+ parser.addShortOpt("dir", 'd');
+ parser.addDocumentation("dir", "use the supplied directory as MultiMC root instead of the binary location (use '.' for current)");
+ // --update
+ parser.addOption("update");
+ parser.addShortOpt("update", 'u');
+ parser.addDocumentation("update", "replaces the given file with the running executable", "<path>");
+ // --quietupdate
+ parser.addSwitch("quietupdate");
+ parser.addShortOpt("quietupdate", 'U');
+ parser.addDocumentation("quietupdate", "doesn't restart MultiMC after installing updates");
+ // --launch
+ parser.addOption("launch");
+ parser.addShortOpt("launch", 'l');
+ parser.addDocumentation("launch", "tries to launch the given instance", "<inst>");
+
+ // parse the arguments
+ try
+ {
+ args = parser.parse(arguments());
+ }
+ catch(ParsingError e)
+ {
+ std::cerr << "CommandLineError: " << e.what() << std::endl;
+ std::cerr << "Try '%1 -h' to get help on MultiMC's command line parameters." << std::endl;
+ m_status = MultiMC::Failed;
+ return;
+ }
+
+ // display help and exit
+ if (args["help"].toBool())
+ {
+ std::cout << qPrintable(parser.compileHelp(arguments()[0]));
+ m_status = MultiMC::Succeeded;
+ return;
+ }
+
+ // display version and exit
+ if (args["version"].toBool())
+ {
+ std::cout << "Version " << VERSION_STR << std::endl;
+ std::cout << "Git " << GIT_COMMIT << std::endl;
+ std::cout << "Tag: " << JENKINS_BUILD_TAG << " " << (ARCH==x64?"x86_64":"x86") << std::endl;
+ m_status = MultiMC::Succeeded;
+ return;
+ }
+
+ // update
+ // Note: cwd is always the current executable path!
+ if (!args["update"].isNull())
+ {
+ std::cout << "Performing MultiMC update: " << qPrintable(args["update"].toString()) << std::endl;
+ QString cwd = QDir::currentPath();
+ QDir::setCurrent(applicationDirPath());
+ QFile file(applicationFilePath());
+ file.copy(args["update"].toString());
+ if(args["quietupdate"].toBool())
+ {
+ m_status = MultiMC::Succeeded;
+ return;
+ }
+ QDir::setCurrent(cwd);
+ }
+ }
+
+ // change directory
+ QDir::setCurrent(args["dir"].toString());
+
+ // load settings
+ initGlobalSettings();
+
+ // and instances
+ m_instances = new InstanceList(m_settings->get("InstanceDir").toString(),this);
+ std::cout << "Loading Instances..." << std::endl;
+ m_instances->loadList();
+
+ // init the http meta cache
+ initHttpMetaCache();
+
+ // create the global network manager
+ m_qnam = new QNetworkAccessManager(this);
+
+ // Register meta types.
+ qRegisterMetaType<LoginResponse>("LoginResponse");
+
+ // launch instance, if that's what should be done
+ if (!args["launch"].isNull())
+ {
+ if(InstanceLauncher(args["launch"].toString()).launch())
+ m_status = MultiMC::Succeeded;
+ else
+ m_status = MultiMC::Failed;
+ return;
+ }
+ m_status = MultiMC::Initialized;
+}
+
+MultiMC::~MultiMC()
+{
+ delete m_settings;
+ delete m_metacache;
+}
+
+void MultiMC::initGlobalSettings()
+{
+ m_settings = new INISettingsObject("multimc.cfg", this);
+ // Updates
+ m_settings->registerSetting(new Setting("UseDevBuilds", false));
+ m_settings->registerSetting(new Setting("AutoUpdate", true));
+
+ // Folders
+ m_settings->registerSetting(new Setting("InstanceDir", "instances"));
+ m_settings->registerSetting(new Setting("CentralModsDir", "mods"));
+ m_settings->registerSetting(new Setting("LWJGLDir", "lwjgl"));
+
+ // Console
+ m_settings->registerSetting(new Setting("ShowConsole", true));
+ m_settings->registerSetting(new Setting("AutoCloseConsole", true));
+
+ // Toolbar settings
+ m_settings->registerSetting(new Setting("InstanceToolbarVisible", true));
+ m_settings->registerSetting(new Setting("InstanceToolbarPosition", QPoint()));
+
+ // Console Colors
+// m_settings->registerSetting(new Setting("SysMessageColor", QColor(Qt::blue)));
+// m_settings->registerSetting(new Setting("StdOutColor", QColor(Qt::black)));
+// m_settings->registerSetting(new Setting("StdErrColor", QColor(Qt::red)));
+
+ // Window Size
+ m_settings->registerSetting(new Setting("LaunchMaximized", false));
+ m_settings->registerSetting(new Setting("MinecraftWinWidth", 854));
+ m_settings->registerSetting(new Setting("MinecraftWinHeight", 480));
+
+ // Auto login
+ m_settings->registerSetting(new Setting("AutoLogin", false));
+
+ // Memory
+ m_settings->registerSetting(new Setting("MinMemAlloc", 512));
+ m_settings->registerSetting(new Setting("MaxMemAlloc", 1024));
+ m_settings->registerSetting(new Setting("PermGen", 64));
+
+ // Java Settings
+ m_settings->registerSetting(new Setting("JavaPath", "java"));
+ m_settings->registerSetting(new Setting("JvmArgs", ""));
+
+ // Custom Commands
+ m_settings->registerSetting(new Setting("PreLaunchCommand", ""));
+ m_settings->registerSetting(new Setting("PostExitCommand", ""));
+
+ // The cat
+ m_settings->registerSetting(new Setting("TheCat", false));
+
+ // Shall the main window hide on instance launch
+ m_settings->registerSetting(new Setting("NoHide", false));
+}
+
+void MultiMC::initHttpMetaCache()
+{
+ m_metacache = new HttpMetaCache("metacache");
+ m_metacache->addBase("assets", QDir("assets").absolutePath());
+ m_metacache->addBase("versions", QDir("versions").absolutePath());
+ m_metacache->addBase("libraries", QDir("libraries").absolutePath());
+ m_metacache->Load();
+}
+
+
+IconList* MultiMC::icons()
+{
+ if ( !m_icons )
+ {
+ m_icons = new IconList;
+ }
+ return m_icons;
+}
+
+
+int main(int argc, char *argv[])
+{
+ // initialize Qt
+ MultiMC app(argc, argv);
+
+ // show main window
+ MainWindow mainWin;
+ mainWin.show();
+
+ switch(app.status())
+ {
+ case MultiMC::Initialized:
+ return app.exec();
+ case MultiMC::Failed:
+ return 1;
+ case MultiMC::Succeeded:
+ return 0;
+ }
+}
+
+#include "MultiMC.moc" \ No newline at end of file
diff --git a/MultiMC.h b/MultiMC.h
new file mode 100644
index 00000000..0c8b673b
--- /dev/null
+++ b/MultiMC.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#include <QApplication>
+#include "MultiMCVersion.h"
+#include "config.h"
+
+class HttpMetaCache;
+class SettingsObject;
+class InstanceList;
+class IconList;
+class QNetworkAccessManager;
+
+#if defined(MMC)
+#undef MMC
+#endif
+#define MMC (static_cast<MultiMC *>(QCoreApplication::instance()))
+
+class MultiMC : public QApplication
+{
+ Q_OBJECT
+public:
+ enum Status
+ {
+ Failed,
+ Succeeded,
+ Initialized,
+ };
+
+public:
+ MultiMC ( int& argc, char** argv );
+ virtual ~MultiMC();
+
+ SettingsObject * settings()
+ {
+ return m_settings;
+ };
+
+ InstanceList * instances()
+ {
+ return m_instances;
+ };
+
+ IconList * icons();
+
+ Status status()
+ {
+ return m_status;
+ }
+
+ MultiMCVersion version()
+ {
+ return m_version;
+ }
+
+ QNetworkAccessManager * qnam()
+ {
+ return m_qnam;
+ }
+
+ HttpMetaCache * metacache()
+ {
+ return m_metacache;
+ }
+private:
+ void initGlobalSettings();
+
+ void initHttpMetaCache();
+private:
+ SettingsObject * m_settings = nullptr;
+ InstanceList * m_instances = nullptr;
+ IconList * m_icons = nullptr;
+ QNetworkAccessManager * m_qnam = nullptr;
+ HttpMetaCache * m_metacache = nullptr;
+ Status m_status = MultiMC::Failed;
+ MultiMCVersion m_version = {VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD};
+}; \ No newline at end of file
diff --git a/MultiMC.pro b/MultiMC.pro
deleted file mode 100644
index b82b2294..00000000
--- a/MultiMC.pro
+++ /dev/null
@@ -1,47 +0,0 @@
-#-------------------------------------------------
-#
-# Project created by QtCreator 2013-01-08T14:14:58
-#
-#-------------------------------------------------
-
-QT += core gui
-
-greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
-
-TARGET = MultiMC
-TEMPLATE = app
-
-
-SOURCES += main.cpp\
- gui/mainwindow.cpp \
- data/instancebase.cpp \
- util/pathutils.cpp \
- data/instancelist.cpp \
- data/stdinstance.cpp \
- data/inifile.cpp \
- gui/settingsdialog.cpp \
- gui/modeditwindow.cpp \
- util/appsettings.cpp \
- gui/instancesettings.cpp
-
-HEADERS += gui/mainwindow.h \
- data/instancebase.h \
- util/pathutils.h \
- data/instancelist.h \
- data/stdinstance.h \
- data/inifile.h \
- gui/settingsdialog.h \
- gui/modeditwindow.h \
- util/apputils.h \
- util/appsettings.h \
- gui/instancesettings.h
-
-FORMS += gui/mainwindow.ui \
- gui/settingsdialog.ui \
- gui/modeditwindow.ui \
- gui/instancesettings.ui \
- gui/logindialog.ui \
- gui/consolewindow.ui
-
-RESOURCES += \
- multimc.qrc
diff --git a/AppVersion.h b/MultiMCVersion.h
index 86f53950..70a2259e 100644
--- a/AppVersion.h
+++ b/MultiMCVersion.h
@@ -15,26 +15,26 @@
#pragma once
-#include <QObject>
+#include <QString>
/*!
* \brief The Version class represents a MultiMC version number.
*/
-class AppVersion : public QObject
+struct MultiMCVersion
{
- Q_OBJECT
-public:
- explicit AppVersion(int major = 0, int minor = 0, int revision = 0,
- int build = 0, QObject *parent = 0);
-
- AppVersion(const AppVersion& ver);
-
/*!
* \brief Converts the Version to a string.
* \return The version number in string format (major.minor.revision.build).
*/
- QString toString() const;
-
+ QString toString() const
+ {
+ return QString("%1.%2.%3.%4").arg(
+ QString::number(major),
+ QString::number(minor),
+ QString::number(revision),
+ QString::number(build));
+ }
+
/*!
* \brief The major version number.
* For MultiMC 5, this will always be 5.
@@ -59,7 +59,5 @@ public:
* a new build is run.
*/
int build;
-
- static AppVersion current;
};
diff --git a/depends/classparser/src/javautils.cpp b/depends/classparser/src/javautils.cpp
index 4a359031..3a5c6934 100644
--- a/depends/classparser/src/javautils.cpp
+++ b/depends/classparser/src/javautils.cpp
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "multimc_pragma.h"
#include "classfile.h"
#include "javautils.h"
diff --git a/depends/settings/include/settingsobject.h b/depends/settings/include/settingsobject.h
index a2f03699..e8bf5c83 100644
--- a/depends/settings/include/settingsobject.h
+++ b/depends/settings/include/settingsobject.h
@@ -13,8 +13,7 @@
* limitations under the License.
*/
-#ifndef SETTINGSOBJECT_H
-#define SETTINGSOBJECT_H
+#pragma once
#include <QObject>
#include <QMap>
@@ -183,10 +182,3 @@ protected:
private:
QMap<QString, Setting *> m_settings;
};
-
-/*!
- * \brief A global settings object.
- */
-LIBSETTINGS_EXPORT extern SettingsObject *globalSettings;
-
-#endif // SETTINGSOBJECT_H
diff --git a/depends/settings/src/settingsobject.cpp b/depends/settings/src/settingsobject.cpp
index bf7b8825..2ca544ad 100644
--- a/depends/settings/src/settingsobject.cpp
+++ b/depends/settings/src/settingsobject.cpp
@@ -18,8 +18,6 @@
#include <QVariant>
-SettingsObject *globalSettings;
-
SettingsObject::SettingsObject(QObject *parent) :
QObject(parent)
{
diff --git a/gui/IconPickerDialog.cpp b/gui/IconPickerDialog.cpp
index b75eb30c..2dd80292 100644
--- a/gui/IconPickerDialog.cpp
+++ b/gui/IconPickerDialog.cpp
@@ -1,7 +1,8 @@
+#include <MultiMC.h>
#include "IconPickerDialog.h"
#include "instancedelegate.h"
#include "ui_IconPickerDialog.h"
-#include "logic/IconListModel.h"
+#include "logic/lists/IconList.h"
#include <QKeyEvent>
#include <QPushButton>
#include <QFileDialog>
@@ -38,8 +39,7 @@ IconPickerDialog::IconPickerDialog(QWidget *parent) :
contentsWidget->installEventFilter(this);
- IconList * list = IconList::instance();
- contentsWidget->setModel(list);
+ contentsWidget->setModel(MMC->icons());
auto buttonAdd = ui->buttonBox->addButton("Add Icon",QDialogButtonBox::ResetRole);
auto buttonRemove = ui->buttonBox->addButton("Remove Icon",QDialogButtonBox::ResetRole);
@@ -71,7 +71,6 @@ bool IconPickerDialog::eventFilter ( QObject* obj, QEvent* evt)
return QDialog::eventFilter(obj ,evt);
}
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(evt);
- IconList * list = IconList::instance();
switch(keyEvent->key())
{
case Qt::Key_Delete:
@@ -89,14 +88,12 @@ bool IconPickerDialog::eventFilter ( QObject* obj, QEvent* evt)
void IconPickerDialog::addNewIcon()
{
QStringList fileNames = QFileDialog::getOpenFileNames(this, "Select Icons", QString(), "Icons (*.png *.jpg *.jpeg)");
- IconList * list = IconList::instance();
- list->installIcons(fileNames);
+ MMC->icons()->installIcons(fileNames);
}
void IconPickerDialog::removeSelectedIcon()
{
- IconList * list = IconList::instance();
- list->deleteIcon(selectedIconKey);
+ MMC->icons()->deleteIcon(selectedIconKey);
}
@@ -119,7 +116,7 @@ void IconPickerDialog::selectionChanged ( QItemSelection selected, QItemSelectio
int IconPickerDialog::exec ( QString selection )
{
- IconList * list = IconList::instance();
+ IconList * list = MMC->icons();
auto contentsWidget = ui->iconView;
selectedIconKey = selection;
diff --git a/gui/aboutdialog.cpp b/gui/aboutdialog.cpp
index 873cc175..9792d4fe 100644
--- a/gui/aboutdialog.cpp
+++ b/gui/aboutdialog.cpp
@@ -1,9 +1,7 @@
#include "aboutdialog.h"
#include "ui_aboutdialog.h"
-#include <AppVersion.h>
-
#include <QIcon>
-#include <QApplication>
+#include <MultiMC.h>
AboutDialog::AboutDialog(QWidget *parent) :
QDialog(parent),
@@ -12,10 +10,10 @@ AboutDialog::AboutDialog(QWidget *parent) :
ui->setupUi(this);
ui->icon->setPixmap(QIcon(":/icons/multimc/scalable/apps/multimc.svg").pixmap(64));
- ui->title->setText("MultiMC " + AppVersion::current.toString());
+ ui->title->setText("MultiMC " + MMC->version().toString());
connect(ui->closeButton, SIGNAL(clicked()), SLOT(close()));
- QApplication::instance()->connect(ui->aboutQt, SIGNAL(clicked()), SLOT(aboutQt()));
+ MMC->connect(ui->aboutQt, SIGNAL(clicked()), SLOT(aboutQt()));
}
AboutDialog::~AboutDialog()
diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp
index 152773e7..7ddc66a9 100644
--- a/gui/mainwindow.cpp
+++ b/gui/mainwindow.cpp
@@ -16,6 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <MultiMC.h>
#include "mainwindow.h"
#include "ui_mainwindow.h"
@@ -23,7 +24,7 @@
#include <QMenu>
#include <QMessageBox>
#include <QInputDialog>
-#include <QApplication>
+
#include <QDesktopServices>
#include <QUrl>
#include <QDir>
@@ -48,33 +49,30 @@
#include "gui/consolewindow.h"
#include "gui/instancesettings.h"
-#include "AppSettings.h"
-#include "AppVersion.h"
-
#include "logic/lists/InstanceList.h"
+#include "logic/lists/MinecraftVersionList.h"
+#include "logic/lists/LwjglVersionList.h"
+#include "logic/lists/IconList.h"
+
#include "logic/tasks/LoginTask.h"
#include "logic/BaseInstance.h"
#include "logic/InstanceFactory.h"
#include "logic/MinecraftProcess.h"
#include "logic/OneSixAssets.h"
#include "logic/OneSixUpdate.h"
-#include "logic/lists/MinecraftVersionList.h"
-#include "logic/lists/LwjglVersionList.h"
-#include <logic/IconListModel.h>
-#include <logic/LegacyInstance.h>
+
+#include "logic/LegacyInstance.h"
#include "instancedelegate.h"
#include "IconPickerDialog.h"
#include "LabeledToolButton.h"
#include "EditNotesDialog.h"
-MainWindow::MainWindow ( QWidget *parent ) :
- QMainWindow ( parent ),
- ui ( new Ui::MainWindow ),
- instList ( globalSettings->get ( "InstanceDir" ).toString() )
+MainWindow::MainWindow ( QWidget *parent )
+ :QMainWindow ( parent ), ui ( new Ui::MainWindow )
{
ui->setupUi ( this );
- setWindowTitle ( QString ( "MultiMC %1" ).arg ( AppVersion::current.toString() ) );
+ setWindowTitle ( QString ( "MultiMC %1" ).arg ( MMC->version().toString() ) );
// Set the selected instance to null
m_selectedInstance = nullptr;
@@ -126,7 +124,7 @@ MainWindow::MainWindow ( QWidget *parent ) :
//proxymodel->setDynamicSortFilter ( true );
// FIXME: instList should be global-ish, or at least not tied to the main window... maybe the application itself?
- proxymodel->setSourceModel ( &instList );
+ proxymodel->setSourceModel ( MMC->instances() );
proxymodel->sort ( 0 );
view->setFrameShape ( QFrame::NoFrame );
view->setModel ( proxymodel );
@@ -135,7 +133,7 @@ MainWindow::MainWindow ( QWidget *parent ) :
}
// The cat background
{
- bool cat_enable = globalSettings->get("TheCat").toBool();
+ bool cat_enable = MMC->settings()->get("TheCat").toBool();
ui->actionCAT->setChecked(cat_enable);
connect(ui->actionCAT, SIGNAL(toggled(bool)), SLOT(onCatToggled(bool)));
setCatBackground(cat_enable);
@@ -151,12 +149,11 @@ MainWindow::MainWindow ( QWidget *parent ) :
);
// model reset -> selection is invalid. All the instance pointers are wrong.
// FIXME: stop using POINTERS everywhere
- connect(&instList,SIGNAL(dataIsInvalid()),SLOT(selectionBad()));
+ connect(MMC->instances() ,SIGNAL(dataIsInvalid()),SLOT(selectionBad()));
// run the things that load and download other things... FIXME: this is NOT the place
// FIXME: invisible actions in the background = NOPE.
{
- instList.loadList();
if (!MinecraftVersionList::getMainList().isLoaded())
{
m_versionLoadTask = MinecraftVersionList::getMainList().getLoadTask();
@@ -212,7 +209,7 @@ bool MainWindow::eventFilter ( QObject* obj, QEvent* ev )
void MainWindow::onCatToggled ( bool state )
{
setCatBackground(state);
- globalSettings->set("TheCat", state);
+ MMC->settings()->set("TheCat", state);
}
void MainWindow::setCatBackground ( bool enabled )
@@ -264,7 +261,7 @@ void MainWindow::on_actionAddInstance_triggered()
BaseInstance *newInstance = NULL;
QString instDirName = DirNameFromString(newInstDlg.instName());
- QString instDir = PathCombine(globalSettings->get("InstanceDir").toString(), instDirName);
+ QString instDir = PathCombine(MMC->settings()->get("InstanceDir").toString(), instDirName);
auto &loader = InstanceFactory::get();
@@ -275,7 +272,7 @@ void MainWindow::on_actionAddInstance_triggered()
case InstanceFactory::NoCreateError:
newInstance->setName(newInstDlg.instName());
newInstance->setIconKey(newInstDlg.iconKey());
- instList.add(InstancePtr(newInstance));
+ MMC->instances()->add(InstancePtr(newInstance));
return;
case InstanceFactory::InstExists:
@@ -305,8 +302,7 @@ void MainWindow::on_actionChangeInstIcon_triggered()
if(dlg.result() == QDialog::Accepted)
{
m_selectedInstance->setIconKey(dlg.selectedIconKey);
- IconList * iconListModel = IconList::instance();
- auto ico =iconListModel->getIcon(dlg.selectedIconKey);
+ auto ico = MMC->icons()->getIcon(dlg.selectedIconKey);
ui->actionChangeInstIcon->setIcon(ico);
}
}
@@ -328,18 +324,18 @@ void MainWindow::on_actionChangeInstGroup_triggered()
void MainWindow::on_actionViewInstanceFolder_triggered()
{
- QString str = globalSettings->get ( "InstanceDir" ).toString();
+ QString str = MMC->settings()->get ( "InstanceDir" ).toString();
openDirInDefaultProgram ( str );
}
void MainWindow::on_actionRefresh_triggered()
{
- instList.loadList();
+ MMC->instances()->loadList();
}
void MainWindow::on_actionViewCentralModsFolder_triggered()
{
- openDirInDefaultProgram ( globalSettings->get ( "CentralModsDir" ).toString() , true);
+ openDirInDefaultProgram ( MMC->settings()->get ( "CentralModsDir" ).toString() , true);
}
void MainWindow::on_actionConfig_Folder_triggered()
@@ -365,7 +361,7 @@ void MainWindow::on_actionSettings_triggered()
void MainWindow::on_actionReportBug_triggered()
{
- openWebPage ( QUrl ( "http://jira.forkk.net/browse/MMC" ) );
+ openWebPage ( QUrl ( "http://multimc.myjetbrains.com/youtrack/dashboard#newissue=yes" ) );
}
void MainWindow::on_actionNews_triggered()
@@ -542,7 +538,7 @@ void MainWindow::launchInstance(BaseInstance *instance, LoginResponse response)
return;
// Prepare GUI: If it shall stay open disable the required parts
- if (globalSettings->get("NoHide").toBool())
+ if (MMC->settings()->get("NoHide").toBool())
{
ui->actionLaunchInstance->setEnabled(false);
}
@@ -647,8 +643,7 @@ void MainWindow::instanceChanged( const QModelIndex& current, const QModelIndex&
ui->actionEditInstMods->setEnabled(m_selectedInstance->menuActionEnabled("actionEditInstMods"));
statusBar()->clearMessage();
statusBar()->showMessage(m_selectedInstance->getStatusbarDescription());
- IconList * iconListModel = IconList::instance();
- auto ico =iconListModel->getIcon(iconKey);
+ auto ico =MMC->icons()->getIcon(iconKey);
ui->actionChangeInstIcon->setIcon(ico);
}
else
@@ -664,8 +659,7 @@ void MainWindow::selectionBad()
statusBar()->clearMessage();
ui->instanceToolBar->setEnabled(false);
renameButton->setText("Rename Instance");
- IconList * iconListModel = IconList::instance();
- auto ico =iconListModel->getIcon(iconKey);
+ auto ico = MMC->icons()->getIcon(iconKey);
ui->actionChangeInstIcon->setIcon(ico);
}
diff --git a/gui/mainwindow.h b/gui/mainwindow.h
index e8a6cbcf..2b0e1d34 100644
--- a/gui/mainwindow.h
+++ b/gui/mainwindow.h
@@ -135,7 +135,6 @@ private:
KCategoryDrawer * drawer;
KCategorizedView * view;
InstanceProxyModel * proxymodel;
- InstanceList instList;
MinecraftProcess *proc;
ConsoleWindow *console;
OneSixAssets *assets_downloader;
diff --git a/gui/newinstancedialog.cpp b/gui/newinstancedialog.cpp
index f0a70a1b..ac3bcd7d 100644
--- a/gui/newinstancedialog.cpp
+++ b/gui/newinstancedialog.cpp
@@ -13,12 +13,13 @@
* limitations under the License.
*/
+#include <MultiMC.h>
#include "newinstancedialog.h"
#include "ui_newinstancedialog.h"
#include "logic/InstanceFactory.h"
#include "logic/InstanceVersion.h"
-#include "logic/IconListModel.h"
+#include "logic/lists/IconList.h"
#include "logic/lists/MinecraftVersionList.h"
#include "logic/tasks/Task.h"
@@ -49,8 +50,7 @@ NewInstanceDialog::NewInstanceDialog(QWidget *parent) :
*/
setSelectedVersion(MinecraftVersionList::getMainList().getLatestStable());
InstIconKey = "infinity";
- IconList * list = IconList::instance();
- ui->iconButton->setIcon(list->getIcon(InstIconKey));
+ ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
}
NewInstanceDialog::~NewInstanceDialog()
@@ -113,9 +113,8 @@ void NewInstanceDialog::on_iconButton_clicked()
if(dlg.result() == QDialog::Accepted)
{
- IconList * list = IconList::instance();
InstIconKey = dlg.selectedIconKey;
- ui->iconButton->setIcon(list->getIcon(InstIconKey));
+ ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
}
}
diff --git a/gui/settingsdialog.cpp b/gui/settingsdialog.cpp
index 52093039..a1fbb8e7 100644
--- a/gui/settingsdialog.cpp
+++ b/gui/settingsdialog.cpp
@@ -16,8 +16,8 @@
#include "settingsdialog.h"
#include "ui_settingsdialog.h"
-#include "AppSettings.h"
-
+#include <MultiMC.h>
+#include <settingsobject.h>
#include <QFileDialog>
#include <QMessageBox>
@@ -27,7 +27,7 @@ SettingsDialog::SettingsDialog(QWidget *parent) :
{
ui->setupUi(this);
- loadSettings(globalSettings);
+ loadSettings(MMC->settings());
updateCheckboxStuff();
}
@@ -85,7 +85,7 @@ void SettingsDialog::on_maximizedCheckBox_clicked(bool checked)
void SettingsDialog::on_buttonBox_accepted()
{
- applySettings(globalSettings);
+ applySettings(MMC->settings());
}
void SettingsDialog::applySettings(SettingsObject *s)
diff --git a/logic/BaseInstance.cpp b/logic/BaseInstance.cpp
index bd3229c8..e166449f 100644
--- a/logic/BaseInstance.cpp
+++ b/logic/BaseInstance.cpp
@@ -18,6 +18,7 @@
#include <QFileInfo>
#include <QDir>
+#include <MultiMC.h>
#include "inisettingsobject.h"
#include "setting.h"
@@ -52,6 +53,8 @@ BaseInstance::BaseInstance( BaseInstancePrivate* d_in,
settings().registerSetting(new Setting("UseCustomBaseJar", true));
settings().registerSetting(new Setting("CustomBaseJar", ""));
+ auto globalSettings = MMC->settings();
+
// Java Settings
settings().registerSetting(new Setting("OverrideJava", false));
settings().registerSetting(new OverrideSetting("JavaPath", globalSettings->getSetting("JavaPath")));
diff --git a/logic/InstanceLauncher.cpp b/logic/InstanceLauncher.cpp
new file mode 100644
index 00000000..312f4c69
--- /dev/null
+++ b/logic/InstanceLauncher.cpp
@@ -0,0 +1,74 @@
+#include "InstanceLauncher.h"
+#include "MultiMC.h"
+
+#include <iostream>
+#include "gui/logindialog.h"
+#include "gui/taskdialog.h"
+#include "gui/consolewindow.h"
+#include "logic/tasks/LoginTask.h"
+#include "logic/MinecraftProcess.h"
+#include "lists/InstanceList.h"
+
+
+InstanceLauncher::InstanceLauncher ( QString instId )
+ :QObject(), instId ( instId )
+{}
+
+void InstanceLauncher::onTerminated()
+{
+ std::cout << "Minecraft exited" << std::endl;
+ MMC->quit();
+}
+
+void InstanceLauncher::onLoginComplete()
+{
+ LoginTask * task = ( LoginTask * ) QObject::sender();
+ auto result = task->getResult();
+ auto instance = MMC->instances()->getInstanceById(instId);
+ proc = instance->prepareForLaunch ( result.username, result.sessionID );
+ if ( !proc )
+ {
+ //FIXME: report error
+ return;
+ }
+ console = new ConsoleWindow();
+ console->show();
+
+ connect ( proc, SIGNAL ( ended() ), SLOT ( onTerminated() ) );
+ connect ( proc, SIGNAL ( log ( QString,MessageLevel::Enum ) ), console, SLOT ( write ( QString,MessageLevel::Enum ) ) );
+
+ proc->launch();
+}
+
+void InstanceLauncher::doLogin ( const QString& errorMsg )
+{
+ LoginDialog* loginDlg = new LoginDialog ( nullptr, errorMsg );
+ loginDlg->exec();
+ if ( loginDlg->result() == QDialog::Accepted )
+ {
+ UserInfo uInfo {loginDlg->getUsername(), loginDlg->getPassword() };
+
+ TaskDialog* tDialog = new TaskDialog ( nullptr );
+ LoginTask* loginTask = new LoginTask ( uInfo, tDialog );
+ connect ( loginTask, SIGNAL ( succeeded() ),SLOT ( onLoginComplete() ), Qt::QueuedConnection );
+ connect ( loginTask, SIGNAL ( failed ( QString ) ),SLOT ( doLogin ( QString ) ), Qt::QueuedConnection );
+ tDialog->exec ( loginTask );
+ }
+ //onLoginComplete(LoginResponse("Offline","Offline", 1));
+}
+
+int InstanceLauncher::launch()
+{
+ std::cout << "Launching Instance '" << qPrintable ( instId ) << "'" << std::endl;
+ auto instance = MMC->instances()->getInstanceById(instId);
+ if ( instance.isNull() )
+ {
+ std::cout << "Could not find instance requested. note that you have to specify the ID, not the NAME" << std::endl;
+ return 1;
+ }
+
+ std::cout << "Logging in..." << std::endl;
+ doLogin ( "" );
+
+ return MMC->exec();
+}
diff --git a/logic/InstanceLauncher.h b/logic/InstanceLauncher.h
new file mode 100644
index 00000000..de93e3d7
--- /dev/null
+++ b/logic/InstanceLauncher.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <QObject>
+
+class MinecraftProcess;
+class ConsoleWindow;
+
+// Commandline instance launcher
+class InstanceLauncher : public QObject
+{
+ Q_OBJECT
+
+private:
+ QString instId;
+ MinecraftProcess *proc;
+ ConsoleWindow *console;
+
+public:
+ InstanceLauncher(QString instId);
+
+private slots:
+ void onTerminated();
+ void onLoginComplete();
+ void doLogin(const QString &errorMsg);
+
+public:
+ int launch();
+};
diff --git a/logic/LegacyInstance.cpp b/logic/LegacyInstance.cpp
index 124cdfcb..0672d2c8 100644
--- a/logic/LegacyInstance.cpp
+++ b/logic/LegacyInstance.cpp
@@ -2,7 +2,7 @@
#include "LegacyInstance_p.h"
#include "MinecraftProcess.h"
#include "LegacyUpdate.h"
-#include "IconListModel.h"
+#include "lists/IconList.h"
#include <setting.h>
#include <pathutils.h>
#include <cmdutils.h>
@@ -10,6 +10,7 @@
#include <QFileInfo>
#include <QDir>
#include <QImage>
+#include <MultiMC.h>
#define LAUNCHER_FILE "MultiMCLauncher.jar"
@@ -32,8 +33,7 @@ MinecraftProcess* LegacyInstance::prepareForLaunch(QString user, QString session
{
MinecraftProcess * proc = new MinecraftProcess(this);
- IconList * list = IconList::instance();
- QIcon icon = list->getIcon(iconKey());
+ QIcon icon = MMC->icons()->getIcon(iconKey());
auto pixmap = icon.pixmap(128,128);
pixmap.save(PathCombine(minecraftRoot(), "icon.png"),"PNG");
@@ -66,7 +66,7 @@ MinecraftProcess* LegacyInstance::prepareForLaunch(QString user, QString session
args << QString("-Xdock:name=\"%1\"").arg(windowTitle);
#endif
- QString lwjgl = QDir(globalSettings->get("LWJGLDir").toString() + "/" + lwjglVersion()).absolutePath();
+ QString lwjgl = QDir(MMC->settings()->get("LWJGLDir").toString() + "/" + lwjglVersion()).absolutePath();
// launcher arguments
args << QString("-Xms%1m").arg(settings().get("MinMemAlloc").toInt());
diff --git a/logic/LegacyUpdate.cpp b/logic/LegacyUpdate.cpp
index 3d286373..c75a0011 100644
--- a/logic/LegacyUpdate.cpp
+++ b/logic/LegacyUpdate.cpp
@@ -3,7 +3,7 @@
#include "lists/MinecraftVersionList.h"
#include "BaseInstance.h"
#include "LegacyInstance.h"
-#include "net/NetWorker.h"
+#include "MultiMC.h"
#include "ModList.h"
#include <pathutils.h>
#include <quazip.h>
@@ -52,15 +52,15 @@ void LegacyUpdate::lwjglStart()
QString url = version->url();
QUrl realUrl(url);
QString hostname = realUrl.host();
- auto &worker = NetWorker::qnam();
+ auto worker = MMC->qnam();
QNetworkRequest req(realUrl);
req.setRawHeader("Host", hostname.toLatin1());
req.setHeader(QNetworkRequest::UserAgentHeader, "Wget/1.14 (linux-gnu)");
- QNetworkReply * rep = worker.get ( req );
+ QNetworkReply * rep = worker->get ( req );
m_reply = QSharedPointer<QNetworkReply> (rep, &QObject::deleteLater);
connect(rep, SIGNAL(downloadProgress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64)));
- connect(&worker, SIGNAL(finished(QNetworkReply*)), SLOT(lwjglFinished(QNetworkReply*)));
+ connect(worker, SIGNAL(finished(QNetworkReply*)), SLOT(lwjglFinished(QNetworkReply*)));
//connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(downloadError(QNetworkReply::NetworkError)));
}
@@ -77,13 +77,13 @@ void LegacyUpdate::lwjglFinished(QNetworkReply* reply)
"\nSometimes you have to wait a bit if you download many LWJGL versions in a row. YMMV");
return;
}
- auto &worker = NetWorker::qnam();
+ auto *worker = MMC->qnam();
//Here i check if there is a cookie for me in the reply and extract it
QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie>>(reply->header(QNetworkRequest::SetCookieHeader));
if(cookies.count() != 0)
{
//you must tell which cookie goes with which url
- worker.cookieJar()->setCookiesFromUrl(cookies, QUrl("sourceforge.net"));
+ worker->cookieJar()->setCookiesFromUrl(cookies, QUrl("sourceforge.net"));
}
//here you can check for the 302 or whatever other header i need
@@ -96,7 +96,7 @@ void LegacyUpdate::lwjglFinished(QNetworkReply* reply)
QNetworkRequest req(redirectedTo);
req.setRawHeader("Host", hostname.toLatin1());
req.setHeader(QNetworkRequest::UserAgentHeader, "Wget/1.14 (linux-gnu)");
- QNetworkReply * rep = worker.get(req);
+ QNetworkReply * rep = worker->get(req);
connect(rep, SIGNAL(downloadProgress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64)));
m_reply = QSharedPointer<QNetworkReply> (rep, &QObject::deleteLater);
return;
@@ -227,7 +227,9 @@ void LegacyUpdate::jarStart()
QString intended_version_id = inst->intendedVersionId();
urlstr += intended_version_id + "/" + intended_version_id + ".jar";
- legacyDownloadJob.reset(new DownloadJob(QUrl(urlstr), inst->defaultBaseJar()));
+ auto dljob = new DownloadJob("Minecraft.jar for version " + intended_version_id);
+ dljob->add(QUrl(urlstr), inst->defaultBaseJar());
+ legacyDownloadJob.reset();
connect(legacyDownloadJob.data(), SIGNAL(finished()), SLOT(jarFinished()));
connect(legacyDownloadJob.data(), SIGNAL(failed()), SLOT(jarFailed()));
connect(legacyDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64)));
diff --git a/logic/OneSixAssets.cpp b/logic/OneSixAssets.cpp
index c65ee607..5bdd29d7 100644
--- a/logic/OneSixAssets.cpp
+++ b/logic/OneSixAssets.cpp
@@ -3,6 +3,8 @@
#include <QtXml/QtXml>
#include "OneSixAssets.h"
#include "net/DownloadJob.h"
+#include "net/HttpMetaCache.h"
+#include "MultiMC.h"
inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname)
{
@@ -65,7 +67,7 @@ void OneSixAssets::fetchXMLFinished()
nuke_whitelist.clear();
auto firstJob = index_job->first();
- QByteArray ba = firstJob->m_data;
+ QByteArray ba = firstJob.dynamicCast<ByteArrayDownload>()->m_data;
QString xmlErrorMsg;
QDomDocument doc;
@@ -76,10 +78,12 @@ void OneSixAssets::fetchXMLFinished()
//QRegExp etag_match(".*([a-f0-9]{32}).*");
QDomNodeList contents = doc.elementsByTagName ( "Contents" );
- DownloadJob *job = new DownloadJob();
+ DownloadJob *job = new DownloadJob("Assets");
connect ( job, SIGNAL(succeeded()), SLOT(downloadFinished()) );
connect ( job, SIGNAL(failed()), SIGNAL(failed()) );
+ auto metacache = MMC->metacache();
+
for ( int i = 0; i < contents.length(); i++ )
{
QDomElement element = contents.at ( i ).toElement();
@@ -104,22 +108,12 @@ void OneSixAssets::fetchXMLFinished()
if ( sizeStr == "0" )
continue;
- QString filename = fprefix + keyStr;
- QFile check_file ( filename );
- QString client_etag = "nonsense";
- // if there already is a file and md5 checking is in effect and it can be opened
- if ( check_file.exists() && check_file.open ( QIODevice::ReadOnly ) )
- {
- // check the md5 against the expected one
- client_etag = QCryptographicHash::hash ( check_file.readAll(), QCryptographicHash::Md5 ).toHex().constData();
- check_file.close();
- }
-
- QString trimmedEtag = etagStr.remove ( '"' );
nuke_whitelist.append ( keyStr );
- if(trimmedEtag != client_etag)
+
+ auto entry = metacache->resolveEntry("assets", keyStr, etagStr);
+ if(entry->stale)
{
- job->add ( QUrl ( prefix + keyStr ), filename );
+ job->add(QUrl(prefix + keyStr), entry);
}
}
if(job->size())
@@ -135,7 +129,8 @@ void OneSixAssets::fetchXMLFinished()
}
void OneSixAssets::start()
{
- DownloadJob * job = new DownloadJob(QUrl ( "http://s3.amazonaws.com/Minecraft.Resources/" ));
+ auto job = new DownloadJob("Assets index");
+ job->add(QUrl ( "http://s3.amazonaws.com/Minecraft.Resources/" ));
connect ( job, SIGNAL(succeeded()), SLOT ( fetchXMLFinished() ) );
index_job.reset ( job );
job->start();
diff --git a/logic/OneSixUpdate.cpp b/logic/OneSixUpdate.cpp
index 428d6ef7..ce71bde0 100644
--- a/logic/OneSixUpdate.cpp
+++ b/logic/OneSixUpdate.cpp
@@ -12,7 +12,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+#include "MultiMC.h"
#include "OneSixUpdate.h"
#include <QtNetwork>
@@ -72,7 +72,9 @@ void OneSixUpdate::versionFileStart()
QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/");
urlstr += targetVersion->descriptor + "/" + targetVersion->descriptor + ".json";
- specificVersionDownloadJob.reset(new DownloadJob(QUrl(urlstr)));
+ auto job = new DownloadJob("Version index");
+ job->add(QUrl(urlstr));
+ specificVersionDownloadJob.reset(job);
connect(specificVersionDownloadJob.data(), SIGNAL(succeeded()), SLOT(versionFileFinished()));
connect(specificVersionDownloadJob.data(), SIGNAL(failed()), SLOT(versionFileFailed()));
connect(specificVersionDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64)));
@@ -92,7 +94,7 @@ void OneSixUpdate::versionFileFinished()
// FIXME: detect errors here, download to a temp file, swap
QFile vfile1 (version1);
vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly );
- vfile1.write(DlJob->m_data);
+ vfile1.write(DlJob.dynamicCast<ByteArrayDownload>()->m_data);
vfile1.close();
}
@@ -134,16 +136,22 @@ void OneSixUpdate::jarlibStart()
QString targetstr ("versions/");
targetstr += version->id + "/" + version->id + ".jar";
- jarlibDownloadJob.reset(new DownloadJob(QUrl(urlstr), targetstr));
+ auto job = new DownloadJob("Libraries for instance " + inst->name());
+ job->add(QUrl(urlstr), targetstr);
+ jarlibDownloadJob.reset(job);
auto libs = version->getActiveNativeLibs();
libs.append(version->getActiveNormalLibs());
+ auto metacache = MMC->metacache();
for(auto lib: libs)
{
QString download_path = lib->downloadPath();
- QString storage_path = "libraries/" + lib->storagePath();
- jarlibDownloadJob->add(download_path, storage_path);
+ auto entry = metacache->resolveEntry("libraries", lib->storagePath());
+ if(entry->stale)
+ {
+ jarlibDownloadJob->add(download_path, entry);
+ }
}
connect(jarlibDownloadJob.data(), SIGNAL(succeeded()), SLOT(jarlibFinished()));
connect(jarlibDownloadJob.data(), SIGNAL(failed()), SLOT(jarlibFailed()));
diff --git a/logic/IconListModel.cpp b/logic/lists/IconList.cpp
index 4a5795d6..6988d02f 100644
--- a/logic/IconListModel.cpp
+++ b/logic/lists/IconList.cpp
@@ -1,4 +1,4 @@
-#include "IconListModel.h"
+#include "IconList.h"
#include <pathutils.h>
#include <QMap>
#include <QEventLoop>
@@ -6,8 +6,6 @@
#include <QMimeData>
#include <QUrl>
#define MAX_SIZE 1024
-IconList* IconList::m_Instance = 0;
-QMutex IconList::mutex;
struct entry
{
@@ -256,25 +254,4 @@ int IconList::getIconIndex ( QString key )
return -1;
}
-
-void IconList::drop()
-{
- mutex.lock();
- delete m_Instance;
- m_Instance = 0;
- mutex.unlock();
-}
-
-IconList* IconList::instance()
-{
- if ( !m_Instance )
- {
- mutex.lock();
- if ( !m_Instance )
- m_Instance = new IconList;
- mutex.unlock();
- }
- return m_Instance;
-}
-
-#include "IconListModel.moc" \ No newline at end of file
+#include "IconList.moc" \ No newline at end of file
diff --git a/logic/IconListModel.h b/logic/lists/IconList.h
index 907dfd81..cad80cdf 100644
--- a/logic/IconListModel.h
+++ b/logic/lists/IconList.h
@@ -9,8 +9,9 @@ class Private;
class IconList : public QAbstractListModel
{
public:
- static IconList* instance();
- static void drop();
+ IconList();
+ virtual ~IconList();
+
QIcon getIcon ( QString key );
int getIconIndex ( QString key );
@@ -28,14 +29,10 @@ public:
void installIcons ( QStringList iconFiles );
private:
- virtual ~IconList();
- IconList();
// hide copy constructor
IconList ( const IconList & ) = delete;
// hide assign op
IconList& operator= ( const IconList & ) = delete;
void reindex();
- static IconList* m_Instance;
- static QMutex mutex;
Private* d;
};
diff --git a/logic/lists/InstanceList.cpp b/logic/lists/InstanceList.cpp
index 1d13e3f2..b930f781 100644
--- a/logic/lists/InstanceList.cpp
+++ b/logic/lists/InstanceList.cpp
@@ -22,13 +22,13 @@
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
+#include <pathutils.h>
+#include "MultiMC.h"
#include "logic/lists/InstanceList.h"
+#include "logic/lists/IconList.h"
#include "logic/BaseInstance.h"
#include "logic/InstanceFactory.h"
-#include <logic/IconListModel.h>
-
-#include "pathutils.h"
const static int GROUP_FILE_FORMAT_VERSION = 1;
@@ -81,9 +81,8 @@ QVariant InstanceList::data ( const QModelIndex& index, int role ) const
}
case Qt::DecorationRole:
{
- IconList * ic = IconList::instance();
QString key = pdata->iconKey();
- return ic->getIcon(key);
+ return MMC->icons()->getIcon(key);
}
// for now.
case KCategorizedSortFilterProxyModel::CategorySortRole:
@@ -413,5 +412,3 @@ bool InstanceProxyModel::subSortLessThan (const QModelIndex& left, const QModelI
return QString::localeAwareCompare(pdataLeft->name(), pdataRight->name()) < 0;
//return pdataLeft->name() < pdataRight->name();
}
-
-#include "InstanceList.moc" \ No newline at end of file
diff --git a/logic/lists/LwjglVersionList.cpp b/logic/lists/LwjglVersionList.cpp
index c0854628..d7826a82 100644
--- a/logic/lists/LwjglVersionList.cpp
+++ b/logic/lists/LwjglVersionList.cpp
@@ -14,7 +14,7 @@
*/
#include "LwjglVersionList.h"
-#include "logic/net/NetWorker.h"
+#include "MultiMC.h"
#include <QtNetwork>
@@ -91,8 +91,8 @@ void LWJGLVersionList::loadList()
Q_ASSERT_X(!m_loading, "loadList", "list is already loading (m_loading is true)");
setLoading(true);
- auto & worker = NetWorker::qnam();
- reply = worker.get(QNetworkRequest(QUrl(RSS_URL)));
+ auto worker = MMC->qnam();
+ reply = worker->get(QNetworkRequest(QUrl(RSS_URL)));
connect(reply, SIGNAL(finished()), SLOT(netRequestComplete()));
}
diff --git a/logic/lists/MinecraftVersionList.cpp b/logic/lists/MinecraftVersionList.cpp
index 4444f5b0..42fb1b50 100644
--- a/logic/lists/MinecraftVersionList.cpp
+++ b/logic/lists/MinecraftVersionList.cpp
@@ -14,7 +14,7 @@
*/
#include "MinecraftVersionList.h"
-#include <logic/net/NetWorker.h>
+#include <MultiMC.h>
#include <QDebug>
@@ -151,8 +151,8 @@ MCVListLoadTask::~MCVListLoadTask()
void MCVListLoadTask::executeTask()
{
setStatus("Loading instance version list...");
- auto & worker = NetWorker::qnam();
- vlistReply = worker.get(QNetworkRequest(QUrl(QString(MCVLIST_URLBASE) + "versions.json")));
+ auto worker = MMC->qnam();
+ vlistReply = worker->get(QNetworkRequest(QUrl(QString(MCVLIST_URLBASE) + "versions.json")));
connect(vlistReply, SIGNAL(finished()), this, SLOT(list_downloaded()));
}
diff --git a/logic/net/ByteArrayDownload.cpp b/logic/net/ByteArrayDownload.cpp
new file mode 100644
index 00000000..6ae3f121
--- /dev/null
+++ b/logic/net/ByteArrayDownload.cpp
@@ -0,0 +1,62 @@
+#include "ByteArrayDownload.h"
+#include "MultiMC.h"
+#include <QDebug>
+
+ByteArrayDownload::ByteArrayDownload ( QUrl url )
+ : Download()
+{
+ m_url = url;
+ m_status = Job_NotStarted;
+}
+
+void ByteArrayDownload::start()
+{
+ qDebug() << "Downloading " << m_url.toString();
+ QNetworkRequest request ( m_url );
+ auto worker = MMC->qnam();
+ QNetworkReply * rep = worker->get ( request );
+
+ m_reply = QSharedPointer<QNetworkReply> ( rep, &QObject::deleteLater );
+ connect ( rep, SIGNAL ( downloadProgress ( qint64,qint64 ) ), SLOT ( downloadProgress ( qint64,qint64 ) ) );
+ connect ( rep, SIGNAL ( finished() ), SLOT ( downloadFinished() ) );
+ connect ( rep, SIGNAL ( error ( QNetworkReply::NetworkError ) ), SLOT ( downloadError ( QNetworkReply::NetworkError ) ) );
+ connect ( rep, SIGNAL ( readyRead() ), SLOT ( downloadReadyRead() ) );
+}
+
+void ByteArrayDownload::downloadProgress ( qint64 bytesReceived, qint64 bytesTotal )
+{
+ emit progress (index_within_job, bytesReceived, bytesTotal );
+}
+
+void ByteArrayDownload::downloadError ( QNetworkReply::NetworkError error )
+{
+ // error happened during download.
+ // TODO: log the reason why
+ m_status = Job_Failed;
+}
+
+void ByteArrayDownload::downloadFinished()
+{
+ // if the download succeeded
+ if ( m_status != Job_Failed )
+ {
+ // nothing went wrong...
+ m_status = Job_Finished;
+ m_data = m_reply->readAll();
+ m_reply.clear();
+ emit succeeded(index_within_job);
+ return;
+ }
+ // else the download failed
+ else
+ {
+ m_reply.clear();
+ emit failed(index_within_job);
+ return;
+ }
+}
+
+void ByteArrayDownload::downloadReadyRead()
+{
+ // ~_~
+}
diff --git a/logic/net/ByteArrayDownload.h b/logic/net/ByteArrayDownload.h
new file mode 100644
index 00000000..428b21db
--- /dev/null
+++ b/logic/net/ByteArrayDownload.h
@@ -0,0 +1,24 @@
+#pragma once
+#include "Download.h"
+
+class ByteArrayDownload: public Download
+{
+ Q_OBJECT
+public:
+ ByteArrayDownload(QUrl url);
+
+public:
+ /// if not saving to file, downloaded data is placed here
+ QByteArray m_data;
+
+public slots:
+ virtual void start();
+
+protected slots:
+ void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
+ void downloadError(QNetworkReply::NetworkError error);
+ void downloadFinished();
+ void downloadReadyRead();
+};
+
+typedef QSharedPointer<ByteArrayDownload> ByteArrayDownloadPtr;
diff --git a/logic/net/CacheDownload.cpp b/logic/net/CacheDownload.cpp
new file mode 100644
index 00000000..c0074574
--- /dev/null
+++ b/logic/net/CacheDownload.cpp
@@ -0,0 +1,122 @@
+#include "MultiMC.h"
+#include "CacheDownload.h"
+#include <pathutils.h>
+
+#include <QCryptographicHash>
+#include <QFileInfo>
+#include <QDateTime>
+#include <QDebug>
+
+CacheDownload::CacheDownload (QUrl url, MetaEntryPtr entry )
+ :Download(), md5sum(QCryptographicHash::Md5)
+{
+ m_url = url;
+ m_entry = entry;
+ m_target_path = entry->getFullPath();
+ m_status = Job_NotStarted;
+ m_opened_for_saving = false;
+}
+
+void CacheDownload::start()
+{
+ if(!m_entry->stale)
+ {
+ emit succeeded(index_within_job);
+ return;
+ }
+ m_output_file.setFileName(m_target_path);
+ // if there already is a file and md5 checking is in effect and it can be opened
+ if(!ensureFilePathExists(m_target_path))
+ {
+ emit failed(index_within_job);
+ return;
+ }
+ qDebug() << "Downloading " << m_url.toString();
+ QNetworkRequest request ( m_url );
+ request.setRawHeader(QString("If-None-Match").toLatin1(), m_entry->etag.toLatin1());
+
+ auto worker = MMC->qnam();
+ QNetworkReply * rep = worker->get ( request );
+
+ m_reply = QSharedPointer<QNetworkReply> ( rep, &QObject::deleteLater );
+ connect ( rep, SIGNAL ( downloadProgress ( qint64,qint64 ) ), SLOT ( downloadProgress ( qint64,qint64 ) ) );
+ connect ( rep, SIGNAL ( finished() ), SLOT ( downloadFinished() ) );
+ connect ( rep, SIGNAL ( error ( QNetworkReply::NetworkError ) ), SLOT ( downloadError ( QNetworkReply::NetworkError ) ) );
+ connect ( rep, SIGNAL ( readyRead() ), SLOT ( downloadReadyRead() ) );
+}
+
+void CacheDownload::downloadProgress ( qint64 bytesReceived, qint64 bytesTotal )
+{
+ emit progress (index_within_job, bytesReceived, bytesTotal );
+}
+
+void CacheDownload::downloadError ( QNetworkReply::NetworkError error )
+{
+ // error happened during download.
+ // TODO: log the reason why
+ m_status = Job_Failed;
+}
+void CacheDownload::downloadFinished()
+{
+ // if the download succeeded
+ if ( m_status != Job_Failed )
+ {
+
+ // nothing went wrong...
+ m_status = Job_Finished;
+ if(m_opened_for_saving)
+ {
+ // save the data to the downloadable if we aren't saving to file
+ m_output_file.close();
+ m_entry->md5sum = md5sum.result().toHex().constData();
+ }
+ else
+ {
+ if ( m_output_file.open ( QIODevice::ReadOnly ) )
+ {
+ m_entry->md5sum = QCryptographicHash::hash ( m_output_file.readAll(), QCryptographicHash::Md5 ).toHex().constData();
+ m_output_file.close();
+ }
+ }
+ QFileInfo output_file_info(m_target_path);
+
+
+ m_entry->etag = m_reply->rawHeader("ETag").constData();
+ m_entry->last_changed_timestamp = output_file_info.lastModified().toUTC().toMSecsSinceEpoch();
+ m_entry->stale = false;
+ MMC->metacache()->updateEntry(m_entry);
+
+ m_reply.clear();
+ emit succeeded(index_within_job);
+ return;
+ }
+ // else the download failed
+ else
+ {
+ m_output_file.close();
+ m_output_file.remove();
+ m_reply.clear();
+ emit failed(index_within_job);
+ return;
+ }
+}
+
+void CacheDownload::downloadReadyRead()
+{
+ if(!m_opened_for_saving)
+ {
+ if ( !m_output_file.open ( QIODevice::WriteOnly ) )
+ {
+ /*
+ * Can't open the file... the job failed
+ */
+ m_reply->abort();
+ emit failed(index_within_job);
+ return;
+ }
+ m_opened_for_saving = true;
+ }
+ QByteArray ba = m_reply->readAll();
+ md5sum.addData(ba);
+ m_output_file.write ( ba );
+}
diff --git a/logic/net/CacheDownload.h b/logic/net/CacheDownload.h
new file mode 100644
index 00000000..f95dabd5
--- /dev/null
+++ b/logic/net/CacheDownload.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "Download.h"
+#include "HttpMetaCache.h"
+#include <QFile>
+#include <qcryptographichash.h>
+
+class CacheDownload : public Download
+{
+ Q_OBJECT
+public:
+ MetaEntryPtr m_entry;
+ /// is the saving file already open?
+ bool m_opened_for_saving;
+ /// if saving to file, use the one specified in this string
+ QString m_target_path;
+ /// this is the output file, if any
+ QFile m_output_file;
+ /// the hash-as-you-download
+ QCryptographicHash md5sum;
+public:
+ explicit CacheDownload(QUrl url, MetaEntryPtr entry);
+
+protected slots:
+ virtual void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
+ virtual void downloadError(QNetworkReply::NetworkError error);
+ virtual void downloadFinished();
+ virtual void downloadReadyRead();
+
+public slots:
+ virtual void start();
+};
+
+typedef QSharedPointer<CacheDownload> CacheDownloadPtr;
diff --git a/logic/net/Download.h b/logic/net/Download.h
new file mode 100644
index 00000000..91f09dec
--- /dev/null
+++ b/logic/net/Download.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include <QObject>
+#include <QUrl>
+#include <QSharedPointer>
+#include <QNetworkReply>
+
+
+enum JobStatus
+{
+ Job_NotStarted,
+ Job_InProgress,
+ Job_Finished,
+ Job_Failed
+};
+
+class Download : public QObject
+{
+ Q_OBJECT
+protected:
+ explicit Download(): QObject(0){};
+public:
+ virtual ~Download() {};
+
+public:
+ /// the network reply
+ QSharedPointer<QNetworkReply> m_reply;
+
+ /// source URL
+ QUrl m_url;
+
+ /// The file's status
+ JobStatus m_status;
+
+ /// index within the parent job
+ int index_within_job = 0;
+
+signals:
+ void started(int index);
+ void progress(int index, qint64 current, qint64 total);
+ void succeeded(int index);
+ void failed(int index);
+
+protected slots:
+ virtual void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) = 0;
+ virtual void downloadError(QNetworkReply::NetworkError error) = 0;
+ virtual void downloadFinished() = 0;
+ virtual void downloadReadyRead() = 0;
+
+public slots:
+ virtual void start() = 0;
+};
+
+typedef QSharedPointer<Download> DownloadPtr;
diff --git a/logic/net/DownloadJob.cpp b/logic/net/DownloadJob.cpp
index 5c8ed4b9..cbc2c5fe 100644
--- a/logic/net/DownloadJob.cpp
+++ b/logic/net/DownloadJob.cpp
@@ -1,136 +1,29 @@
#include "DownloadJob.h"
#include "pathutils.h"
-#include "NetWorker.h"
+#include "MultiMC.h"
+#include "FileDownload.h"
+#include "ByteArrayDownload.h"
+#include "CacheDownload.h"
-Download::Download (QUrl url, QString target_path, QString expected_md5 )
- :Job()
+ByteArrayDownloadPtr DownloadJob::add ( QUrl url )
{
- m_url = url;
- m_target_path = target_path;
- m_expected_md5 = expected_md5;
-
- m_check_md5 = m_expected_md5.size();
- m_save_to_file = m_target_path.size();
- m_status = Job_NotStarted;
- m_opened_for_saving = false;
-}
-
-void Download::start()
-{
- if ( m_save_to_file )
- {
- QString filename = m_target_path;
- m_output_file.setFileName ( filename );
- // if there already is a file and md5 checking is in effect and it can be opened
- if ( m_output_file.exists() && m_output_file.open ( QIODevice::ReadOnly ) )
- {
- // check the md5 against the expected one
- QString hash = QCryptographicHash::hash ( m_output_file.readAll(), QCryptographicHash::Md5 ).toHex().constData();
- m_output_file.close();
- // skip this file if they match
- if ( m_check_md5 && hash == m_expected_md5 )
- {
- qDebug() << "Skipping " << m_url.toString() << ": md5 match.";
- emit succeeded(index_within_job);
- return;
- }
- else
- {
- m_expected_md5 = hash;
- }
- }
- if(!ensureFilePathExists(filename))
- {
- emit failed(index_within_job);
- return;
- }
- }
- qDebug() << "Downloading " << m_url.toString();
- QNetworkRequest request ( m_url );
- request.setRawHeader(QString("If-None-Match").toLatin1(), m_expected_md5.toLatin1());
-
- auto &worker = NetWorker::qnam();
- QNetworkReply * rep = worker.get ( request );
-
- m_reply = QSharedPointer<QNetworkReply> ( rep, &QObject::deleteLater );
- connect ( rep, SIGNAL ( downloadProgress ( qint64,qint64 ) ), SLOT ( downloadProgress ( qint64,qint64 ) ) );
- connect ( rep, SIGNAL ( finished() ), SLOT ( downloadFinished() ) );
- connect ( rep, SIGNAL ( error ( QNetworkReply::NetworkError ) ), SLOT ( downloadError ( QNetworkReply::NetworkError ) ) );
- connect ( rep, SIGNAL ( readyRead() ), SLOT ( downloadReadyRead() ) );
-}
-
-void Download::downloadProgress ( qint64 bytesReceived, qint64 bytesTotal )
-{
- emit progress (index_within_job, bytesReceived, bytesTotal );
-}
-
-void Download::downloadError ( QNetworkReply::NetworkError error )
-{
- // error happened during download.
- // TODO: log the reason why
- m_status = Job_Failed;
-}
-
-void Download::downloadFinished()
-{
- // if the download succeeded
- if ( m_status != Job_Failed )
- {
- // nothing went wrong...
- m_status = Job_Finished;
- // save the data to the downloadable if we aren't saving to file
- if ( !m_save_to_file )
- {
- m_data = m_reply->readAll();
- }
- else
- {
- m_output_file.close();
- }
-
- //TODO: check md5 here!
- m_reply.clear();
- emit succeeded(index_within_job);
- return;
- }
- // else the download failed
- else
- {
- if ( m_save_to_file )
- {
- m_output_file.close();
- m_output_file.remove();
- }
- m_reply.clear();
- emit failed(index_within_job);
- return;
- }
+ ByteArrayDownloadPtr ptr (new ByteArrayDownload(url));
+ ptr->index_within_job = downloads.size();
+ downloads.append(ptr);
+ return ptr;
}
-void Download::downloadReadyRead()
+FileDownloadPtr DownloadJob::add ( QUrl url, QString rel_target_path)
{
- if( m_save_to_file )
- {
- if(!m_opened_for_saving)
- {
- if ( !m_output_file.open ( QIODevice::WriteOnly ) )
- {
- /*
- * Can't open the file... the job failed
- */
- m_reply->abort();
- emit failed(index_within_job);
- return;
- }
- m_opened_for_saving = true;
- }
- m_output_file.write ( m_reply->readAll() );
- }
+ FileDownloadPtr ptr (new FileDownload(url, rel_target_path));
+ ptr->index_within_job = downloads.size();
+ downloads.append(ptr);
+ return ptr;
}
-DownloadPtr DownloadJob::add ( QUrl url, QString rel_target_path, QString expected_md5 )
+CacheDownloadPtr DownloadJob::add ( QUrl url, MetaEntryPtr entry)
{
- DownloadPtr ptr (new Download(url, rel_target_path, expected_md5));
+ CacheDownloadPtr ptr (new CacheDownload(url, entry));
ptr->index_within_job = downloads.size();
downloads.append(ptr);
return ptr;
@@ -139,14 +32,17 @@ DownloadPtr DownloadJob::add ( QUrl url, QString rel_target_path, QString expect
void DownloadJob::partSucceeded ( int index )
{
num_succeeded++;
+ qDebug() << m_job_name.toLocal8Bit() << " progress: " << num_succeeded << "/" << downloads.size();
if(num_failed + num_succeeded == downloads.size())
{
if(num_failed)
{
+ qDebug() << m_job_name.toLocal8Bit() << " failed.";
emit failed();
}
else
{
+ qDebug() << m_job_name.toLocal8Bit() << " succeeded.";
emit succeeded();
}
}
@@ -157,14 +53,8 @@ void DownloadJob::partFailed ( int index )
num_failed++;
if(num_failed + num_succeeded == downloads.size())
{
- if(num_failed)
- {
- emit failed();
- }
- else
- {
- emit succeeded();
- }
+ qDebug() << m_job_name.toLocal8Bit() << " failed.";
+ emit failed();
}
}
@@ -176,6 +66,7 @@ void DownloadJob::partProgress ( int index, qint64 bytesReceived, qint64 bytesTo
void DownloadJob::start()
{
+ qDebug() << m_job_name.toLocal8Bit() << " started.";
for(auto iter: downloads)
{
connect(iter.data(), SIGNAL(succeeded(int)), SLOT(partSucceeded(int)));
diff --git a/logic/net/DownloadJob.h b/logic/net/DownloadJob.h
index adeef646..71466282 100644
--- a/logic/net/DownloadJob.h
+++ b/logic/net/DownloadJob.h
@@ -1,98 +1,28 @@
#pragma once
#include <QtNetwork>
+#include "Download.h"
+#include "ByteArrayDownload.h"
+#include "FileDownload.h"
+#include "CacheDownload.h"
+#include "HttpMetaCache.h"
class DownloadJob;
-class Download;
typedef QSharedPointer<DownloadJob> DownloadJobPtr;
-typedef QSharedPointer<Download> DownloadPtr;
-
-enum JobStatus
-{
- Job_NotStarted,
- Job_InProgress,
- Job_Finished,
- Job_Failed
-};
-
-class Job : public QObject
-{
- Q_OBJECT
-protected:
- explicit Job(): QObject(0){};
-public:
- virtual ~Job() {};
-
-public slots:
- virtual void start() = 0;
-};
-
-class Download: public Job
-{
- friend class DownloadJob;
- Q_OBJECT
-protected:
- Download(QUrl url, QString rel_target_path = QString(), QString expected_md5 = QString());
-public:
- /// the network reply
- QSharedPointer<QNetworkReply> m_reply;
- /// source URL
- QUrl m_url;
-
- /// if true, check the md5sum against a provided md5sum
- /// also, if a file exists, perform an md5sum first and don't download only if they don't match
- bool m_check_md5;
- /// the expected md5 checksum
- QString m_expected_md5;
-
- /// save to file?
- bool m_save_to_file;
- /// is the saving file already open?
- bool m_opened_for_saving;
- /// if saving to file, use the one specified in this string
- QString m_target_path;
- /// this is the output file, if any
- QFile m_output_file;
- /// if not saving to file, downloaded data is placed here
- QByteArray m_data;
-
- int currentProgress = 0;
- int totalProgress = 0;
-
- /// The file's status
- JobStatus m_status;
-
- int index_within_job = 0;
-signals:
- void started(int index);
- void progress(int index, qint64 current, qint64 total);
- void succeeded(int index);
- void failed(int index);
-public slots:
- virtual void start();
-
-private slots:
- void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);;
- void downloadError(QNetworkReply::NetworkError error);
- void downloadFinished();
- void downloadReadyRead();
-};
/**
* A single file for the downloader/cache to process.
*/
-class DownloadJob : public Job
+class DownloadJob : public QObject
{
Q_OBJECT
public:
- explicit DownloadJob()
- :Job(){};
- explicit DownloadJob(QUrl url, QString rel_target_path = QString(), QString expected_md5 = QString())
- :Job()
- {
- add(url, rel_target_path, expected_md5);
- };
+ explicit DownloadJob(QString job_name)
+ :QObject(), m_job_name(job_name){};
+
+ ByteArrayDownloadPtr add(QUrl url);
+ FileDownloadPtr add(QUrl url, QString rel_target_path);
+ CacheDownloadPtr add(QUrl url, MetaEntryPtr entry);
- DownloadPtr add(QUrl url, QString rel_target_path = QString(), QString expected_md5 = QString());
DownloadPtr operator[](int index)
{
return downloads[index];
@@ -119,6 +49,7 @@ private slots:
void partSucceeded(int index);
void partFailed(int index);
private:
+ QString m_job_name;
QList<DownloadPtr> downloads;
int num_succeeded = 0;
int num_failed = 0;
diff --git a/logic/net/FileDownload.cpp b/logic/net/FileDownload.cpp
new file mode 100644
index 00000000..aad4a991
--- /dev/null
+++ b/logic/net/FileDownload.cpp
@@ -0,0 +1,111 @@
+#include "MultiMC.h"
+#include "FileDownload.h"
+#include <pathutils.h>
+#include <QCryptographicHash>
+#include <QDebug>
+
+
+FileDownload::FileDownload ( QUrl url, QString target_path )
+ :Download()
+{
+ m_url = url;
+ m_target_path = target_path;
+ m_check_md5 = false;
+ m_status = Job_NotStarted;
+ m_opened_for_saving = false;
+}
+
+void FileDownload::start()
+{
+ QString filename = m_target_path;
+ m_output_file.setFileName ( filename );
+ // if there already is a file and md5 checking is in effect and it can be opened
+ if ( m_output_file.exists() && m_output_file.open ( QIODevice::ReadOnly ) )
+ {
+ // check the md5 against the expected one
+ QString hash = QCryptographicHash::hash ( m_output_file.readAll(), QCryptographicHash::Md5 ).toHex().constData();
+ m_output_file.close();
+ // skip this file if they match
+ if ( m_check_md5 && hash == m_expected_md5 )
+ {
+ qDebug() << "Skipping " << m_url.toString() << ": md5 match.";
+ emit succeeded(index_within_job);
+ return;
+ }
+ else
+ {
+ m_expected_md5 = hash;
+ }
+ }
+ if(!ensureFilePathExists(filename))
+ {
+ emit failed(index_within_job);
+ return;
+ }
+
+ qDebug() << "Downloading " << m_url.toString();
+ QNetworkRequest request ( m_url );
+ request.setRawHeader(QString("If-None-Match").toLatin1(), m_expected_md5.toLatin1());
+
+ auto worker = MMC->qnam();
+ QNetworkReply * rep = worker->get ( request );
+
+ m_reply = QSharedPointer<QNetworkReply> ( rep, &QObject::deleteLater );
+ connect ( rep, SIGNAL ( downloadProgress ( qint64,qint64 ) ), SLOT ( downloadProgress ( qint64,qint64 ) ) );
+ connect ( rep, SIGNAL ( finished() ), SLOT ( downloadFinished() ) );
+ connect ( rep, SIGNAL ( error ( QNetworkReply::NetworkError ) ), SLOT ( downloadError ( QNetworkReply::NetworkError ) ) );
+ connect ( rep, SIGNAL ( readyRead() ), SLOT ( downloadReadyRead() ) );
+}
+
+void FileDownload::downloadProgress ( qint64 bytesReceived, qint64 bytesTotal )
+{
+ emit progress (index_within_job, bytesReceived, bytesTotal );
+}
+
+void FileDownload::downloadError ( QNetworkReply::NetworkError error )
+{
+ // error happened during download.
+ // TODO: log the reason why
+ m_status = Job_Failed;
+}
+
+void FileDownload::downloadFinished()
+{
+ // if the download succeeded
+ if ( m_status != Job_Failed )
+ {
+ // nothing went wrong...
+ m_status = Job_Finished;
+ m_output_file.close();
+
+ m_reply.clear();
+ emit succeeded(index_within_job);
+ return;
+ }
+ // else the download failed
+ else
+ {
+ m_output_file.close();
+ m_reply.clear();
+ emit failed(index_within_job);
+ return;
+ }
+}
+
+void FileDownload::downloadReadyRead()
+{
+ if(!m_opened_for_saving)
+ {
+ if ( !m_output_file.open ( QIODevice::WriteOnly ) )
+ {
+ /*
+ * Can't open the file... the job failed
+ */
+ m_reply->abort();
+ emit failed(index_within_job);
+ return;
+ }
+ m_opened_for_saving = true;
+ }
+ m_output_file.write ( m_reply->readAll() );
+}
diff --git a/logic/net/FileDownload.h b/logic/net/FileDownload.h
new file mode 100644
index 00000000..190bee58
--- /dev/null
+++ b/logic/net/FileDownload.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "Download.h"
+#include <QFile>
+
+class FileDownload : public Download
+{
+ Q_OBJECT
+public:
+ /// if true, check the md5sum against a provided md5sum
+ /// also, if a file exists, perform an md5sum first and don't download only if they don't match
+ bool m_check_md5;
+ /// the expected md5 checksum
+ QString m_expected_md5;
+ /// is the saving file already open?
+ bool m_opened_for_saving;
+ /// if saving to file, use the one specified in this string
+ QString m_target_path;
+ /// this is the output file, if any
+ QFile m_output_file;
+
+public:
+ explicit FileDownload(QUrl url, QString target_path);
+
+protected slots:
+ virtual void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
+ virtual void downloadError(QNetworkReply::NetworkError error);
+ virtual void downloadFinished();
+ virtual void downloadReadyRead();
+
+public slots:
+ virtual void start();
+};
+
+typedef QSharedPointer<FileDownload> FileDownloadPtr;
diff --git a/logic/net/HttpMetaCache.cpp b/logic/net/HttpMetaCache.cpp
new file mode 100644
index 00000000..46801ab3
--- /dev/null
+++ b/logic/net/HttpMetaCache.cpp
@@ -0,0 +1,231 @@
+#include "MultiMC.h"
+#include "HttpMetaCache.h"
+#include <pathutils.h>
+
+#include <QFileInfo>
+#include <QFile>
+#include <QTemporaryFile>
+#include <QSaveFile>
+#include <QDateTime>
+#include <QCryptographicHash>
+
+#include <QDebug>
+
+#include <QJsonDocument>
+#include <QJsonArray>
+#include <QJsonObject>
+
+QString MetaEntry::getFullPath()
+{
+ return PathCombine(MMC->metacache()->getBasePath(base), path);
+}
+
+
+HttpMetaCache::HttpMetaCache(QString path)
+ :QObject()
+{
+ m_index_file = path;
+ saveBatchingTimer.setSingleShot(true);
+ saveBatchingTimer.setTimerType(Qt::VeryCoarseTimer);
+ connect(&saveBatchingTimer,SIGNAL(timeout()),SLOT(SaveNow()));
+}
+
+HttpMetaCache::~HttpMetaCache()
+{
+ saveBatchingTimer.stop();
+ SaveNow();
+}
+
+MetaEntryPtr HttpMetaCache::getEntry ( QString base, QString resource_path )
+{
+ // no base. no base path. can't store
+ if(!m_entries.contains(base))
+ {
+ // TODO: log problem
+ return MetaEntryPtr();
+ }
+ EntryMap & map = m_entries[base];
+ if(map.entry_list.contains(resource_path))
+ {
+ return map.entry_list[resource_path];
+ }
+ return MetaEntryPtr();
+}
+
+MetaEntryPtr HttpMetaCache::resolveEntry ( QString base, QString resource_path, QString expected_etag )
+{
+ auto entry = getEntry(base, resource_path);
+ // it's not present? generate a default stale entry
+ if(!entry)
+ {
+ return staleEntry(base, resource_path);
+ }
+
+ auto & selected_base = m_entries[base];
+ QString real_path = PathCombine(selected_base.base_path, resource_path);
+ QFileInfo finfo(real_path);
+
+ // is the file really there? if not -> stale
+ if(!finfo.isFile() || !finfo.isReadable())
+ {
+ // if the file doesn't exist, we disown the entry
+ selected_base.entry_list.remove(resource_path);
+ return staleEntry(base, resource_path);
+ }
+
+ if(!expected_etag.isEmpty() && expected_etag != entry->etag)
+ {
+ // if the etag doesn't match expected, we disown the entry
+ selected_base.entry_list.remove(resource_path);
+ return staleEntry(base, resource_path);
+ }
+
+ // if the file changed, check md5sum
+ qint64 file_last_changed = finfo.lastModified().toUTC().toMSecsSinceEpoch();
+ if(file_last_changed != entry->last_changed_timestamp)
+ {
+ QFile input(real_path);
+ input.open(QIODevice::ReadOnly);
+ QString md5sum = QCryptographicHash::hash(input.readAll(), QCryptographicHash::Md5).toHex().constData();
+ if(entry->md5sum != md5sum)
+ {
+ selected_base.entry_list.remove(resource_path);
+ return staleEntry(base, resource_path);
+ }
+ // md5sums matched... keep entry and save the new state to file
+ entry->last_changed_timestamp = file_last_changed;
+ SaveEventually();
+ }
+
+ // entry passed all the checks we cared about.
+ return entry;
+}
+
+bool HttpMetaCache::updateEntry ( MetaEntryPtr stale_entry )
+{
+ if(!m_entries.contains(stale_entry->base))
+ {
+ qDebug() << "Cannot add entry with unknown base: " << stale_entry->base.toLocal8Bit();
+ return false;
+ }
+ if(stale_entry->stale)
+ {
+ qDebug() << "Cannot add stale entry: " << stale_entry->getFullPath().toLocal8Bit();
+ return false;
+ }
+ m_entries[stale_entry->base].entry_list[stale_entry->path] = stale_entry;
+ SaveEventually();
+ return true;
+}
+
+MetaEntryPtr HttpMetaCache::staleEntry(QString base, QString resource_path)
+{
+ auto foo = new MetaEntry;
+ foo->base = base;
+ foo->path = resource_path;
+ foo->stale = true;
+ return MetaEntryPtr(foo);
+}
+
+void HttpMetaCache::addBase ( QString base, QString base_root )
+{
+ // TODO: report error
+ if(m_entries.contains(base))
+ return;
+ // TODO: check if the base path is valid
+ EntryMap foo;
+ foo.base_path = base_root;
+ m_entries[base] = foo;
+}
+
+QString HttpMetaCache::getBasePath ( QString base )
+{
+ if(m_entries.contains(base))
+ {
+ return m_entries[base].base_path;
+ }
+ return QString();
+}
+
+
+void HttpMetaCache::Load()
+{
+ QFile index(m_index_file);
+ if(!index.open(QIODevice::ReadOnly))
+ return;
+
+ QJsonDocument json = QJsonDocument::fromJson(index.readAll());
+ if(!json.isObject())
+ return;
+ auto root = json.object();
+ // check file version first
+ auto version_val =root.value("version");
+ if(!version_val.isString())
+ return;
+ if(version_val.toString() != "1")
+ return;
+
+ // read the entry array
+ auto entries_val =root.value("entries");
+ if(!entries_val.isArray())
+ return;
+ QJsonArray array = entries_val.toArray();
+ for(auto element: array)
+ {
+ if(!element.isObject())
+ return;
+ auto element_obj = element.toObject();
+ QString base = element_obj.value("base").toString();
+ if(!m_entries.contains(base))
+ continue;
+ auto & entrymap = m_entries[base];
+ auto foo = new MetaEntry;
+ foo->base = base;
+ QString path = foo->path = element_obj.value("path").toString();
+ foo->md5sum = element_obj.value("md5sum").toString();
+ foo->etag = element_obj.value("etag").toString();
+ foo->last_changed_timestamp = element_obj.value("last_changed_timestamp").toDouble();
+ // presumed innocent until closer examination
+ foo->stale = false;
+ entrymap.entry_list[path] = MetaEntryPtr( foo );
+ }
+}
+
+void HttpMetaCache::SaveEventually()
+{
+ // reset the save timer
+ saveBatchingTimer.stop();
+ saveBatchingTimer.start(30000);
+}
+
+void HttpMetaCache::SaveNow()
+{
+ QSaveFile tfile(m_index_file);
+ if(!tfile.open(QIODevice::WriteOnly | QIODevice::Truncate))
+ return;
+ QJsonObject toplevel;
+ toplevel.insert("version",QJsonValue(QString("1")));
+ QJsonArray entriesArr;
+ for(auto group : m_entries)
+ {
+ for(auto entry : group.entry_list)
+ {
+ QJsonObject entryObj;
+ entryObj.insert("base", QJsonValue(entry->base));
+ entryObj.insert("path", QJsonValue(entry->path));
+ entryObj.insert("md5sum", QJsonValue(entry->md5sum));
+ entryObj.insert("etag", QJsonValue(entry->etag));
+ entryObj.insert("last_changed_timestamp", QJsonValue(double(entry->last_changed_timestamp)));
+ entriesArr.append(entryObj);
+ }
+ }
+ toplevel.insert("entries",entriesArr);
+ QJsonDocument doc(toplevel);
+ QByteArray jsonData = doc.toJson();
+ qint64 result = tfile.write(jsonData);
+ if(result == -1)
+ return;
+ if(result != jsonData.size())
+ return;
+ tfile.commit();
+}
diff --git a/logic/net/HttpMetaCache.h b/logic/net/HttpMetaCache.h
new file mode 100644
index 00000000..fac6bec3
--- /dev/null
+++ b/logic/net/HttpMetaCache.h
@@ -0,0 +1,57 @@
+#pragma once
+#include <QString>
+#include <QSharedPointer>
+#include <QMap>
+#include <qtimer.h>
+
+struct MetaEntry
+{
+ QString base;
+ QString path;
+ QString md5sum;
+ QString etag;
+ qint64 last_changed_timestamp = 0;
+ bool stale = true;
+ QString getFullPath();
+};
+
+typedef QSharedPointer<MetaEntry> MetaEntryPtr;
+
+class HttpMetaCache : public QObject
+{
+ Q_OBJECT
+public:
+ // supply path to the cache index file
+ HttpMetaCache(QString path);
+ ~HttpMetaCache();
+
+ // get the entry solely from the cache
+ // you probably don't want this, unless you have some specific caching needs.
+ MetaEntryPtr getEntry(QString base, QString resource_path);
+
+ // get the entry from cache and verify that it isn't stale (within reason)
+ MetaEntryPtr resolveEntry(QString base, QString resource_path, QString expected_etag = QString());
+
+ // add a previously resolved stale entry
+ bool updateEntry(MetaEntryPtr stale_entry);
+
+ void addBase(QString base, QString base_root);
+
+ // (re)start a timer that calls SaveNow later.
+ void SaveEventually();
+ void Load();
+ QString getBasePath ( QString base );
+public slots:
+ void SaveNow();
+private:
+ // create a new stale entry, given the parameters
+ MetaEntryPtr staleEntry(QString base, QString resource_path);
+ struct EntryMap
+ {
+ QString base_path;
+ QMap<QString, MetaEntryPtr> entry_list;
+ };
+ QMap<QString, EntryMap> m_entries;
+ QString m_index_file;
+ QTimer saveBatchingTimer;
+}; \ No newline at end of file
diff --git a/logic/net/NetWorker.cpp b/logic/net/NetWorker.cpp
deleted file mode 100644
index c5943348..00000000
--- a/logic/net/NetWorker.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#include "NetWorker.h"
-#include <QThreadStorage>
-
-class NetWorker::Private
-{
-public:
- QNetworkAccessManager manager;
-};
-
-NetWorker::NetWorker ( QObject* parent ) : QObject ( parent )
-{
- d = new Private();
-}
-
-QNetworkAccessManager& NetWorker::qnam()
-{
- auto & w = worker();
- return w.d->manager;
-}
-
-
-NetWorker& NetWorker::worker()
-{
- static QThreadStorage<NetWorker *> storage;
- if (!storage.hasLocalData())
- {
- storage.setLocalData(new NetWorker());
- }
- return *storage.localData();
-}
diff --git a/logic/net/NetWorker.h b/logic/net/NetWorker.h
deleted file mode 100644
index cf7e72e1..00000000
--- a/logic/net/NetWorker.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- _.ooo-._
- .OOOP _ '.
- dOOOO (_) \
- OOOOOb |
- OOOOOOb. |
- OOOOOOOOb |
- YOO(_)OOO /
- 'OOOOOY _.'
- '""""''
-*/
-#pragma once
-
-#include <QNetworkAccessManager>
-#include <QUrl>
-
-class NetWorker : public QObject
-{
- Q_OBJECT
-public:
- // for high level access to the sevices (preferred)
- static NetWorker &worker();
- // for low-level access to the network manager object
- static QNetworkAccessManager &qnam();
-public:
-
-private:
- explicit NetWorker ( QObject* parent = 0 );
- class Private;
- Private * d;
-}; \ No newline at end of file
diff --git a/logic/tasks/LoginTask.cpp b/logic/tasks/LoginTask.cpp
index 4e2f0fb7..ad9de7f5 100644
--- a/logic/tasks/LoginTask.cpp
+++ b/logic/tasks/LoginTask.cpp
@@ -14,7 +14,7 @@
*/
#include "LoginTask.h"
-#include "logic/net/NetWorker.h"
+#include "MultiMC.h"
#include <QStringList>
@@ -29,8 +29,8 @@ LoginTask::LoginTask( const UserInfo& uInfo, QObject* parent ) : Task(parent), u
void LoginTask::executeTask()
{
setStatus("Logging in...");
- auto & worker = NetWorker::qnam();
- connect(&worker, SIGNAL(finished(QNetworkReply*)), this, SLOT(processNetReply(QNetworkReply*)));
+ auto worker = MMC->qnam();
+ connect(worker, SIGNAL(finished(QNetworkReply*)), this, SLOT(processNetReply(QNetworkReply*)));
QUrl loginURL("https://login.minecraft.net/");
QNetworkRequest netRequest(loginURL);
@@ -41,7 +41,7 @@ void LoginTask::executeTask()
params.addQueryItem("password", uInfo.password);
params.addQueryItem("version", "13");
- netReply = worker.post(netRequest, params.query(QUrl::EncodeSpaces).toUtf8());
+ netReply = worker->post(netRequest, params.query(QUrl::EncodeSpaces).toUtf8());
}
void LoginTask::processNetReply(QNetworkReply *reply)
diff --git a/main.cpp b/main.cpp
deleted file mode 100644
index 12ef1ce7..00000000
--- a/main.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-/* Copyright 2013 MultiMC Contributors
- *
- * Authors: Andrew Okin
- * Orochimarufan <orochimarufan.x3@gmail.com>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <iostream>
-
-#include <QApplication>
-#include <QDir>
-
-#include "gui/mainwindow.h"
-#include "gui/logindialog.h"
-#include "gui/taskdialog.h"
-#include "gui/consolewindow.h"
-
-#include "AppSettings.h"
-#include "logic/lists/InstanceList.h"
-#include "logic/tasks/LoginTask.h"
-#include "logic/MinecraftProcess.h"
-
-#include "pathutils.h"
-#include "cmdutils.h"
-
-#include "config.h"
-
-using namespace Util::Commandline;
-
-// Commandline instance launcher
-class InstanceLauncher : public QObject
-{
- Q_OBJECT
-private:
- InstanceList instances;
- QString instId;
- InstancePtr instance;
- MinecraftProcess *proc;
- ConsoleWindow *console;
-public:
- InstanceLauncher(QString instId) : QObject(), instances(globalSettings->get("InstanceDir").toString())
- {
- this->instId = instId;
- }
-
-private slots:
- void onTerminated()
- {
- std::cout << "Minecraft exited" << std::endl;
- QApplication::instance()->quit();
- }
-
- void onLoginComplete()
- {
- LoginTask * task = (LoginTask *) QObject::sender();
- auto result = task->getResult();
- proc = instance->prepareForLaunch(result.username, result.sessionID);
- if(!proc)
- {
- //FIXME: report error
- return;
- }
- console = new ConsoleWindow(proc);
- console->show();
-
- connect(proc, SIGNAL(ended()), SLOT(onTerminated()));
- connect(proc, SIGNAL(log(QString,MessageLevel::Enum)), console, SLOT(write(QString,MessageLevel::Enum)));
-
- proc->launch();
- }
-
- void doLogin(const QString &errorMsg)
- {
- LoginDialog* loginDlg = new LoginDialog(nullptr, errorMsg);
- loginDlg->exec();
- if (loginDlg->result() == QDialog::Accepted)
- {
- UserInfo uInfo{loginDlg->getUsername(), loginDlg->getPassword()};
-
- TaskDialog* tDialog = new TaskDialog(nullptr);
- LoginTask* loginTask = new LoginTask(uInfo, tDialog);
- connect(loginTask, SIGNAL(succeeded()),SLOT(onLoginComplete()), Qt::QueuedConnection);
- connect(loginTask, SIGNAL(failed(QString)),SLOT(doLogin(QString)), Qt::QueuedConnection);
- tDialog->exec(loginTask);
- }
- //onLoginComplete(LoginResponse("Offline","Offline", 1));
- }
-
-public:
- int launch()
- {
- std::cout << "Loading Instances..." << std::endl;
- instances.loadList();
-
- std::cout << "Launching Instance '" << qPrintable(instId) << "'" << std::endl;
- instance = instances.getInstanceById(instId);
- if (instance.isNull())
- {
- std::cout << "Could not find instance requested. note that you have to specify the ID, not the NAME" << std::endl;
- return 1;
- }
-
- std::cout << "Logging in..." << std::endl;
- doLogin("");
-
- return QApplication::instance()->exec();
- }
-};
-
-int main(int argc, char *argv[])
-{
- // initialize Qt
- QApplication app(argc, argv);
- app.setOrganizationName("Forkk");
- app.setApplicationName("MultiMC 5");
-
- // Print app header
- std::cout << "MultiMC 5" << std::endl;
- std::cout << "(c) 2013 MultiMC Contributors" << std::endl << std::endl;
-
- // Commandline parsing
- Parser parser(FlagStyle::GNU, ArgumentStyle::SpaceAndEquals);
-
- // --help
- parser.addSwitch("help");
- parser.addShortOpt("help", 'h');
- parser.addDocumentation("help", "display this help and exit.");
- // --version
- parser.addSwitch("version");
- parser.addShortOpt("version", 'V');
- parser.addDocumentation("version", "display program version and exit.");
- // --dir
- parser.addOption("dir", app.applicationDirPath());
- parser.addShortOpt("dir", 'd');
- parser.addDocumentation("dir", "use the supplied directory as MultiMC root instead of the binary location (use '.' for current)");
- // --update
- parser.addOption("update");
- parser.addShortOpt("update", 'u');
- parser.addDocumentation("update", "replaces the given file with the running executable", "<path>");
- // --quietupdate
- parser.addSwitch("quietupdate");
- parser.addShortOpt("quietupdate", 'U');
- parser.addDocumentation("quietupdate", "doesn't restart MultiMC after installing updates");
- // --launch
- parser.addOption("launch");
- parser.addShortOpt("launch", 'l');
- parser.addDocumentation("launch", "tries to launch the given instance", "<inst>");
-
- // parse the arguments
- QHash<QString, QVariant> args;
- try
- {
- args = parser.parse(app.arguments());
- }
- catch(ParsingError e)
- {
- std::cerr << "CommandLineError: " << e.what() << std::endl;
- std::cerr << "Try '%1 -h' to get help on MultiMC's command line parameters." << std::endl;
- return 1;
- }
-
- // display help and exit
- if (args["help"].toBool())
- {
- std::cout << qPrintable(parser.compileHelp(app.arguments()[0]));
- return 0;
- }
-
- // display version and exit
- if (args["version"].toBool())
- {
- std::cout << "Version " << VERSION_STR << std::endl;
- std::cout << "Git " << GIT_COMMIT << std::endl;
- std::cout << "Tag: " << JENKINS_BUILD_TAG << " " << (ARCH==x64?"x86_64":"x86") << std::endl;
- return 0;
- }
-
- // update
- // Note: cwd is always the current executable path!
- if (!args["update"].isNull())
- {
- std::cout << "Performing MultiMC update: " << qPrintable(args["update"].toString()) << std::endl;
- QString cwd = QDir::currentPath();
- QDir::setCurrent(app.applicationDirPath());
- QFile file(app.applicationFilePath());
- file.copy(args["update"].toString());
- if(args["quietupdate"].toBool())
- return 0;
- QDir::setCurrent(cwd);
- }
-
- // change directory
- QDir::setCurrent(args["dir"].toString());
-
- // load settings
- globalSettings = new AppSettings(&app);
-
- // Register meta types.
- qRegisterMetaType<LoginResponse>("LoginResponse");
-
- // launch instance.
- if (!args["launch"].isNull())
- return InstanceLauncher(args["launch"].toString()).launch();
-
- // show main window
- MainWindow mainWin;
- mainWin.show();
-
- // loop
- return app.exec();
-}
-
-#include "main.moc"
diff --git a/multimc_pragma.h b/multimc_pragma.h
deleted file mode 100644
index 4650e4da..00000000
--- a/multimc_pragma.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#pragma once
-
-// This is here to keep MSVC from spamming the build output with nonsense
-// Call it public domain.
-
-#ifdef _MSC_VER
- // 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
- // C4251 can be ignored in Microsoft Visual C++ 2005 if you are deriving from a type
- // in the Standard C++ Library, compiling a debug release (/MTd) and where the compiler
- // error message refers to _Container_base.
- // Shows up when you export classes that use STL types. Stupid.
- // #pragma warning( disable: 4251 )
-
- // C4273 - inconsistent DLL linkage. how about none?
- #pragma warning( disable: 4273 )
-
- // don't display bogus 'deprecation' and 'unsafe' warnings.
- // See the idiocy: http://msdn.microsoft.com/en-us/magazine/cc163794.aspx
- #define _CRT_SECURE_NO_DEPRECATE
- #define _SCL_SECURE_NO_DEPRECATE
- // Let me demonstrate:
- /**
- * [peterix@peterix dfhack]$ man wcscpy_s
- * No manual entry for wcscpy_s
- *
- * Proprietary extensions.
- */
- //'function': was declared deprecated
- #pragma warning( disable: 4996 )
-
- // disable stupid - forcing value to bool 'true' or 'false' (performance warning).
- // When I do this, it's intentional. Always.
- #pragma warning( disable: 4800 )
-
- // disable more stupid - The compiler ignored an unrecognized pragma. GOOD JOB, DON'T SPAM ME WITH THAT
- #pragma warning( disable: 4068 )
-
- // no signed value outside enum range bs
- //#pragma warning( disable: 4341)
-
- // just shut up already - conversion between types loses precision
- //#pragma warning( disable: 4244)
-
- // signed/unsigned mismatch
- //#pragma warning( disable: 4018)
-
- // nonstandard extension used: enum 'df::whatever::etc' used in qualified name
- //#pragma warning( disable: 4482)
-#endif