MultiMC5/logic/ftb/FTBPlugin.cpp

361 lines
9.9 KiB
C++

#include "FTBPlugin.h"
#include "FTBVersion.h"
#include "LegacyFTBInstance.h"
#include "OneSixFTBInstance.h"
#include <logic/BaseInstance.h>
#include <logic/icons/IconList.h>
#include <logic/InstanceList.h>
#include <logic/minecraft/MinecraftVersionList.h>
#include <logic/settings/INISettingsObject.h>
#include "MultiMC.h"
#include <pathutils.h>
#include "QDebug"
#include <QXmlStreamReader>
#include <QRegularExpression>
struct FTBRecord
{
QString dirName;
QString name;
QString logo;
QString mcVersion;
QString description;
QString instanceDir;
QString templateDir;
bool operator==(const FTBRecord other) const
{
return instanceDir == other.instanceDir;
}
};
inline uint qHash(FTBRecord record)
{
return qHash(record.instanceDir);
}
QSet<FTBRecord> discoverFTBInstances()
{
QSet<FTBRecord> records;
QDir dir = QDir(MMC->settings()->get("FTBLauncherDataRoot").toString());
QDir dataDir = QDir(MMC->settings()->get("FTBRoot").toString());
if (!dataDir.exists())
{
qDebug() << "The FTB directory specified does not exist. Please check your settings";
return records;
}
else if (!dir.exists())
{
qDebug() << "The FTB launcher data directory specified does not exist. Please check "
"your settings";
return records;
}
dir.cd("ModPacks");
auto allFiles = dir.entryList(QDir::Readable | QDir::Files, QDir::Name);
for (auto filename : allFiles)
{
if (!filename.endsWith(".xml"))
continue;
auto fpath = dir.absoluteFilePath(filename);
QFile f(fpath);
qDebug() << "Discovering FTB instances -- " << fpath;
if (!f.open(QFile::ReadOnly))
continue;
// 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.dirName = attrs.value("dir").toString();
record.instanceDir = dataDir.absoluteFilePath(record.dirName);
record.templateDir = dir.absoluteFilePath(record.dirName);
QDir test(record.instanceDir);
qDebug() << dataDir.absolutePath() << record.instanceDir << record.dirName;
if (!test.exists())
continue;
record.name = attrs.value("name").toString();
record.logo = attrs.value("logo").toString();
auto customVersions = attrs.value("customMCVersions");
if (!customVersions.isNull())
{
QMap<QString, QString> versionMatcher;
QString customVersionsStr = customVersions.toString();
QStringList list = customVersionsStr.split(';');
for (auto item : list)
{
auto segment = item.split('^');
if (segment.size() != 2)
{
qCritical() << "FTB: Segment of size < 2 in "
<< customVersionsStr;
continue;
}
versionMatcher[segment[0]] = segment[1];
}
auto actualVersion = attrs.value("version").toString();
if (versionMatcher.contains(actualVersion))
{
record.mcVersion = versionMatcher[actualVersion];
}
else
{
record.mcVersion = attrs.value("mcVersion").toString();
}
}
else
{
record.mcVersion = attrs.value("mcVersion").toString();
}
record.description = attrs.value("description").toString();
records.insert(record);
}
break;
}
case QXmlStreamReader::EndElement:
break;
case QXmlStreamReader::Characters:
break;
default:
break;
}
}
f.close();
}
return records;
}
InstancePtr loadInstance(const QString &instDir)
{
auto m_settings = std::make_shared<INISettingsObject>(PathCombine(instDir, "instance.cfg"));
InstancePtr inst;
m_settings->registerSetting("InstanceType", "Legacy");
QString inst_type = m_settings->get("InstanceType").toString();
if (inst_type == "LegacyFTB")
{
inst.reset(new LegacyFTBInstance(MMC->settings(), m_settings, instDir));
}
else if (inst_type == "OneSixFTB")
{
inst.reset(new OneSixFTBInstance(MMC->settings(), m_settings, instDir));
}
inst->init();
return inst;
}
InstancePtr createInstance(MinecraftVersionPtr version, const QString &instDir)
{
QDir rootDir(instDir);
InstancePtr inst;
if (!version)
{
qCritical() << "Can't create instance for non-existing MC version";
return nullptr;
}
qDebug() << instDir.toUtf8();
if (!rootDir.exists() && !rootDir.mkpath("."))
{
qCritical() << "Can't create instance folder" << instDir;
return nullptr;
}
auto m_settings = std::make_shared<INISettingsObject>(PathCombine(instDir, "instance.cfg"));
m_settings->registerSetting("InstanceType", "Legacy");
if (version->usesLegacyLauncher())
{
m_settings->set("InstanceType", "LegacyFTB");
inst.reset(new LegacyFTBInstance(MMC->settings(),m_settings, instDir));
inst->setIntendedVersionId(version->descriptor());
}
else
{
m_settings->set("InstanceType", "OneSixFTB");
inst.reset(new OneSixFTBInstance(MMC->settings(),m_settings, instDir));
inst->setIntendedVersionId(version->descriptor());
inst->init();
}
return inst;
}
void FTBPlugin::loadInstances(QMap<QString, QString> &groupMap, QList<InstancePtr> &tempList)
{
// nothing to load when we don't have
if (MMC->settings()->get("TrackFTBInstances").toBool() != true)
{
return;
}
auto records = discoverFTBInstances();
if (!records.size())
{
qDebug() << "No FTB instances to load.";
return;
}
qDebug() << "Loading FTB instances! -- got " << records.size();
// process the records we acquired.
for (auto record : records)
{
qDebug() << "Loading FTB instance from " << record.instanceDir;
QString iconKey = record.logo;
iconKey.remove(QRegularExpression("\\..*"));
ENV.icons()->addIcon(iconKey, iconKey, PathCombine(record.templateDir, record.logo),
MMCIcon::Transient);
if (!QFileInfo(PathCombine(record.instanceDir, "instance.cfg")).exists())
{
qDebug() << "Converting " << record.name << " as new.";
auto mcVersion = std::dynamic_pointer_cast<MinecraftVersion>(MMC->minecraftlist()->findVersion(record.mcVersion));
if (!mcVersion)
{
qCritical() << "Can't load instance " << record.instanceDir
<< " because minecraft version " << record.mcVersion
<< " can't be resolved.";
continue;
}
auto instPtr = createInstance(mcVersion, record.instanceDir);
if (!instPtr)
{
continue;
}
instPtr->setGroupInitial("FTB");
instPtr->setName(record.name);
instPtr->setIconKey(iconKey);
instPtr->setIntendedVersionId(record.mcVersion);
instPtr->setNotes(record.description);
if (!InstanceList::continueProcessInstance(instPtr, InstanceList::NoCreateError, record.instanceDir, groupMap))
continue;
tempList.append(InstancePtr(instPtr));
}
else
{
qDebug() << "Loading existing " << record.name;
auto instPtr = loadInstance(record.instanceDir);
if (!instPtr)
{
continue;
}
instPtr->setGroupInitial("FTB");
instPtr->setName(record.name);
instPtr->setIconKey(iconKey);
if (instPtr->intendedVersionId() != record.mcVersion)
{
instPtr->setIntendedVersionId(record.mcVersion);
}
instPtr->setNotes(record.description);
if (!InstanceList::continueProcessInstance(instPtr, InstanceList::NoCreateError, record.instanceDir, groupMap))
continue;
tempList.append(InstancePtr(instPtr));
}
}
}
#ifdef Q_OS_WIN32
#include <windows.h>
static const int APPDATA_BUFFER_SIZE = 1024;
#endif
void FTBPlugin::initialize()
{
auto m_settings = MMC->settings();
// FTB
m_settings->registerSetting("TrackFTBInstances", false);
QString ftbDataDefault;
#ifdef Q_OS_LINUX
QString ftbDefault = ftbDataDefault = QDir::home().absoluteFilePath(".ftblauncher");
#elif defined(Q_OS_WIN32)
wchar_t buf[APPDATA_BUFFER_SIZE];
wchar_t newBuf[APPDATA_BUFFER_SIZE];
QString ftbDefault, newFtbDefault, oldFtbDefault;
if (!GetEnvironmentVariableW(L"LOCALAPPDATA", newBuf, APPDATA_BUFFER_SIZE))
{
qCritical() << "Your LOCALAPPDATA folder is missing! If you are on windows, this means "
"your system is broken.";
}
else
{
newFtbDefault = QDir(QString::fromWCharArray(newBuf)).absoluteFilePath("ftblauncher");
}
if (!GetEnvironmentVariableW(L"APPDATA", buf, APPDATA_BUFFER_SIZE))
{
qCritical() << "Your APPDATA folder is missing! If you are on windows, this means your "
"system is broken.";
}
else
{
oldFtbDefault = QDir(QString::fromWCharArray(buf)).absoluteFilePath("ftblauncher");
}
if (QFile::exists(QDir(newFtbDefault).absoluteFilePath("ftblaunch.cfg")))
{
qDebug() << "Old FTB setup";
ftbDefault = ftbDataDefault = oldFtbDefault;
}
else
{
qDebug() << "New FTB setup";
ftbDefault = oldFtbDefault;
ftbDataDefault = newFtbDefault;
}
#elif defined(Q_OS_MAC)
QString ftbDefault = ftbDataDefault =
PathCombine(QDir::homePath(), "Library/Application Support/ftblauncher");
#endif
m_settings->registerSetting("FTBLauncherDataRoot", ftbDataDefault);
m_settings->registerSetting("FTBLauncherRoot", ftbDefault);
qDebug() << "FTB Launcher paths:" << m_settings->get("FTBLauncherDataRoot").toString()
<< "and" << m_settings->get("FTBLauncherRoot").toString();
m_settings->registerSetting("FTBRoot");
if (m_settings->get("FTBRoot").isNull())
{
QString ftbRoot;
QFile f(QDir(m_settings->get("FTBLauncherRoot").toString())
.absoluteFilePath("ftblaunch.cfg"));
qDebug() << "Attempting to read" << f.fileName();
if (f.open(QFile::ReadOnly))
{
const QString data = QString::fromLatin1(f.readAll());
QRegularExpression exp("installPath=(.*)");
ftbRoot = QDir::cleanPath(exp.match(data).captured(1));
#ifdef Q_OS_WIN32
if (!ftbRoot.isEmpty())
{
if (ftbRoot.at(0).isLetter() && ftbRoot.size() > 1 && ftbRoot.at(1) == '/')
{
ftbRoot.remove(1, 1);
}
}
#endif
if (ftbRoot.isEmpty())
{
qDebug() << "Failed to get FTB root path";
}
else
{
qDebug() << "FTB is installed at" << ftbRoot;
m_settings->set("FTBRoot", ftbRoot);
}
}
else
{
qWarning() << "Couldn't open" << f.fileName() << ":" << f.errorString();
qWarning() << "This is perfectly normal if you don't have FTB installed";
}
}
}