Make FTB instances behave better

* Do not re-create on every reload
* Use the version.json/custom.json logic properly
* Should be offline-friendly
* FTB instances can be copied, turn into normal instances
This commit is contained in:
Petr Mrázek 2013-12-22 04:31:30 +01:00
parent 82c87aa06f
commit 74b5b5f535
5 changed files with 214 additions and 131 deletions

View File

@ -34,8 +34,9 @@
#include "config.h" #include "config.h"
using namespace Util::Commandline; using namespace Util::Commandline;
MultiMC::MultiMC(int &argc, char **argv, const QString &root) : QApplication(argc, argv), MultiMC::MultiMC(int &argc, char **argv, const QString &root)
m_version{VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD, VERSION_CHANNEL, VERSION_BUILD_TYPE} : QApplication(argc, argv), m_version{VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD,
VERSION_CHANNEL, VERSION_BUILD_TYPE}
{ {
setOrganizationName("MultiMC"); setOrganizationName("MultiMC");
setApplicationName("MultiMC5"); setApplicationName("MultiMC5");
@ -135,9 +136,10 @@ MultiMC::MultiMC(int &argc, char **argv, const QString &root) : QApplication(arg
} }
// change directory // change directory
QDir::setCurrent(args["dir"].toString().isEmpty() ? QDir::setCurrent(
(root.isEmpty() ? QDir::currentPath() : QDir::current().absoluteFilePath(root)) args["dir"].toString().isEmpty()
: args["dir"].toString()); ? (root.isEmpty() ? QDir::currentPath() : QDir::current().absoluteFilePath(root))
: args["dir"].toString());
// init the logger // init the logger
initLogger(); initLogger();
@ -174,42 +176,43 @@ MultiMC::MultiMC(int &argc, char **argv, const QString &root) : QApplication(arg
{ {
QLOG_INFO() << "No proxy found."; QLOG_INFO() << "No proxy found.";
} }
else for (auto proxy : proxies) else
{ for (auto proxy : proxies)
QString proxyDesc;
if (proxy.type() == QNetworkProxy::NoProxy)
{ {
QLOG_INFO() << "Using no proxy is an option!"; QString proxyDesc;
continue; if (proxy.type() == QNetworkProxy::NoProxy)
{
QLOG_INFO() << "Using no proxy is an option!";
continue;
}
switch (proxy.type())
{
case QNetworkProxy::DefaultProxy:
proxyDesc = "Default proxy: ";
break;
case QNetworkProxy::Socks5Proxy:
proxyDesc = "Socks5 proxy: ";
break;
case QNetworkProxy::HttpProxy:
proxyDesc = "HTTP proxy: ";
break;
case QNetworkProxy::HttpCachingProxy:
proxyDesc = "HTTP caching: ";
break;
case QNetworkProxy::FtpCachingProxy:
proxyDesc = "FTP caching: ";
break;
default:
proxyDesc = "DERP proxy: ";
break;
}
proxyDesc += QString("%3@%1:%2 pass %4")
.arg(proxy.hostName())
.arg(proxy.port())
.arg(proxy.user())
.arg(proxy.password());
QLOG_INFO() << proxyDesc;
} }
switch (proxy.type())
{
case QNetworkProxy::DefaultProxy:
proxyDesc = "Default proxy: ";
break;
case QNetworkProxy::Socks5Proxy:
proxyDesc = "Socks5 proxy: ";
break;
case QNetworkProxy::HttpProxy:
proxyDesc = "HTTP proxy: ";
break;
case QNetworkProxy::HttpCachingProxy:
proxyDesc = "HTTP caching: ";
break;
case QNetworkProxy::FtpCachingProxy:
proxyDesc = "FTP caching: ";
break;
default:
proxyDesc = "DERP proxy: ";
break;
}
proxyDesc += QString("%3@%1:%2 pass %4")
.arg(proxy.hostName())
.arg(proxy.port())
.arg(proxy.user())
.arg(proxy.password());
QLOG_INFO() << proxyDesc;
}
// create the global network manager // create the global network manager
m_qnam.reset(new QNetworkAccessManager(this)); m_qnam.reset(new QNetworkAccessManager(this));
@ -315,21 +318,23 @@ void MultiMC::initGlobalSettings()
// FTB // FTB
m_settings->registerSetting(new Setting("TrackFTBInstances", false)); m_settings->registerSetting(new Setting("TrackFTBInstances", false));
m_settings->registerSetting(new Setting("FTBLauncherRoot", m_settings->registerSetting(new Setting(
#ifdef Q_OS_LINUX "FTBLauncherRoot",
QDir::home().absoluteFilePath(".ftblauncher") #ifdef Q_OS_LINUX
#elif defined(Q_OS_WIN32) QDir::home().absoluteFilePath(".ftblauncher")
PathCombine(QDir::homePath(), "AppData/Roaming/ftblauncher") #elif defined(Q_OS_WIN32)
#elif defined(Q_OS_MAC) PathCombine(QDir::homePath(), "AppData/Roaming/ftblauncher")
PathCombine(QDir::homePath(), "Library/Application Support/ftblauncher") #elif defined(Q_OS_MAC)
#endif PathCombine(QDir::homePath(), "Library/Application Support/ftblauncher")
)); #endif
));
m_settings->registerSetting(new Setting("FTBRoot")); m_settings->registerSetting(new Setting("FTBRoot"));
if (m_settings->get("FTBRoot").isNull()) if (m_settings->get("FTBRoot").isNull())
{ {
QString ftbRoot; QString ftbRoot;
QFile f(QDir(m_settings->get("FTBLauncherRoot").toString()).absoluteFilePath("ftblaunch.cfg")); QFile f(QDir(m_settings->get("FTBLauncherRoot").toString())
.absoluteFilePath("ftblaunch.cfg"));
QLOG_INFO() << "Attempting to read" << f.fileName(); QLOG_INFO() << "Attempting to read" << f.fileName();
if (f.open(QFile::ReadOnly)) if (f.open(QFile::ReadOnly))
{ {
@ -398,7 +403,6 @@ void MultiMC::initGlobalSettings()
// The cat // The cat
m_settings->registerSetting(new Setting("TheCat", false)); m_settings->registerSetting(new Setting("TheCat", false));
m_settings->registerSetting(new Setting("InstSortMode", "Name")); m_settings->registerSetting(new Setting("InstSortMode", "Name"));
m_settings->registerSetting(new Setting("SelectedInstance", QString())); m_settings->registerSetting(new Setting("SelectedInstance", QString()));
@ -486,17 +490,20 @@ std::shared_ptr<JavaVersionList> MultiMC::javalist()
#error Unsupported operating system. #error Unsupported operating system.
#endif #endif
void MultiMC::installUpdates(const QString& updateFilesDir, bool restartOnFinish) void MultiMC::installUpdates(const QString &updateFilesDir, bool restartOnFinish)
{ {
QLOG_INFO() << "Installing updates."; QLOG_INFO() << "Installing updates.";
#if LINUX #if LINUX
// On Linux, the MultiMC executable file is actually in the bin folder inside the installation directory. // On Linux, the MultiMC executable file is actually in the bin folder inside the
// installation directory.
// This means that MultiMC's *actual* install path is the parent folder. // This means that MultiMC's *actual* install path is the parent folder.
// We need to tell the updater to run with this directory as the install path, rather than the bin folder where the executable is. // We need to tell the updater to run with this directory as the install path, rather than
// the bin folder where the executable is.
// On other operating systems, we'll just use the path to the executable. // On other operating systems, we'll just use the path to the executable.
QString appDir = QFileInfo(MMC->applicationDirPath()).dir().path(); QString appDir = QFileInfo(MMC->applicationDirPath()).dir().path();
// On Linux, we also need to set the finish command to the launch script, rather than the binary. // On Linux, we also need to set the finish command to the launch script, rather than the
// binary.
QString finishCmd = PathCombine(appDir, "MultiMC"); QString finishCmd = PathCombine(appDir, "MultiMC");
#else #else
QString appDir = MMC->applicationDirPath(); QString appDir = MMC->applicationDirPath();
@ -504,18 +511,20 @@ void MultiMC::installUpdates(const QString& updateFilesDir, bool restartOnFinish
#endif #endif
// Build the command we'll use to run the updater. // Build the command we'll use to run the updater.
// Note, the above comment about the app dir path on Linux is irrelevant here because the updater binary is always in the // Note, the above comment about the app dir path on Linux is irrelevant here because the
// updater binary is always in the
// same folder as the main binary. // same folder as the main binary.
QString updaterBinary = PathCombine(MMC->applicationDirPath(), UPDATER_BIN); QString updaterBinary = PathCombine(MMC->applicationDirPath(), UPDATER_BIN);
QStringList args; QStringList args;
// ./updater --install-dir $INSTALL_DIR --package-dir $UPDATEFILES_DIR --script $UPDATEFILES_DIR/file_list.xml --wait $PID --mode main // ./updater --install-dir $INSTALL_DIR --package-dir $UPDATEFILES_DIR --script
// $UPDATEFILES_DIR/file_list.xml --wait $PID --mode main
args << "--install-dir" << appDir; args << "--install-dir" << appDir;
args << "--package-dir" << updateFilesDir; args << "--package-dir" << updateFilesDir;
args << "--script" << PathCombine(updateFilesDir, "file_list.xml"); args << "--script" << PathCombine(updateFilesDir, "file_list.xml");
args << "--wait" << QString::number(MMC->applicationPid()); args << "--wait" << QString::number(MMC->applicationPid());
if (restartOnFinish) if (restartOnFinish)
args << "--finish-cmd" << finishCmd; args << "--finish-cmd" << finishCmd;
QLOG_INFO() << "Running updater with command" << updaterBinary << args.join(" "); QLOG_INFO() << "Running updater with command" << updaterBinary << args.join(" ");
@ -525,7 +534,7 @@ void MultiMC::installUpdates(const QString& updateFilesDir, bool restartOnFinish
MMC->quit(); MMC->quit();
} }
void MultiMC::setUpdateOnExit(const QString& updateFilesDir) void MultiMC::setUpdateOnExit(const QString &updateFilesDir)
{ {
m_updateOnExitPath = updateFilesDir; m_updateOnExitPath = updateFilesDir;
} }
@ -535,5 +544,4 @@ QString MultiMC::getExitUpdatePath() const
return m_updateOnExitPath; return m_updateOnExitPath;
} }
#include "MultiMC.moc" #include "MultiMC.moc"

View File

@ -170,7 +170,17 @@ InstanceFactory::InstCreateError InstanceFactory::copyInstance(BaseInstance *&ne
rootDir.removeRecursively(); rootDir.removeRecursively();
return InstanceFactory::CantCreateDir; return InstanceFactory::CantCreateDir;
} }
auto m_settings = new INISettingsObject(PathCombine(instDir, "instance.cfg"));
m_settings->registerSetting(new Setting("InstanceType", "Legacy"));
QString inst_type = m_settings->get("InstanceType").toString();
if(inst_type == "OneSixFTB")
m_settings->set("InstanceType", "OneSix");
if(inst_type == "LegacyFTB")
m_settings->set("InstanceType", "Legacy");
auto error = loadInstance(newInstance, instDir); auto error = loadInstance(newInstance, instDir);
switch (error) switch (error)
{ {
case NoLoadError: case NoLoadError:

View File

@ -57,7 +57,10 @@ slots:
emitFailed(tr("Couldn't load the version config")); emitFailed(tr("Couldn't load the version config"));
return; return;
} }
if (!forge.apply(instance->getFullVersion())) instance->revertCustomVersion();
instance->customizeVersion();
auto version = instance->getFullVersion();
if (!forge.apply(version))
{ {
emitFailed(tr("Couldn't install Forge")); emitFailed(tr("Couldn't install Forge"));
return; return;

View File

@ -46,7 +46,8 @@ InstanceList::InstanceList(const QString &instDir, QObject *parent)
QDir::current().mkpath(m_instDir); QDir::current().mkpath(m_instDir);
} }
connect(MMC->minecraftlist().get(), &MinecraftVersionList::modelReset, this, &InstanceList::loadList); connect(MMC->minecraftlist().get(), &MinecraftVersionList::modelReset, this,
&InstanceList::loadList);
} }
InstanceList::~InstanceList() InstanceList::~InstanceList()
@ -281,6 +282,124 @@ void InstanceList::loadGroupList(QMap<QString, QString> &groupMap)
} }
} }
struct FTBRecord
{
QString dir;
QString name;
QString logo;
QString mcVersion;
QString description;
};
void InstanceList::loadForgeInstances(QMap<QString, QString> groupMap)
{
QList<FTBRecord> records;
QDir dir = QDir(MMC->settings()->get("FTBLauncherRoot").toString());
QDir dataDir = QDir(MMC->settings()->get("FTBRoot").toString());
if (!dir.exists())
{
QLOG_INFO() << "The FTB launcher directory specified does not exist. Please check your "
"settings.";
return;
}
else if (!dataDir.exists())
{
QLOG_INFO() << "The FTB directory specified does not exist. Please check your settings";
return;
}
dir.cd("ModPacks");
QFile f(dir.absoluteFilePath("modpacks.xml"));
if (!f.open(QFile::ReadOnly))
return;
// read the FTB packs XML.
QXmlStreamReader reader(&f);
while (!reader.atEnd())
{
switch (reader.readNext())
{
case QXmlStreamReader::StartElement:
{
if (reader.name() == "modpack")
{
QXmlStreamAttributes attrs = reader.attributes();
FTBRecord record;
record.dir = attrs.value("dir").toString();
record.name = attrs.value("name").toString();
record.logo = attrs.value("logo").toString();
record.mcVersion = attrs.value("mcVersion").toString();
record.description = attrs.value("description").toString();
records.append(record);
}
break;
}
case QXmlStreamReader::EndElement:
break;
case QXmlStreamReader::Characters:
break;
default:
break;
}
}
f.close();
// process the records we acquired.
for (auto record : records)
{
auto instanceDir = dataDir.absoluteFilePath(record.dir);
auto templateDir = dir.absoluteFilePath(record.dir);
if (!QFileInfo(instanceDir).exists())
{
continue;
}
QString iconKey = record.logo;
iconKey.remove(QRegularExpression("\\..*"));
MMC->icons()->addIcon(iconKey, iconKey, PathCombine(templateDir, record.logo), true);
if (!QFileInfo(PathCombine(instanceDir, "instance.cfg")).exists())
{
BaseInstance *instPtr = NULL;
auto & factory = InstanceFactory::get();
auto version = MMC->minecraftlist()->findVersion(record.mcVersion);
if (!version)
{
QLOG_ERROR() << "Can't load instance " << instanceDir
<< " because minecraft version " << record.mcVersion
<< " can't be resolved.";
continue;
}
auto error = factory.createInstance(instPtr, version, instanceDir,
InstanceFactory::FTBInstance);
if (!instPtr || error != InstanceFactory::NoCreateError)
continue;
instPtr->setGroupInitial("FTB");
instPtr->setName(record.name);
instPtr->setIconKey(iconKey);
instPtr->setIntendedVersionId(record.mcVersion);
instPtr->setNotes(record.description);
continueProcessInstance(instPtr, error, instanceDir, groupMap);
}
else
{
BaseInstance *instPtr = NULL;
auto error = InstanceFactory::get().loadInstance(instPtr, instanceDir);
if (!instPtr || error != InstanceFactory::NoCreateError)
continue;
instPtr->setGroupInitial("FTB");
instPtr->setName(record.name);
instPtr->setIconKey(iconKey);
if (instPtr->intendedVersionId() != record.mcVersion)
instPtr->setIntendedVersionId(record.mcVersion);
instPtr->setNotes(record.description);
continueProcessInstance(instPtr, error, instanceDir, groupMap);
}
}
}
InstanceList::InstListError InstanceList::loadList() InstanceList::InstListError InstanceList::loadList()
{ {
// load the instance groups // load the instance groups
@ -306,69 +425,9 @@ InstanceList::InstListError InstanceList::loadList()
} }
} }
if (MMC->settings()->get("TrackFTBInstances").toBool() && MMC->minecraftlist()->isLoaded()) if (MMC->settings()->get("TrackFTBInstances").toBool())
{ {
QDir dir = QDir(MMC->settings()->get("FTBLauncherRoot").toString()); loadForgeInstances(groupMap);
QDir dataDir = QDir(MMC->settings()->get("FTBRoot").toString());
if (!dir.exists())
{
QLOG_INFO() << "The FTB launcher directory specified does not exist. Please check your settings.";
}
else if (!dataDir.exists())
{
QLOG_INFO() << "The FTB directory specified does not exist. Please check your settings";
}
else
{
dir.cd("ModPacks");
QFile f(dir.absoluteFilePath("modpacks.xml"));
if (f.open(QFile::ReadOnly))
{
QXmlStreamReader reader(&f);
while (!reader.atEnd())
{
switch (reader.readNext())
{
case QXmlStreamReader::StartElement:
{
if (reader.name() == "modpack")
{
QXmlStreamAttributes attrs = reader.attributes();
const QDir instanceDir = QDir(dataDir.absoluteFilePath(attrs.value("dir").toString()));
if (instanceDir.exists())
{
const QString name = attrs.value("name").toString();
const QString iconKey = attrs.value("logo").toString().remove(QRegularExpression("\\..*"));
const QString mcVersion = attrs.value("mcVersion").toString();
const QString notes = attrs.value("description").toString();
QLOG_DEBUG() << dir.absoluteFilePath(attrs.value("logo").toString());
MMC->icons()->addIcon(iconKey, iconKey, dir.absoluteFilePath(attrs.value("dir").toString() + QDir::separator() + attrs.value("logo").toString()), true);
BaseInstance *instPtr = NULL;
auto error = InstanceFactory::get().createInstance(instPtr, MMC->minecraftlist()->findVersion(mcVersion), instanceDir.absolutePath(), InstanceFactory::FTBInstance);
if (instPtr && error == InstanceFactory::NoCreateError)
{
instPtr->setGroupInitial("FTB");
instPtr->setName(name);
instPtr->setIconKey(iconKey);
instPtr->setIntendedVersionId(mcVersion);
instPtr->setNotes(notes);
}
continueProcessInstance(instPtr, error, instanceDir, groupMap);
}
}
break;
}
case QXmlStreamReader::EndElement:
break;
case QXmlStreamReader::Characters:
break;
default:
break;
}
}
}
}
} }
endResetModel(); endResetModel();
@ -444,13 +503,14 @@ int InstanceList::getInstIndex(BaseInstance *inst) const
return -1; return -1;
} }
void InstanceList::continueProcessInstance(BaseInstance *instPtr, const int error, const QDir &dir, QMap<QString, QString> &groupMap) void InstanceList::continueProcessInstance(BaseInstance *instPtr, const int error,
const QDir &dir, QMap<QString, QString> &groupMap)
{ {
if (error != InstanceFactory::NoLoadError && error != InstanceFactory::NotAnInstance) if (error != InstanceFactory::NoLoadError && error != InstanceFactory::NotAnInstance)
{ {
QString errorMsg = QString("Failed to load instance %1: ") QString errorMsg = QString("Failed to load instance %1: ")
.arg(QFileInfo(dir.absolutePath()).baseName()) .arg(QFileInfo(dir.absolutePath()).baseName())
.toUtf8(); .toUtf8();
switch (error) switch (error)
{ {
@ -463,8 +523,8 @@ void InstanceList::continueProcessInstance(BaseInstance *instPtr, const int erro
else if (!instPtr) else if (!instPtr)
{ {
QLOG_ERROR() << QString("Error loading instance %1. Instance loader returned null.") QLOG_ERROR() << QString("Error loading instance %1. Instance loader returned null.")
.arg(QFileInfo(dir.absolutePath()).baseName()) .arg(QFileInfo(dir.absolutePath()).baseName())
.toUtf8(); .toUtf8();
} }
else else
{ {

View File

@ -109,6 +109,7 @@ slots:
* \brief Loads the instance list. Triggers notifications. * \brief Loads the instance list. Triggers notifications.
*/ */
InstListError loadList(); InstListError loadList();
void loadForgeInstances(QMap<QString, QString> groupMap);
private private
slots: slots:
@ -119,7 +120,8 @@ slots:
private: private:
int getInstIndex(BaseInstance *inst) const; int getInstIndex(BaseInstance *inst) const;
void continueProcessInstance(BaseInstance *instPtr, const int error, const QDir &dir, QMap<QString, QString> &groupMap); void continueProcessInstance(BaseInstance *instPtr, const int error, const QDir &dir,
QMap<QString, QString> &groupMap);
protected: protected:
QString m_instDir; QString m_instDir;