2013-09-07 02:00:58 +00:00
|
|
|
#include "MultiMC.h"
|
2014-04-06 01:59:37 +00:00
|
|
|
#include "BuildConfig.h"
|
2015-07-05 00:29:41 +00:00
|
|
|
#include "pages/BasePageProvider.h"
|
|
|
|
#include "pages/global/MultiMCPage.h"
|
|
|
|
#include "pages/global/MinecraftPage.h"
|
|
|
|
#include "pages/global/JavaPage.h"
|
|
|
|
#include "pages/global/ProxyPage.h"
|
|
|
|
#include "pages/global/ExternalToolsPage.h"
|
|
|
|
#include "pages/global/AccountListPage.h"
|
2015-10-01 22:12:53 +00:00
|
|
|
#include "pages/global/PasteEEPage.h"
|
2014-04-05 20:58:47 +00:00
|
|
|
|
2016-10-21 07:07:26 +00:00
|
|
|
#include "themes/ITheme.h"
|
|
|
|
#include "themes/SystemTheme.h"
|
|
|
|
#include "themes/DarkTheme.h"
|
|
|
|
|
2013-09-07 02:00:58 +00:00
|
|
|
#include <iostream>
|
|
|
|
#include <QDir>
|
2013-12-06 18:59:58 +00:00
|
|
|
#include <QFileInfo>
|
2013-09-07 02:00:58 +00:00
|
|
|
#include <QNetworkAccessManager>
|
2013-09-08 21:43:19 +00:00
|
|
|
#include <QTranslator>
|
|
|
|
#include <QLibraryInfo>
|
2013-10-14 01:59:21 +00:00
|
|
|
#include <QMessageBox>
|
2013-12-06 18:59:58 +00:00
|
|
|
#include <QStringList>
|
2015-02-02 01:14:14 +00:00
|
|
|
#include <QDebug>
|
2016-10-21 23:43:36 +00:00
|
|
|
#include <QStyleFactory>
|
2013-09-07 02:00:58 +00:00
|
|
|
|
2015-02-09 00:51:14 +00:00
|
|
|
#include "InstanceList.h"
|
2016-10-02 22:55:54 +00:00
|
|
|
#include "FolderInstanceProvider.h"
|
|
|
|
#include "minecraft/ftb/FTBInstanceProvider.h"
|
|
|
|
|
2016-02-27 18:58:40 +00:00
|
|
|
#include <minecraft/auth/MojangAccountList.h>
|
2015-02-09 00:51:14 +00:00
|
|
|
#include "icons/IconList.h"
|
2016-02-27 18:58:40 +00:00
|
|
|
//FIXME: get rid of this
|
|
|
|
#include "minecraft/legacy/LwjglVersionList.h"
|
2015-02-09 00:51:14 +00:00
|
|
|
#include "minecraft/MinecraftVersionList.h"
|
2016-02-27 18:58:40 +00:00
|
|
|
#include "minecraft/liteloader/LiteLoaderVersionList.h"
|
|
|
|
#include "minecraft/forge/ForgeVersionList.h"
|
2013-09-15 22:54:39 +00:00
|
|
|
|
2015-02-09 00:51:14 +00:00
|
|
|
#include "net/HttpMetaCache.h"
|
|
|
|
#include "net/URLConstants.h"
|
|
|
|
#include "Env.h"
|
2013-09-07 02:00:58 +00:00
|
|
|
|
2015-02-09 00:51:14 +00:00
|
|
|
#include "java/JavaUtils.h"
|
2013-10-06 22:44:34 +00:00
|
|
|
|
2015-02-09 00:51:14 +00:00
|
|
|
#include "updater/UpdateChecker.h"
|
2013-10-06 22:44:34 +00:00
|
|
|
|
2015-02-09 00:51:14 +00:00
|
|
|
#include "tools/JProfiler.h"
|
|
|
|
#include "tools/JVisualVM.h"
|
|
|
|
#include "tools/MCEditTool.h"
|
2014-02-15 13:19:35 +00:00
|
|
|
|
2015-03-01 21:20:57 +00:00
|
|
|
#include <xdgicon.h>
|
2015-02-09 00:51:14 +00:00
|
|
|
#include "settings/INISettingsObject.h"
|
|
|
|
#include "settings/Setting.h"
|
2015-02-02 01:14:14 +00:00
|
|
|
|
2015-02-09 00:51:14 +00:00
|
|
|
#include "trans/TranslationDownloader.h"
|
2013-09-07 02:00:58 +00:00
|
|
|
|
2016-02-27 18:58:40 +00:00
|
|
|
#include "minecraft/ftb/FTBPlugin.h"
|
2014-03-05 21:20:45 +00:00
|
|
|
|
2015-10-04 23:47:27 +00:00
|
|
|
#include <Commandline.h>
|
|
|
|
#include <FileSystem.h>
|
2016-01-05 06:32:52 +00:00
|
|
|
#include <DesktopServices.h>
|
2015-10-04 23:47:27 +00:00
|
|
|
|
2016-06-08 23:58:50 +00:00
|
|
|
#if defined Q_OS_WIN32
|
|
|
|
#ifndef WIN32_LEAN_AND_MEAN
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
|
|
#endif
|
|
|
|
#include <windows.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#endif
|
|
|
|
|
2015-10-04 23:47:27 +00:00
|
|
|
using namespace Commandline;
|
2013-09-07 02:00:58 +00:00
|
|
|
|
2014-11-09 19:49:23 +00:00
|
|
|
MultiMC::MultiMC(int &argc, char **argv, bool test_mode) : QApplication(argc, argv)
|
2013-09-07 02:00:58 +00:00
|
|
|
{
|
2016-06-08 23:58:50 +00:00
|
|
|
#if defined Q_OS_WIN32
|
|
|
|
// attach the parent console
|
|
|
|
if(AttachConsole(ATTACH_PARENT_PROCESS))
|
|
|
|
{
|
|
|
|
// if attach succeeds, reopen and sync all the i/o
|
|
|
|
if(freopen("CON", "w", stdout))
|
|
|
|
{
|
|
|
|
std::cout.sync_with_stdio();
|
|
|
|
}
|
|
|
|
if(freopen("CON", "w", stderr))
|
|
|
|
{
|
|
|
|
std::cerr.sync_with_stdio();
|
|
|
|
}
|
|
|
|
if(freopen("CON", "r", stdin))
|
|
|
|
{
|
|
|
|
std::cin.sync_with_stdio();
|
|
|
|
}
|
|
|
|
auto out = GetStdHandle (STD_OUTPUT_HANDLE);
|
|
|
|
DWORD written;
|
|
|
|
const char * endline = "\n";
|
|
|
|
WriteConsole(out, endline, strlen(endline), &written, NULL);
|
|
|
|
consoleAttached = true;
|
|
|
|
}
|
|
|
|
#endif
|
2013-10-28 19:55:12 +00:00
|
|
|
setOrganizationName("MultiMC");
|
|
|
|
setApplicationName("MultiMC5");
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2015-02-02 01:14:14 +00:00
|
|
|
startTime = QDateTime::currentDateTime();
|
|
|
|
|
2014-01-01 14:42:43 +00:00
|
|
|
setAttribute(Qt::AA_UseHighDpiPixmaps);
|
2013-10-26 07:38:21 +00:00
|
|
|
// Don't quit on hiding the last window
|
|
|
|
this->setQuitOnLastWindowClosed(false);
|
|
|
|
|
2013-09-07 02:00:58 +00:00
|
|
|
// Commandline parsing
|
|
|
|
QHash<QString, QVariant> args;
|
|
|
|
{
|
|
|
|
Parser parser(FlagStyle::GNU, ArgumentStyle::SpaceAndEquals);
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2013-09-07 02:00:58 +00:00
|
|
|
// --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');
|
2013-09-22 22:23:50 +00:00
|
|
|
parser.addDocumentation("dir", "use the supplied directory as MultiMC root instead of "
|
|
|
|
"the binary location (use '.' for current)");
|
2015-09-29 22:11:00 +00:00
|
|
|
// --launch
|
|
|
|
parser.addOption("launch");
|
|
|
|
parser.addShortOpt("launch", 'l');
|
|
|
|
parser.addDocumentation("launch", "launch the specified instance (by instance ID)");
|
2014-05-22 05:49:45 +00:00
|
|
|
|
2013-09-07 02:00:58 +00:00
|
|
|
// parse the arguments
|
|
|
|
try
|
|
|
|
{
|
|
|
|
args = parser.parse(arguments());
|
|
|
|
}
|
2013-09-22 22:23:50 +00:00
|
|
|
catch (ParsingError e)
|
2013-09-07 02:00:58 +00:00
|
|
|
{
|
|
|
|
std::cerr << "CommandLineError: " << e.what() << std::endl;
|
2013-09-22 22:23:50 +00:00
|
|
|
std::cerr << "Try '%1 -h' to get help on MultiMC's command line parameters."
|
|
|
|
<< std::endl;
|
2013-09-07 02:00:58 +00:00
|
|
|
m_status = MultiMC::Failed;
|
|
|
|
return;
|
|
|
|
}
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2013-09-07 02:00:58 +00:00
|
|
|
// display help and exit
|
|
|
|
if (args["help"].toBool())
|
|
|
|
{
|
|
|
|
std::cout << qPrintable(parser.compileHelp(arguments()[0]));
|
|
|
|
m_status = MultiMC::Succeeded;
|
|
|
|
return;
|
|
|
|
}
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2013-09-07 02:00:58 +00:00
|
|
|
// display version and exit
|
|
|
|
if (args["version"].toBool())
|
|
|
|
{
|
2015-12-28 03:45:49 +00:00
|
|
|
std::cout << "Version " << BuildConfig.printableVersionString().toStdString() << std::endl;
|
2014-04-05 20:58:47 +00:00
|
|
|
std::cout << "Git " << BuildConfig.GIT_COMMIT.toStdString() << std::endl;
|
2013-09-07 02:00:58 +00:00
|
|
|
m_status = MultiMC::Succeeded;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2015-01-31 15:59:03 +00:00
|
|
|
|
|
|
|
QString origcwdPath = QDir::currentPath();
|
|
|
|
QString binPath = applicationDirPath();
|
2014-01-03 01:29:05 +00:00
|
|
|
QString adjustedBy;
|
2015-12-27 02:34:03 +00:00
|
|
|
QString dataPath;
|
2013-09-07 02:00:58 +00:00
|
|
|
// change directory
|
2014-01-03 01:29:05 +00:00
|
|
|
QString dirParam = args["dir"].toString();
|
2014-01-05 15:47:12 +00:00
|
|
|
if (!dirParam.isEmpty())
|
2014-01-03 01:29:05 +00:00
|
|
|
{
|
|
|
|
// the dir param. it makes multimc data path point to whatever the user specified
|
|
|
|
// on command line
|
|
|
|
adjustedBy += "Command line " + dirParam;
|
|
|
|
dataPath = dirParam;
|
|
|
|
}
|
2014-01-04 23:06:55 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
dataPath = applicationDirPath();
|
|
|
|
adjustedBy += "Fallback to binary path " + dataPath;
|
|
|
|
}
|
2014-01-05 15:47:12 +00:00
|
|
|
|
2015-09-29 22:11:00 +00:00
|
|
|
launchId = args["launch"].toString();
|
|
|
|
|
2015-10-04 23:47:27 +00:00
|
|
|
if (!FS::ensureFolderPathExists(dataPath) || !QDir::setCurrent(dataPath))
|
2014-01-03 01:29:05 +00:00
|
|
|
{
|
|
|
|
// BAD STUFF. WHAT DO?
|
|
|
|
initLogger();
|
2015-02-02 01:14:14 +00:00
|
|
|
qCritical() << "Failed to set work path. Will exit. NOW.";
|
2014-01-03 01:29:05 +00:00
|
|
|
m_status = MultiMC::Failed;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-11-09 19:49:23 +00:00
|
|
|
// in test mode, root path is the same as the binary path.
|
|
|
|
if (test_mode)
|
2014-01-05 15:47:12 +00:00
|
|
|
{
|
|
|
|
rootPath = binPath;
|
|
|
|
}
|
|
|
|
else
|
2014-01-03 01:29:05 +00:00
|
|
|
{
|
2014-07-27 13:50:03 +00:00
|
|
|
#ifdef Q_OS_LINUX
|
2015-10-04 23:47:27 +00:00
|
|
|
QDir foo(FS::PathCombine(binPath, ".."));
|
2014-01-03 01:29:05 +00:00
|
|
|
rootPath = foo.absolutePath();
|
2014-07-27 13:50:03 +00:00
|
|
|
#elif defined(Q_OS_WIN32)
|
2014-01-04 23:06:55 +00:00
|
|
|
rootPath = binPath;
|
2014-07-27 13:50:03 +00:00
|
|
|
#elif defined(Q_OS_MAC)
|
2015-10-05 00:00:03 +00:00
|
|
|
QDir foo(FS::PathCombine(binPath, "../.."));
|
2014-01-03 01:29:05 +00:00
|
|
|
rootPath = foo.absolutePath();
|
2014-07-27 13:50:03 +00:00
|
|
|
#endif
|
2014-01-03 01:29:05 +00:00
|
|
|
}
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2013-10-05 23:13:40 +00:00
|
|
|
// init the logger
|
|
|
|
initLogger();
|
|
|
|
|
2015-02-02 01:14:14 +00:00
|
|
|
qDebug() << "MultiMC 5, (c) 2013-2015 MultiMC Contributors";
|
2015-12-28 03:45:49 +00:00
|
|
|
qDebug() << "Version : " << BuildConfig.printableVersionString();
|
2015-02-02 01:14:14 +00:00
|
|
|
qDebug() << "Git commit : " << BuildConfig.GIT_COMMIT;
|
2015-12-28 03:45:49 +00:00
|
|
|
qDebug() << "Git refspec : " << BuildConfig.GIT_REFSPEC;
|
2014-01-03 01:29:05 +00:00
|
|
|
if (adjustedBy.size())
|
|
|
|
{
|
2015-02-02 01:14:14 +00:00
|
|
|
qDebug() << "Work dir before adjustment : " << origcwdPath;
|
|
|
|
qDebug() << "Work dir after adjustment : " << QDir::currentPath();
|
|
|
|
qDebug() << "Adjusted by : " << adjustedBy;
|
2014-01-03 01:29:05 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-02-02 01:14:14 +00:00
|
|
|
qDebug() << "Work dir : " << QDir::currentPath();
|
2014-01-03 01:29:05 +00:00
|
|
|
}
|
2015-02-02 01:14:14 +00:00
|
|
|
qDebug() << "Binary path : " << binPath;
|
|
|
|
qDebug() << "Application root path : " << rootPath;
|
2016-08-09 20:29:17 +00:00
|
|
|
if(!launchId.isEmpty())
|
|
|
|
{
|
|
|
|
qDebug() << "ID of instance to launch : " << launchId;
|
|
|
|
}
|
2014-01-03 01:29:05 +00:00
|
|
|
|
2013-09-07 02:00:58 +00:00
|
|
|
// load settings
|
2014-11-09 19:49:23 +00:00
|
|
|
initGlobalSettings(test_mode);
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2014-01-04 15:13:28 +00:00
|
|
|
// load translations
|
|
|
|
initTranslations();
|
|
|
|
|
2013-12-01 23:55:24 +00:00
|
|
|
// initialize the updater
|
2015-12-28 03:45:49 +00:00
|
|
|
if(BuildConfig.UPDATER_ENABLED)
|
|
|
|
{
|
|
|
|
m_updateChecker.reset(new UpdateChecker(BuildConfig.CHANLIST_URL, BuildConfig.VERSION_CHANNEL, BuildConfig.VERSION_BUILD));
|
|
|
|
}
|
2014-01-12 18:28:42 +00:00
|
|
|
|
2014-09-30 00:05:44 +00:00
|
|
|
m_translationChecker.reset(new TranslationDownloader());
|
|
|
|
|
2015-02-01 10:44:47 +00:00
|
|
|
// load icons
|
|
|
|
initIcons();
|
|
|
|
|
2016-10-21 07:07:26 +00:00
|
|
|
// load themes
|
|
|
|
initThemes();
|
|
|
|
|
2013-09-07 02:00:58 +00:00
|
|
|
// and instances
|
2013-10-28 19:55:12 +00:00
|
|
|
auto InstDirSetting = m_settings->getSetting("InstanceDir");
|
2014-07-27 13:50:03 +00:00
|
|
|
// instance path: check for problems with '!' in instance path and warn the user in the log
|
|
|
|
// and rememer that we have to show him a dialog when the gui starts (if it does so)
|
2015-01-27 21:31:07 +00:00
|
|
|
QString instDir = m_settings->get("InstanceDir").toString();
|
2015-02-02 01:14:14 +00:00
|
|
|
qDebug() << "Instance path : " << instDir;
|
2015-10-04 23:47:27 +00:00
|
|
|
if (FS::checkProblemticPathJava(QDir(instDir)))
|
2014-07-27 13:50:03 +00:00
|
|
|
{
|
2015-02-02 01:14:14 +00:00
|
|
|
qWarning()
|
2014-07-27 13:50:03 +00:00
|
|
|
<< "Your instance path contains \'!\' and this is known to cause java problems";
|
|
|
|
}
|
2015-02-01 02:08:25 +00:00
|
|
|
m_instances.reset(new InstanceList(m_settings, InstDirSetting->get().toString(), this));
|
2016-10-02 22:55:54 +00:00
|
|
|
m_instanceFolder = new FolderInstanceProvider(m_settings, instDir);
|
|
|
|
connect(InstDirSetting.get(), &Setting::SettingChanged, m_instanceFolder, &FolderInstanceProvider::on_InstFolderChanged);
|
|
|
|
m_instances->addInstanceProvider(m_instanceFolder);
|
|
|
|
m_instances->addInstanceProvider(new FTBInstanceProvider(m_settings));
|
|
|
|
|
2015-02-02 01:14:14 +00:00
|
|
|
qDebug() << "Loading Instances...";
|
2016-10-02 22:55:54 +00:00
|
|
|
m_instances->loadList(true);
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2013-11-18 18:58:03 +00:00
|
|
|
// and accounts
|
|
|
|
m_accounts.reset(new MojangAccountList(this));
|
2015-02-02 01:14:14 +00:00
|
|
|
qDebug() << "Loading accounts...";
|
2013-11-19 18:53:30 +00:00
|
|
|
m_accounts->setListFilePath("accounts.json", true);
|
2013-11-18 18:58:03 +00:00
|
|
|
m_accounts->loadList();
|
|
|
|
|
2013-09-08 00:15:20 +00:00
|
|
|
// init the http meta cache
|
2015-12-27 02:34:03 +00:00
|
|
|
ENV.initHttpMetaCache();
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2013-09-08 00:15:20 +00:00
|
|
|
// create the global network manager
|
2015-01-31 15:59:03 +00:00
|
|
|
ENV.m_qnam.reset(new QNetworkAccessManager(this));
|
2014-09-30 00:05:44 +00:00
|
|
|
|
2014-01-06 21:02:58 +00:00
|
|
|
// init proxy settings
|
2015-01-31 15:59:03 +00:00
|
|
|
{
|
|
|
|
QString proxyTypeStr = settings()->get("ProxyType").toString();
|
|
|
|
QString addr = settings()->get("ProxyAddr").toString();
|
|
|
|
int port = settings()->get("ProxyPort").value<qint16>();
|
|
|
|
QString user = settings()->get("ProxyUser").toString();
|
|
|
|
QString pass = settings()->get("ProxyPass").toString();
|
|
|
|
ENV.updateProxySettings(proxyTypeStr, addr, port, user, pass);
|
|
|
|
}
|
|
|
|
|
2015-05-19 20:28:51 +00:00
|
|
|
initSSL();
|
|
|
|
|
2015-01-31 15:59:03 +00:00
|
|
|
m_translationChecker->downloadTranslations();
|
2014-01-06 21:02:58 +00:00
|
|
|
|
2015-01-27 21:31:07 +00:00
|
|
|
//FIXME: what to do with these?
|
2014-02-15 13:19:35 +00:00
|
|
|
m_profilers.insert("jprofiler",
|
|
|
|
std::shared_ptr<BaseProfilerFactory>(new JProfilerFactory()));
|
|
|
|
m_profilers.insert("jvisualvm",
|
|
|
|
std::shared_ptr<BaseProfilerFactory>(new JVisualVMFactory()));
|
|
|
|
for (auto profiler : m_profilers.values())
|
|
|
|
{
|
2014-09-06 16:16:56 +00:00
|
|
|
profiler->registerSettings(m_settings);
|
2014-02-15 13:19:35 +00:00
|
|
|
}
|
2015-01-27 21:31:07 +00:00
|
|
|
|
|
|
|
//FIXME: what to do with these?
|
2014-07-27 13:50:03 +00:00
|
|
|
m_tools.insert("mcedit", std::shared_ptr<BaseDetachedToolFactory>(new MCEditFactory()));
|
2014-02-16 09:46:14 +00:00
|
|
|
for (auto tool : m_tools.values())
|
|
|
|
{
|
2014-09-06 16:16:56 +00:00
|
|
|
tool->registerSettings(m_settings);
|
2014-02-16 09:46:14 +00:00
|
|
|
}
|
2014-02-15 13:19:35 +00:00
|
|
|
|
2014-01-05 12:17:42 +00:00
|
|
|
connect(this, SIGNAL(aboutToQuit()), SLOT(onExit()));
|
2013-09-07 02:00:58 +00:00
|
|
|
m_status = MultiMC::Initialized;
|
|
|
|
}
|
|
|
|
|
|
|
|
MultiMC::~MultiMC()
|
|
|
|
{
|
2013-09-22 22:23:50 +00:00
|
|
|
if (m_mmc_translator)
|
2013-09-08 23:20:17 +00:00
|
|
|
{
|
2013-10-05 23:13:40 +00:00
|
|
|
removeTranslator(m_mmc_translator.get());
|
2013-09-08 23:20:17 +00:00
|
|
|
}
|
2013-09-22 22:23:50 +00:00
|
|
|
if (m_qt_translator)
|
2013-09-08 23:20:17 +00:00
|
|
|
{
|
2013-10-05 23:13:40 +00:00
|
|
|
removeTranslator(m_qt_translator.get());
|
2013-09-08 23:20:17 +00:00
|
|
|
}
|
2016-06-08 23:58:50 +00:00
|
|
|
#if defined Q_OS_WIN32
|
|
|
|
if(consoleAttached)
|
|
|
|
{
|
|
|
|
const char * endline = "\n";
|
|
|
|
auto out = GetStdHandle (STD_OUTPUT_HANDLE);
|
|
|
|
DWORD written;
|
|
|
|
WriteConsole(out, endline, strlen(endline), &written, NULL);
|
|
|
|
}
|
|
|
|
#endif
|
2013-09-07 02:00:58 +00:00
|
|
|
}
|
|
|
|
|
2015-09-28 22:48:33 +00:00
|
|
|
#ifdef Q_OS_MAC
|
|
|
|
#include "CertWorkaround.h"
|
|
|
|
#endif
|
|
|
|
|
2015-05-19 20:28:51 +00:00
|
|
|
void MultiMC::initSSL()
|
|
|
|
{
|
|
|
|
#ifdef Q_OS_MAC
|
|
|
|
Q_INIT_RESOURCE(certs);
|
2015-09-28 22:48:33 +00:00
|
|
|
RebuildQtCertificates();
|
2015-05-19 20:28:51 +00:00
|
|
|
QFile equifaxFile(":/certs/Equifax_Secure_Certificate_Authority.pem");
|
|
|
|
equifaxFile.open(QIODevice::ReadOnly);
|
|
|
|
QSslCertificate equifaxCert(equifaxFile.readAll(), QSsl::Pem);
|
|
|
|
QSslSocket::addDefaultCaCertificate(equifaxCert);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-09-08 23:20:17 +00:00
|
|
|
void MultiMC::initTranslations()
|
|
|
|
{
|
2014-01-04 15:13:28 +00:00
|
|
|
QLocale locale(m_settings->get("Language").toString());
|
|
|
|
QLocale::setDefault(locale);
|
2015-02-02 01:14:14 +00:00
|
|
|
qDebug() << "Your language is" << locale.bcp47Name();
|
2013-09-22 02:21:36 +00:00
|
|
|
m_qt_translator.reset(new QTranslator());
|
2014-01-04 15:13:28 +00:00
|
|
|
if (m_qt_translator->load("qt_" + locale.bcp47Name(),
|
2013-09-22 22:23:50 +00:00
|
|
|
QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
2013-09-08 23:20:17 +00:00
|
|
|
{
|
2015-02-02 01:14:14 +00:00
|
|
|
qDebug() << "Loading Qt Language File for"
|
2014-01-04 15:13:28 +00:00
|
|
|
<< locale.bcp47Name().toLocal8Bit().constData() << "...";
|
2013-10-05 23:13:40 +00:00
|
|
|
if (!installTranslator(m_qt_translator.get()))
|
2013-09-08 23:20:17 +00:00
|
|
|
{
|
2015-02-02 01:14:14 +00:00
|
|
|
qCritical() << "Loading Qt Language File failed.";
|
2013-09-22 02:21:36 +00:00
|
|
|
m_qt_translator.reset();
|
2013-09-08 23:20:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-09-22 02:21:36 +00:00
|
|
|
m_qt_translator.reset();
|
2013-09-08 23:20:17 +00:00
|
|
|
}
|
|
|
|
|
2013-09-22 02:21:36 +00:00
|
|
|
m_mmc_translator.reset(new QTranslator());
|
2015-12-27 02:34:03 +00:00
|
|
|
if (m_mmc_translator->load("mmc_" + locale.bcp47Name(), FS::PathCombine(QDir::currentPath(), "translations")))
|
2013-09-08 23:20:17 +00:00
|
|
|
{
|
2015-02-02 01:14:14 +00:00
|
|
|
qDebug() << "Loading MMC Language File for"
|
2014-01-04 15:13:28 +00:00
|
|
|
<< locale.bcp47Name().toLocal8Bit().constData() << "...";
|
2013-10-05 23:13:40 +00:00
|
|
|
if (!installTranslator(m_mmc_translator.get()))
|
2013-09-08 23:20:17 +00:00
|
|
|
{
|
2015-02-02 01:14:14 +00:00
|
|
|
qCritical() << "Loading MMC Language File failed.";
|
2013-09-22 02:21:36 +00:00
|
|
|
m_mmc_translator.reset();
|
2013-09-08 23:20:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-09-22 02:21:36 +00:00
|
|
|
m_mmc_translator.reset();
|
2013-09-08 23:20:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-01 10:44:47 +00:00
|
|
|
void MultiMC::initIcons()
|
|
|
|
{
|
|
|
|
auto setting = MMC->settings()->getSetting("IconsDir");
|
2016-04-10 02:29:29 +00:00
|
|
|
m_icons.reset(new IconList(QString(":/icons/instances/"), setting->get().toString()));
|
2015-02-01 10:44:47 +00:00
|
|
|
connect(setting.get(), &Setting::SettingChanged,[&](const Setting &, QVariant value)
|
|
|
|
{
|
2016-04-10 02:29:29 +00:00
|
|
|
m_icons->directoryChanged(value.toString());
|
2015-02-01 10:44:47 +00:00
|
|
|
});
|
2016-05-02 22:27:28 +00:00
|
|
|
ENV.registerIconList(m_icons);
|
2015-02-01 10:44:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-21 10:05:44 +00:00
|
|
|
void moveFile(const QString &oldName, const QString &newName)
|
|
|
|
{
|
|
|
|
QFile::remove(newName);
|
|
|
|
QFile::copy(oldName, newName);
|
|
|
|
QFile::remove(oldName);
|
|
|
|
}
|
2015-02-02 01:14:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
void appDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
|
|
|
{
|
|
|
|
const char *levels = "DWCF";
|
|
|
|
const QString format("%1 %2 %3\n");
|
|
|
|
|
|
|
|
qint64 msecstotal = MMC->timeSinceStart();
|
|
|
|
qint64 seconds = msecstotal / 1000;
|
|
|
|
qint64 msecs = msecstotal % 1000;
|
|
|
|
QString foo;
|
|
|
|
char buf[1025] = {0};
|
|
|
|
::snprintf(buf, 1024, "%5lld.%03lld", seconds, msecs);
|
|
|
|
|
|
|
|
QString out = format.arg(buf).arg(levels[type]).arg(msg);
|
|
|
|
|
|
|
|
MMC->logFile->write(out.toUtf8());
|
|
|
|
MMC->logFile->flush();
|
|
|
|
QTextStream(stderr) << out.toLocal8Bit();
|
|
|
|
fflush(stderr);
|
|
|
|
}
|
|
|
|
|
2013-10-05 23:13:40 +00:00
|
|
|
void MultiMC::initLogger()
|
|
|
|
{
|
2013-12-21 10:05:44 +00:00
|
|
|
static const QString logBase = "MultiMC-%0.log";
|
|
|
|
|
|
|
|
moveFile(logBase.arg(3), logBase.arg(4));
|
|
|
|
moveFile(logBase.arg(2), logBase.arg(3));
|
|
|
|
moveFile(logBase.arg(1), logBase.arg(2));
|
|
|
|
moveFile(logBase.arg(0), logBase.arg(1));
|
|
|
|
|
2015-02-02 01:14:14 +00:00
|
|
|
qInstallMessageHandler(appDebugOutput);
|
|
|
|
|
|
|
|
logFile = std::make_shared<QFile>(logBase.arg(0));
|
|
|
|
logFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
|
2013-10-05 23:13:40 +00:00
|
|
|
}
|
|
|
|
|
2014-11-09 19:49:23 +00:00
|
|
|
void MultiMC::initGlobalSettings(bool test_mode)
|
2013-09-07 02:00:58 +00:00
|
|
|
{
|
2013-09-22 02:21:36 +00:00
|
|
|
m_settings.reset(new INISettingsObject("multimc.cfg", this));
|
2013-09-22 22:23:50 +00:00
|
|
|
// Updates
|
2014-04-05 20:58:47 +00:00
|
|
|
m_settings->registerSetting("UpdateChannel", BuildConfig.VERSION_CHANNEL);
|
2014-01-01 14:08:40 +00:00
|
|
|
m_settings->registerSetting("AutoUpdate", true);
|
2016-10-21 07:07:26 +00:00
|
|
|
|
|
|
|
// Theming
|
2014-05-25 01:22:17 +00:00
|
|
|
m_settings->registerSetting("IconTheme", QString("multimc"));
|
2016-10-21 07:07:26 +00:00
|
|
|
m_settings->registerSetting("ApplicationTheme", QString("system"));
|
2014-02-13 21:00:51 +00:00
|
|
|
|
2014-01-05 01:46:47 +00:00
|
|
|
// Notifications
|
2014-01-03 18:19:27 +00:00
|
|
|
m_settings->registerSetting("ShownNotifications", QString());
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2014-11-08 20:17:28 +00:00
|
|
|
// Remembered state
|
|
|
|
m_settings->registerSetting("LastUsedGroupForNewInstance", QString());
|
|
|
|
|
2014-11-10 05:26:17 +00:00
|
|
|
QString defaultMonospace;
|
2014-12-03 20:48:27 +00:00
|
|
|
int defaultSize = 11;
|
2014-11-10 05:26:17 +00:00
|
|
|
#ifdef Q_OS_WIN32
|
2014-12-03 20:48:27 +00:00
|
|
|
defaultMonospace = "Courier";
|
|
|
|
defaultSize = 10;
|
2014-11-11 14:43:32 +00:00
|
|
|
#elif defined(Q_OS_MAC)
|
2014-11-10 05:26:17 +00:00
|
|
|
defaultMonospace = "Menlo";
|
|
|
|
#else
|
|
|
|
defaultMonospace = "Monospace";
|
|
|
|
#endif
|
2014-11-09 19:49:23 +00:00
|
|
|
if(!test_mode)
|
|
|
|
{
|
2014-11-10 05:26:17 +00:00
|
|
|
// resolve the font so the default actually matches
|
2014-11-09 19:49:23 +00:00
|
|
|
QFont consoleFont;
|
2014-11-10 05:26:17 +00:00
|
|
|
consoleFont.setFamily(defaultMonospace);
|
2014-11-09 19:49:23 +00:00
|
|
|
consoleFont.setStyleHint(QFont::Monospace);
|
|
|
|
consoleFont.setFixedPitch(true);
|
|
|
|
QFontInfo consoleFontInfo(consoleFont);
|
2014-11-10 05:26:17 +00:00
|
|
|
QString resolvedDefaultMonospace = consoleFontInfo.family();
|
|
|
|
QFont resolvedFont(resolvedDefaultMonospace);
|
2015-02-02 01:14:14 +00:00
|
|
|
qDebug() << "Detected default console font:" << resolvedDefaultMonospace
|
2014-11-10 05:26:17 +00:00
|
|
|
<< ", substitutions:" << resolvedFont.substitutions().join(',');
|
|
|
|
m_settings->registerSetting("ConsoleFont", resolvedDefaultMonospace);
|
2014-11-09 19:49:23 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-11-10 05:26:17 +00:00
|
|
|
// in test mode, we don't have UI, so we don't do any font resolving
|
|
|
|
m_settings->registerSetting("ConsoleFont", defaultMonospace);
|
2014-11-09 19:49:23 +00:00
|
|
|
}
|
2014-12-03 20:48:27 +00:00
|
|
|
m_settings->registerSetting("ConsoleFontSize", defaultSize);
|
2015-06-10 23:49:13 +00:00
|
|
|
m_settings->registerSetting("ConsoleMaxLines", 100000);
|
|
|
|
m_settings->registerSetting("ConsoleOverflowStop", true);
|
2014-11-09 18:48:35 +00:00
|
|
|
|
2015-02-02 00:09:28 +00:00
|
|
|
FTBPlugin::initialize(m_settings);
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2013-09-07 02:00:58 +00:00
|
|
|
// Folders
|
2014-01-01 14:08:40 +00:00
|
|
|
m_settings->registerSetting("InstanceDir", "instances");
|
|
|
|
m_settings->registerSetting({"CentralModsDir", "ModsDir"}, "mods");
|
|
|
|
m_settings->registerSetting({"LWJGLDir", "LwjglDir"}, "lwjgl");
|
|
|
|
m_settings->registerSetting("IconsDir", "icons");
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2013-12-29 16:51:16 +00:00
|
|
|
// Editors
|
2014-01-01 14:08:40 +00:00
|
|
|
m_settings->registerSetting("JsonEditor", QString());
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2014-01-04 15:13:28 +00:00
|
|
|
// Language
|
|
|
|
m_settings->registerSetting("Language", QLocale(QLocale::system().language()).bcp47Name());
|
|
|
|
|
2013-09-07 02:00:58 +00:00
|
|
|
// Console
|
2014-01-01 14:08:40 +00:00
|
|
|
m_settings->registerSetting("ShowConsole", true);
|
2014-04-17 12:13:16 +00:00
|
|
|
m_settings->registerSetting("RaiseConsole", true);
|
2014-01-01 14:08:40 +00:00
|
|
|
m_settings->registerSetting("AutoCloseConsole", true);
|
2014-01-17 21:55:10 +00:00
|
|
|
m_settings->registerSetting("LogPrePostOutput", true);
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2013-09-07 02:00:58 +00:00
|
|
|
// Console Colors
|
2014-01-01 14:08:40 +00:00
|
|
|
// m_settings->registerSetting("SysMessageColor", QColor(Qt::blue));
|
|
|
|
// m_settings->registerSetting("StdOutColor", QColor(Qt::black));
|
|
|
|
// m_settings->registerSetting("StdErrColor", QColor(Qt::red));
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2013-09-07 02:00:58 +00:00
|
|
|
// Window Size
|
2014-01-01 14:08:40 +00:00
|
|
|
m_settings->registerSetting({"LaunchMaximized", "MCWindowMaximize"}, false);
|
|
|
|
m_settings->registerSetting({"MinecraftWinWidth", "MCWindowWidth"}, 854);
|
|
|
|
m_settings->registerSetting({"MinecraftWinHeight", "MCWindowHeight"}, 480);
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2014-01-06 21:02:58 +00:00
|
|
|
// Proxy Settings
|
2015-02-05 23:41:36 +00:00
|
|
|
m_settings->registerSetting("ProxyType", "None");
|
2014-01-06 21:02:58 +00:00
|
|
|
m_settings->registerSetting({"ProxyAddr", "ProxyHostName"}, "127.0.0.1");
|
|
|
|
m_settings->registerSetting("ProxyPort", 8080);
|
|
|
|
m_settings->registerSetting({"ProxyUser", "ProxyUsername"}, "");
|
|
|
|
m_settings->registerSetting({"ProxyPass", "ProxyPassword"}, "");
|
|
|
|
|
2013-09-07 02:00:58 +00:00
|
|
|
// Memory
|
2014-01-01 14:08:40 +00:00
|
|
|
m_settings->registerSetting({"MinMemAlloc", "MinMemoryAlloc"}, 512);
|
|
|
|
m_settings->registerSetting({"MaxMemAlloc", "MaxMemoryAlloc"}, 1024);
|
2015-02-02 08:42:36 +00:00
|
|
|
m_settings->registerSetting("PermGen", 128);
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2013-09-07 02:00:58 +00:00
|
|
|
// Java Settings
|
2014-01-01 14:08:40 +00:00
|
|
|
m_settings->registerSetting("JavaPath", "");
|
2015-05-03 23:20:48 +00:00
|
|
|
m_settings->registerSetting("JavaTimestamp", 0);
|
2016-06-16 00:20:23 +00:00
|
|
|
m_settings->registerSetting("JavaArchitecture", "");
|
2015-05-03 23:20:48 +00:00
|
|
|
m_settings->registerSetting("JavaVersion", "");
|
2014-01-01 14:08:40 +00:00
|
|
|
m_settings->registerSetting("LastHostname", "");
|
2014-06-27 22:05:00 +00:00
|
|
|
m_settings->registerSetting("JavaDetectionHack", "");
|
2014-01-01 14:08:40 +00:00
|
|
|
m_settings->registerSetting("JvmArgs", "");
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2016-06-16 00:20:23 +00:00
|
|
|
// Minecraft launch method
|
|
|
|
m_settings->registerSetting("MCLaunchMethod", "LauncherPart");
|
|
|
|
|
2015-05-24 12:49:54 +00:00
|
|
|
// Wrapper command for launch
|
|
|
|
m_settings->registerSetting("WrapperCommand", "");
|
|
|
|
|
2013-09-07 02:00:58 +00:00
|
|
|
// Custom Commands
|
2014-01-01 14:08:40 +00:00
|
|
|
m_settings->registerSetting({"PreLaunchCommand", "PreLaunchCmd"}, "");
|
2014-01-01 15:17:49 +00:00
|
|
|
m_settings->registerSetting({"PostExitCommand", "PostExitCmd"}, "");
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2013-09-07 02:00:58 +00:00
|
|
|
// The cat
|
2014-01-01 14:08:40 +00:00
|
|
|
m_settings->registerSetting("TheCat", false);
|
2013-09-22 22:23:50 +00:00
|
|
|
|
2014-01-01 14:08:40 +00:00
|
|
|
m_settings->registerSetting("InstSortMode", "Name");
|
|
|
|
m_settings->registerSetting("SelectedInstance", QString());
|
2013-11-03 00:45:25 +00:00
|
|
|
|
|
|
|
// Window state and geometry
|
2014-01-01 14:08:40 +00:00
|
|
|
m_settings->registerSetting("MainWindowState", "");
|
|
|
|
m_settings->registerSetting("MainWindowGeometry", "");
|
2013-11-23 00:41:28 +00:00
|
|
|
|
2014-01-01 14:08:40 +00:00
|
|
|
m_settings->registerSetting("ConsoleWindowState", "");
|
|
|
|
m_settings->registerSetting("ConsoleWindowGeometry", "");
|
2013-11-23 00:41:28 +00:00
|
|
|
|
2014-01-02 02:20:34 +00:00
|
|
|
m_settings->registerSetting("SettingsGeometry", "");
|
2014-06-02 23:34:44 +00:00
|
|
|
|
|
|
|
m_settings->registerSetting("PagedGeometry", "");
|
2015-05-29 00:22:02 +00:00
|
|
|
|
|
|
|
// Jar mod nag dialog in version page
|
|
|
|
m_settings->registerSetting("JarModNagSeen", false);
|
2015-07-05 00:29:41 +00:00
|
|
|
|
2015-10-01 22:12:53 +00:00
|
|
|
// paste.ee API key
|
|
|
|
m_settings->registerSetting("PasteEEAPIKey", "multimc");
|
2015-07-05 00:29:41 +00:00
|
|
|
|
|
|
|
// Init page provider
|
|
|
|
{
|
|
|
|
m_globalSettingsProvider = std::make_shared<GenericPageProvider>(tr("Settings"));
|
|
|
|
m_globalSettingsProvider->addPage<MultiMCPage>();
|
|
|
|
m_globalSettingsProvider->addPage<MinecraftPage>();
|
|
|
|
m_globalSettingsProvider->addPage<JavaPage>();
|
|
|
|
m_globalSettingsProvider->addPage<ProxyPage>();
|
|
|
|
m_globalSettingsProvider->addPage<ExternalToolsPage>();
|
|
|
|
m_globalSettingsProvider->addPage<AccountListPage>();
|
2015-10-01 22:12:53 +00:00
|
|
|
m_globalSettingsProvider->addPage<PasteEEPage>();
|
2015-07-05 00:29:41 +00:00
|
|
|
}
|
2013-09-07 02:00:58 +00:00
|
|
|
}
|
|
|
|
|
2013-10-05 23:13:40 +00:00
|
|
|
std::shared_ptr<LWJGLVersionList> MultiMC::lwjgllist()
|
2013-09-15 22:54:39 +00:00
|
|
|
{
|
2013-09-22 22:23:50 +00:00
|
|
|
if (!m_lwjgllist)
|
2013-09-15 22:54:39 +00:00
|
|
|
{
|
2013-09-22 02:21:36 +00:00
|
|
|
m_lwjgllist.reset(new LWJGLVersionList());
|
2015-02-02 00:09:28 +00:00
|
|
|
ENV.registerVersionList("org.lwjgl.legacy", m_lwjgllist);
|
2013-09-15 22:54:39 +00:00
|
|
|
}
|
|
|
|
return m_lwjgllist;
|
|
|
|
}
|
2013-09-22 02:21:36 +00:00
|
|
|
|
2013-10-05 23:13:40 +00:00
|
|
|
std::shared_ptr<ForgeVersionList> MultiMC::forgelist()
|
2013-09-15 22:54:39 +00:00
|
|
|
{
|
2013-09-22 22:23:50 +00:00
|
|
|
if (!m_forgelist)
|
2013-09-15 22:54:39 +00:00
|
|
|
{
|
2013-09-22 02:21:36 +00:00
|
|
|
m_forgelist.reset(new ForgeVersionList());
|
2015-02-02 00:09:28 +00:00
|
|
|
ENV.registerVersionList("net.minecraftforge", m_forgelist);
|
2013-09-15 22:54:39 +00:00
|
|
|
}
|
|
|
|
return m_forgelist;
|
|
|
|
}
|
|
|
|
|
2014-02-19 21:34:17 +00:00
|
|
|
std::shared_ptr<LiteLoaderVersionList> MultiMC::liteloaderlist()
|
|
|
|
{
|
|
|
|
if (!m_liteloaderlist)
|
|
|
|
{
|
|
|
|
m_liteloaderlist.reset(new LiteLoaderVersionList());
|
2015-02-02 00:09:28 +00:00
|
|
|
ENV.registerVersionList("com.mumfrey.liteloader", m_liteloaderlist);
|
2014-02-19 21:34:17 +00:00
|
|
|
}
|
|
|
|
return m_liteloaderlist;
|
|
|
|
}
|
|
|
|
|
2013-10-05 23:13:40 +00:00
|
|
|
std::shared_ptr<MinecraftVersionList> MultiMC::minecraftlist()
|
2013-09-15 22:54:39 +00:00
|
|
|
{
|
2013-09-22 22:23:50 +00:00
|
|
|
if (!m_minecraftlist)
|
2013-09-15 22:54:39 +00:00
|
|
|
{
|
2013-09-22 02:21:36 +00:00
|
|
|
m_minecraftlist.reset(new MinecraftVersionList());
|
2015-02-03 01:39:15 +00:00
|
|
|
ENV.registerVersionList("net.minecraft", m_minecraftlist);
|
2013-09-15 22:54:39 +00:00
|
|
|
}
|
|
|
|
return m_minecraftlist;
|
|
|
|
}
|
|
|
|
|
2016-01-01 23:35:54 +00:00
|
|
|
std::shared_ptr<JavaInstallList> MultiMC::javalist()
|
2013-10-14 01:59:21 +00:00
|
|
|
{
|
|
|
|
if (!m_javalist)
|
|
|
|
{
|
2016-01-01 23:35:54 +00:00
|
|
|
m_javalist.reset(new JavaInstallList());
|
2015-02-03 01:39:15 +00:00
|
|
|
ENV.registerVersionList("com.java", m_javalist);
|
2013-10-14 01:59:21 +00:00
|
|
|
}
|
|
|
|
return m_javalist;
|
|
|
|
}
|
|
|
|
|
2015-06-08 00:43:16 +00:00
|
|
|
// from <sys/stat.h>
|
|
|
|
#ifndef S_IRUSR
|
|
|
|
#define __S_IREAD 0400 /* Read by owner. */
|
|
|
|
#define __S_IWRITE 0200 /* Write by owner. */
|
|
|
|
#define __S_IEXEC 0100 /* Execute by owner. */
|
|
|
|
#define S_IRUSR __S_IREAD /* Read by owner. */
|
|
|
|
#define S_IWUSR __S_IWRITE /* Write by owner. */
|
|
|
|
#define S_IXUSR __S_IEXEC /* Execute by owner. */
|
|
|
|
|
|
|
|
#define S_IRGRP (S_IRUSR >> 3) /* Read by group. */
|
|
|
|
#define S_IWGRP (S_IWUSR >> 3) /* Write by group. */
|
|
|
|
#define S_IXGRP (S_IXUSR >> 3) /* Execute by group. */
|
|
|
|
|
|
|
|
#define S_IROTH (S_IRGRP >> 3) /* Read by others. */
|
|
|
|
#define S_IWOTH (S_IWGRP >> 3) /* Write by others. */
|
|
|
|
#define S_IXOTH (S_IXGRP >> 3) /* Execute by others. */
|
|
|
|
#endif
|
|
|
|
static QFile::Permissions unixModeToPermissions(const int mode)
|
|
|
|
{
|
|
|
|
QFile::Permissions perms;
|
|
|
|
|
|
|
|
if (mode & S_IRUSR)
|
|
|
|
{
|
|
|
|
perms |= QFile::ReadUser;
|
|
|
|
}
|
|
|
|
if (mode & S_IWUSR)
|
|
|
|
{
|
|
|
|
perms |= QFile::WriteUser;
|
|
|
|
}
|
|
|
|
if (mode & S_IXUSR)
|
|
|
|
{
|
|
|
|
perms |= QFile::ExeUser;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode & S_IRGRP)
|
|
|
|
{
|
|
|
|
perms |= QFile::ReadGroup;
|
|
|
|
}
|
|
|
|
if (mode & S_IWGRP)
|
|
|
|
{
|
|
|
|
perms |= QFile::WriteGroup;
|
|
|
|
}
|
|
|
|
if (mode & S_IXGRP)
|
|
|
|
{
|
|
|
|
perms |= QFile::ExeGroup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode & S_IROTH)
|
|
|
|
{
|
|
|
|
perms |= QFile::ReadOther;
|
|
|
|
}
|
|
|
|
if (mode & S_IWOTH)
|
|
|
|
{
|
|
|
|
perms |= QFile::WriteOther;
|
|
|
|
}
|
|
|
|
if (mode & S_IXOTH)
|
|
|
|
{
|
|
|
|
perms |= QFile::ExeOther;
|
|
|
|
}
|
|
|
|
return perms;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MultiMC::installUpdates(const QString updateFilesDir, GoUpdate::OperationList operations)
|
2013-12-06 18:59:58 +00:00
|
|
|
{
|
2015-06-08 22:48:25 +00:00
|
|
|
qint64 pid = -1;
|
|
|
|
QStringList args;
|
|
|
|
bool started = false;
|
|
|
|
|
2015-02-02 01:14:14 +00:00
|
|
|
qDebug() << "Installing updates.";
|
2015-10-04 23:47:27 +00:00
|
|
|
#ifdef Q_OS_WIN
|
2015-01-27 21:31:07 +00:00
|
|
|
QString finishCmd = applicationFilePath();
|
2015-10-04 23:47:27 +00:00
|
|
|
#elif defined Q_OS_LINUX
|
|
|
|
QString finishCmd = FS::PathCombine(root(), "MultiMC");
|
|
|
|
#elif defined Q_OS_MAC
|
2015-01-27 21:31:07 +00:00
|
|
|
QString finishCmd = applicationFilePath();
|
2014-07-27 13:50:03 +00:00
|
|
|
#else
|
|
|
|
#error Unsupported operating system.
|
|
|
|
#endif
|
2014-01-05 15:47:12 +00:00
|
|
|
|
2015-10-04 23:47:27 +00:00
|
|
|
QString backupPath = FS::PathCombine(root(), "update", "backup");
|
2015-06-09 22:46:45 +00:00
|
|
|
QDir origin(root());
|
2015-06-09 21:23:46 +00:00
|
|
|
|
|
|
|
// clean up the backup folder. it should be empty before we start
|
2015-10-04 23:47:27 +00:00
|
|
|
if(!FS::deletePath(backupPath))
|
2015-06-08 00:43:16 +00:00
|
|
|
{
|
2015-06-09 21:23:46 +00:00
|
|
|
qWarning() << "couldn't remove previous backup folder" << backupPath;
|
2015-06-08 00:43:16 +00:00
|
|
|
}
|
2015-06-09 21:23:46 +00:00
|
|
|
// and it should exist.
|
2015-10-04 23:47:27 +00:00
|
|
|
if(!FS::ensureFolderPathExists(backupPath))
|
2015-06-08 00:43:16 +00:00
|
|
|
{
|
2015-06-09 21:23:46 +00:00
|
|
|
qWarning() << "couldn't create folder" << backupPath;
|
2015-06-08 00:43:16 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-06-09 21:23:46 +00:00
|
|
|
|
2015-06-08 00:43:16 +00:00
|
|
|
struct BackupEntry
|
|
|
|
{
|
|
|
|
QString orig;
|
|
|
|
QString backup;
|
|
|
|
};
|
2015-06-09 18:58:19 +00:00
|
|
|
enum Failure
|
|
|
|
{
|
2015-06-09 21:23:46 +00:00
|
|
|
Replace,
|
2015-06-09 18:58:19 +00:00
|
|
|
Delete,
|
|
|
|
Start,
|
|
|
|
Nothing
|
|
|
|
} failedOperationType = Nothing;
|
|
|
|
QString failedFile;
|
|
|
|
|
2015-06-08 00:43:16 +00:00
|
|
|
QList <BackupEntry> backups;
|
|
|
|
QList <BackupEntry> trashcan;
|
2015-06-09 21:23:46 +00:00
|
|
|
|
2015-06-10 00:31:34 +00:00
|
|
|
bool useXPHack = false;
|
|
|
|
QString exePath;
|
|
|
|
QString exeOrigin;
|
|
|
|
QString exeBackup;
|
|
|
|
|
2015-06-09 21:23:46 +00:00
|
|
|
// perform the update operations
|
2015-06-08 00:43:16 +00:00
|
|
|
for(auto op: operations)
|
|
|
|
{
|
|
|
|
switch(op.type)
|
|
|
|
{
|
2015-06-09 21:23:46 +00:00
|
|
|
// replace = move original out to backup, if it exists, move the new file in its place
|
|
|
|
case GoUpdate::Operation::OP_REPLACE:
|
2015-06-08 00:43:16 +00:00
|
|
|
{
|
2016-01-12 05:52:29 +00:00
|
|
|
#ifdef Q_OS_WIN32
|
|
|
|
// hack for people renaming the .exe because ... reasons :)
|
|
|
|
if(op.dest == "MultiMC.exe")
|
|
|
|
{
|
|
|
|
op.dest = QFileInfo(applicationFilePath()).fileName();
|
|
|
|
}
|
|
|
|
#endif
|
2015-10-04 23:47:27 +00:00
|
|
|
QFileInfo replaced (FS::PathCombine(root(), op.dest));
|
2015-06-10 00:31:34 +00:00
|
|
|
#ifdef Q_OS_WIN32
|
|
|
|
if(QSysInfo::windowsVersion() < QSysInfo::WV_VISTA)
|
|
|
|
{
|
|
|
|
if(replaced.fileName() == "MultiMC.exe")
|
|
|
|
{
|
|
|
|
QDir rootDir(root());
|
|
|
|
exeOrigin = rootDir.relativeFilePath(op.file);
|
|
|
|
exePath = rootDir.relativeFilePath(op.dest);
|
2015-10-04 23:47:27 +00:00
|
|
|
exeBackup = rootDir.relativeFilePath(FS::PathCombine(backupPath, replaced.fileName()));
|
2015-06-10 00:31:34 +00:00
|
|
|
useXPHack = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2015-06-08 00:43:16 +00:00
|
|
|
if(replaced.exists())
|
|
|
|
{
|
2015-06-09 21:23:46 +00:00
|
|
|
QString backupName = op.dest;
|
|
|
|
backupName.replace('/', '_');
|
2015-10-04 23:47:27 +00:00
|
|
|
QString backupFilePath = FS::PathCombine(backupPath, backupName);
|
2015-06-08 22:48:25 +00:00
|
|
|
if(!QFile::rename(replaced.absoluteFilePath(), backupFilePath))
|
|
|
|
{
|
2015-06-09 21:23:46 +00:00
|
|
|
qWarning() << "Couldn't move:" << replaced.absoluteFilePath() << "to" << backupFilePath;
|
|
|
|
failedOperationType = Replace;
|
2015-06-09 18:58:19 +00:00
|
|
|
failedFile = op.dest;
|
2015-06-08 22:48:25 +00:00
|
|
|
goto FAILED;
|
|
|
|
}
|
2015-06-08 00:43:16 +00:00
|
|
|
BackupEntry be;
|
|
|
|
be.orig = replaced.absoluteFilePath();
|
|
|
|
be.backup = backupFilePath;
|
|
|
|
backups.append(be);
|
|
|
|
}
|
2015-06-09 21:23:46 +00:00
|
|
|
// make sure the folder we are putting this into exists
|
2015-10-04 23:47:27 +00:00
|
|
|
if(!FS::ensureFilePathExists(replaced.absoluteFilePath()))
|
2015-06-09 21:23:46 +00:00
|
|
|
{
|
|
|
|
qWarning() << "REPLACE: Couldn't create folder:" << replaced.absoluteFilePath();
|
|
|
|
failedOperationType = Replace;
|
|
|
|
failedFile = op.dest;
|
|
|
|
goto FAILED;
|
|
|
|
}
|
|
|
|
// now move the new file in
|
|
|
|
if(!QFile::rename(op.file, replaced.absoluteFilePath()))
|
2015-06-08 22:48:25 +00:00
|
|
|
{
|
2015-06-09 21:23:46 +00:00
|
|
|
qWarning() << "REPLACE: Couldn't move:" << op.file << "to" << replaced.absoluteFilePath();
|
|
|
|
failedOperationType = Replace;
|
2015-06-09 18:58:19 +00:00
|
|
|
failedFile = op.dest;
|
2015-06-08 22:48:25 +00:00
|
|
|
goto FAILED;
|
|
|
|
}
|
2015-06-08 00:43:16 +00:00
|
|
|
QFile::setPermissions(replaced.absoluteFilePath(), unixModeToPermissions(op.mode));
|
|
|
|
}
|
|
|
|
break;
|
2015-06-09 21:23:46 +00:00
|
|
|
// delete = move original to backup
|
2015-06-08 00:43:16 +00:00
|
|
|
case GoUpdate::Operation::OP_DELETE:
|
|
|
|
{
|
2015-10-04 23:47:27 +00:00
|
|
|
QString origFilePath = FS::PathCombine(root(), op.file);
|
2015-06-08 00:43:16 +00:00
|
|
|
if(QFile::exists(origFilePath))
|
|
|
|
{
|
2015-08-23 20:33:59 +00:00
|
|
|
QString backupName = op.file;
|
|
|
|
backupName.replace('/', '_');
|
2015-10-04 23:47:27 +00:00
|
|
|
QString trashFilePath = FS::PathCombine(backupPath, backupName);
|
2015-08-23 20:33:59 +00:00
|
|
|
|
2015-06-09 18:58:19 +00:00
|
|
|
if(!QFile::rename(origFilePath, trashFilePath))
|
|
|
|
{
|
2015-06-09 21:23:46 +00:00
|
|
|
qWarning() << "DELETE: Couldn't move:" << op.file << "to" << trashFilePath;
|
2015-06-09 18:58:19 +00:00
|
|
|
failedFile = op.file;
|
|
|
|
failedOperationType = Delete;
|
|
|
|
goto FAILED;
|
|
|
|
}
|
2015-06-08 00:43:16 +00:00
|
|
|
BackupEntry be;
|
|
|
|
be.orig = origFilePath;
|
|
|
|
be.backup = trashFilePath;
|
|
|
|
trashcan.append(be);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// try to start the new binary
|
2015-06-08 22:48:25 +00:00
|
|
|
args = qApp->arguments();
|
2015-06-08 00:43:16 +00:00
|
|
|
args.removeFirst();
|
2015-06-10 00:31:34 +00:00
|
|
|
|
|
|
|
// on old Windows, do insane things... no error checking here, this is just to have something.
|
|
|
|
if(useXPHack)
|
|
|
|
{
|
|
|
|
QString script;
|
|
|
|
auto nativePath = QDir::toNativeSeparators(exePath);
|
|
|
|
auto nativeOriginPath = QDir::toNativeSeparators(exeOrigin);
|
|
|
|
auto nativeBackupPath = QDir::toNativeSeparators(exeBackup);
|
|
|
|
|
|
|
|
// so we write this vbscript thing...
|
|
|
|
QTextStream out(&script);
|
|
|
|
out << "WScript.Sleep 1000\n";
|
|
|
|
out << "Set fso=CreateObject(\"Scripting.FileSystemObject\")\n";
|
|
|
|
out << "Set shell=CreateObject(\"WScript.Shell\")\n";
|
|
|
|
out << "fso.MoveFile \"" << nativePath << "\", \"" << nativeBackupPath << "\"\n";
|
|
|
|
out << "fso.MoveFile \"" << nativeOriginPath << "\", \"" << nativePath << "\"\n";
|
|
|
|
out << "shell.Run \"" << nativePath << "\"\n";
|
|
|
|
|
2015-10-04 23:47:27 +00:00
|
|
|
QString scriptPath = FS::PathCombine(root(), "update", "update.vbs");
|
2015-06-10 00:31:34 +00:00
|
|
|
|
|
|
|
// we save it
|
|
|
|
QFile scriptFile(scriptPath);
|
|
|
|
scriptFile.open(QIODevice::WriteOnly);
|
|
|
|
scriptFile.write(script.toLocal8Bit().replace("\n", "\r\n"));
|
|
|
|
scriptFile.close();
|
|
|
|
|
|
|
|
// we run it
|
|
|
|
started = QProcess::startDetached("wscript", {scriptPath}, root());
|
|
|
|
|
|
|
|
// and we quit. conscious thought.
|
|
|
|
qApp->quit();
|
|
|
|
return;
|
|
|
|
}
|
2015-06-08 22:48:25 +00:00
|
|
|
started = QProcess::startDetached(finishCmd, args, QDir::currentPath(), &pid);
|
2015-06-08 00:43:16 +00:00
|
|
|
// failed to start... ?
|
2015-06-08 22:48:25 +00:00
|
|
|
if(!started || pid == -1)
|
2015-06-08 00:43:16 +00:00
|
|
|
{
|
2015-06-08 22:48:25 +00:00
|
|
|
qWarning() << "Couldn't start new process properly!";
|
2015-06-09 18:58:19 +00:00
|
|
|
failedOperationType = Start;
|
2015-06-08 00:43:16 +00:00
|
|
|
goto FAILED;
|
|
|
|
}
|
2015-06-09 22:46:45 +00:00
|
|
|
origin.rmdir(updateFilesDir);
|
2015-06-08 00:43:16 +00:00
|
|
|
qApp->quit();
|
|
|
|
return;
|
|
|
|
|
|
|
|
FAILED:
|
2015-06-08 22:48:25 +00:00
|
|
|
qWarning() << "Update failed!";
|
2015-06-09 18:58:19 +00:00
|
|
|
bool revertOK = true;
|
2015-06-08 00:43:16 +00:00
|
|
|
// if the above failed, roll back changes
|
|
|
|
for(auto backup:backups)
|
|
|
|
{
|
2015-06-08 22:48:25 +00:00
|
|
|
qWarning() << "restoring" << backup.orig << "from" << backup.backup;
|
2015-06-09 18:58:19 +00:00
|
|
|
if(!QFile::remove(backup.orig))
|
|
|
|
{
|
|
|
|
revertOK = false;
|
|
|
|
qWarning() << "removing new" << backup.orig << "failed!";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!QFile::rename(backup.backup, backup.orig))
|
|
|
|
{
|
|
|
|
revertOK = false;
|
2015-06-09 21:23:46 +00:00
|
|
|
qWarning() << "restoring" << backup.orig << "failed!";
|
2015-06-09 18:58:19 +00:00
|
|
|
}
|
2015-06-08 00:43:16 +00:00
|
|
|
}
|
|
|
|
for(auto backup:trashcan)
|
|
|
|
{
|
2015-06-08 22:48:25 +00:00
|
|
|
qWarning() << "restoring" << backup.orig << "from" << backup.backup;
|
2015-06-09 21:23:46 +00:00
|
|
|
if(!QFile::rename(backup.backup, backup.orig))
|
|
|
|
{
|
|
|
|
revertOK = false;
|
|
|
|
qWarning() << "restoring" << backup.orig << "failed!";
|
|
|
|
}
|
2015-06-09 18:58:19 +00:00
|
|
|
}
|
|
|
|
QString msg;
|
|
|
|
if(!revertOK)
|
|
|
|
{
|
|
|
|
msg = tr("The update failed and then the update revert failed too.\n"
|
|
|
|
"You will have to repair MultiMC manually.\n"
|
|
|
|
"Please let us know why and how this happened.").arg(failedFile);
|
|
|
|
}
|
|
|
|
else switch (failedOperationType)
|
|
|
|
{
|
2015-06-09 21:23:46 +00:00
|
|
|
case Replace:
|
|
|
|
msg = tr("Couldn't replace file %1. Changes were reverted.\n"
|
|
|
|
"See the MultiMC log file for details.").arg(failedFile);
|
2015-06-09 18:58:19 +00:00
|
|
|
break;
|
|
|
|
case Delete:
|
2015-06-09 21:23:46 +00:00
|
|
|
msg = tr("Couldn't remove file %1. Changes were reverted.\n"
|
|
|
|
"See the MultiMC log file for details.").arg(failedFile);
|
2015-06-09 18:58:19 +00:00
|
|
|
break;
|
|
|
|
case Start:
|
|
|
|
msg = tr("The new version didn't start and the update was rolled back.");
|
|
|
|
break;
|
|
|
|
case Nothing:
|
|
|
|
default:
|
|
|
|
return;
|
2015-06-08 00:43:16 +00:00
|
|
|
}
|
2015-06-09 21:23:46 +00:00
|
|
|
QMessageBox::critical(nullptr, tr("Update failed!"), msg);
|
2013-12-06 18:59:58 +00:00
|
|
|
}
|
|
|
|
|
2016-10-21 07:07:26 +00:00
|
|
|
std::vector<ITheme *> MultiMC::getValidApplicationThemes()
|
|
|
|
{
|
|
|
|
std::vector<ITheme *> ret;
|
|
|
|
auto iter = m_themes.cbegin();
|
|
|
|
while (iter != m_themes.cend())
|
|
|
|
{
|
|
|
|
ret.push_back((*iter).second.get());
|
|
|
|
iter++;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MultiMC::initThemes()
|
|
|
|
{
|
|
|
|
auto insertTheme = [this](ITheme * theme)
|
|
|
|
{
|
|
|
|
m_themes.insert(std::make_pair(theme->id(), std::unique_ptr<ITheme>(theme)));
|
|
|
|
};
|
|
|
|
insertTheme(new SystemTheme());
|
|
|
|
insertTheme(new DarkTheme());
|
|
|
|
}
|
|
|
|
|
|
|
|
void MultiMC::setApplicationTheme(const QString& name)
|
|
|
|
{
|
|
|
|
auto systemPalette = qApp->palette();
|
|
|
|
auto themeIter = m_themes.find(name);
|
|
|
|
if(themeIter != m_themes.end())
|
|
|
|
{
|
|
|
|
auto & theme = (*themeIter).second;
|
2016-10-21 23:43:36 +00:00
|
|
|
setStyle(QStyleFactory::create(theme->qtTheme()));
|
2016-10-21 07:07:26 +00:00
|
|
|
setPalette(theme->colorScheme());
|
|
|
|
setStyleSheet(theme->appStyleSheet());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
qWarning() << "Tried to set invalid theme:" << name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-01 21:20:57 +00:00
|
|
|
void MultiMC::setIconTheme(const QString& name)
|
|
|
|
{
|
|
|
|
XdgIcon::setThemeName(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
QIcon MultiMC::getThemedIcon(const QString& name)
|
|
|
|
{
|
|
|
|
return XdgIcon::fromTheme(name);
|
|
|
|
}
|
|
|
|
|
2014-01-05 12:17:42 +00:00
|
|
|
void MultiMC::onExit()
|
2013-12-06 18:59:58 +00:00
|
|
|
{
|
2015-02-01 02:08:25 +00:00
|
|
|
if(m_instances)
|
|
|
|
{
|
2016-10-02 22:55:54 +00:00
|
|
|
// m_instances->saveGroupList();
|
2015-02-01 02:08:25 +00:00
|
|
|
}
|
2015-01-31 15:59:03 +00:00
|
|
|
ENV.destroy();
|
2015-02-02 01:14:14 +00:00
|
|
|
if(logFile)
|
|
|
|
{
|
|
|
|
logFile->flush();
|
|
|
|
logFile->close();
|
|
|
|
}
|
2013-12-06 18:59:58 +00:00
|
|
|
}
|
|
|
|
|
2013-12-30 13:45:59 +00:00
|
|
|
bool MultiMC::openJsonEditor(const QString &filename)
|
2013-12-29 16:51:16 +00:00
|
|
|
{
|
|
|
|
const QString file = QDir::current().absoluteFilePath(filename);
|
|
|
|
if (m_settings->get("JsonEditor").toString().isEmpty())
|
|
|
|
{
|
2016-01-05 06:32:52 +00:00
|
|
|
return DesktopServices::openUrl(QUrl::fromLocalFile(file));
|
2013-12-29 16:51:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-01-05 06:32:52 +00:00
|
|
|
//return DesktopServices::openFile(m_settings->get("JsonEditor").toString(), file);
|
2016-03-17 12:25:57 +00:00
|
|
|
return DesktopServices::run(m_settings->get("JsonEditor").toString(), {file});
|
2013-12-29 16:51:16 +00:00
|
|
|
}
|
|
|
|
}
|
2013-09-07 02:00:58 +00:00
|
|
|
|
2013-09-22 02:21:36 +00:00
|
|
|
#include "MultiMC.moc"
|