sneedmc/api/logic/minecraft/ftb/FTBInstanceProvider.cpp
2016-11-09 01:22:02 +01:00

273 lines
7.5 KiB
C++

#include "FTBInstanceProvider.h"
#include <QDir>
#include <QDebug>
#include <QXmlStreamReader>
#include <QRegularExpression>
#include <settings/INISettingsObject.h>
#include <FileSystem.h>
#include "Env.h"
#include "minecraft/MinecraftVersion.h"
#include "LegacyFTBInstance.h"
#include "OneSixFTBInstance.h"
inline uint qHash(FTBRecord record)
{
return qHash(record.instanceDir);
}
FTBInstanceProvider::FTBInstanceProvider(SettingsObjectPtr settings)
: BaseInstanceProvider(settings)
{
// nil
}
QList<InstanceId> FTBInstanceProvider::discoverInstances()
{
// nothing to load when we don't have
if (m_globalSettings->get("TrackFTBInstances").toBool() != true)
{
return {};
}
m_records.clear();
discoverFTBEntries();
return m_records.keys();
}
InstancePtr FTBInstanceProvider::loadInstance(const InstanceId& id)
{
// process the records we acquired.
auto iter = m_records.find(id);
if(iter == m_records.end())
{
qWarning() << "Cannot load instance" << id << "without a record";
return nullptr;
}
auto & record = m_records[id];
qDebug() << "Loading FTB instance from " << record.instanceDir;
QString iconKey = record.iconKey;
auto icons = ENV.icons();
if(icons)
{
icons->addIcon(iconKey, iconKey, FS::PathCombine(record.templateDir, record.logo), IconType::Transient);
}
auto settingsFilePath = FS::PathCombine(record.instanceDir, "instance.cfg");
qDebug() << "ICON get!";
if (QFileInfo(settingsFilePath).exists())
{
auto instPtr = loadInstance(record);
if (!instPtr)
{
qWarning() << "Couldn't load instance config:" << settingsFilePath;
if(!QFile::remove(settingsFilePath))
{
qWarning() << "Couldn't remove broken instance config!";
return nullptr;
}
// failed to load, but removed the poisonous file
}
else
{
return InstancePtr(instPtr);
}
}
auto instPtr = createInstance(record);
if (!instPtr)
{
qWarning() << "Couldn't create FTB instance!";
return nullptr;
}
return InstancePtr(instPtr);
}
void FTBInstanceProvider::discoverFTBEntries()
{
QDir dir = QDir(m_globalSettings->get("FTBLauncherLocal").toString());
QDir dataDir = QDir(m_globalSettings->get("FTBRoot").toString());
if (!dataDir.exists())
{
qDebug() << "The FTB directory specified does not exist. Please check your settings";
return;
}
else if (!dir.exists())
{
qDebug() << "The FTB launcher data directory specified does not exist. Please check "
"your settings";
return;
}
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();
QString logo = record.logo;
record.iconKey = logo.remove(QRegularExpression("\\..*"));
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();
auto id = "FTB/" + record.dirName;
m_records[id] = record;
}
break;
}
case QXmlStreamReader::EndElement:
break;
case QXmlStreamReader::Characters:
break;
default:
break;
}
}
f.close();
}
}
InstancePtr FTBInstanceProvider::loadInstance(const FTBRecord & record) const
{
InstancePtr inst;
auto m_settings = std::make_shared<INISettingsObject>(FS::PathCombine(record.instanceDir, "instance.cfg"));
m_settings->registerSetting("InstanceType", "Legacy");
qDebug() << "Loading existing " << record.name;
QString inst_type = m_settings->get("InstanceType").toString();
if (inst_type == "LegacyFTB")
{
inst.reset(new LegacyFTBInstance(m_globalSettings, m_settings, record.instanceDir));
}
else if (inst_type == "OneSixFTB")
{
inst.reset(new OneSixFTBInstance(m_globalSettings, m_settings, record.instanceDir));
}
else
{
return nullptr;
}
qDebug() << "Construction " << record.instanceDir;
SettingsObject::Lock lock(inst->settings());
inst->init();
qDebug() << "Init " << record.instanceDir;
inst->setGroupInitial("FTB");
/**
* FIXME: this does not respect the user's preferences. BUT, it would work nicely with the planned pack support
* -> instead of changing the user values, change pack values (defaults you can look at and revert to)
*/
/*
inst->setName(record.name);
inst->setIconKey(record.iconKey);
inst->setNotes(record.description);
*/
if (inst->intendedVersionId() != record.mcVersion)
{
inst->setIntendedVersionId(record.mcVersion);
}
qDebug() << "Loaded instance " << inst->name() << " from " << inst->instanceRoot();
return inst;
}
InstancePtr FTBInstanceProvider::createInstance(const FTBRecord & record) const
{
QDir rootDir(record.instanceDir);
InstancePtr inst;
qDebug() << "Converting " << record.name << " as new.";
if (!rootDir.exists() && !rootDir.mkpath("."))
{
qCritical() << "Can't create instance folder" << record.instanceDir;
return nullptr;
}
auto m_settings = std::make_shared<INISettingsObject>(FS::PathCombine(record.instanceDir, "instance.cfg"));
m_settings->registerSetting("InstanceType", "Legacy");
// all legacy versions are built in. therefore we can do this even if we don't have ALL the versions Mojang has on their servers.
auto mcVersion = std::dynamic_pointer_cast<MinecraftVersion>(ENV.getVersion("net.minecraft", record.mcVersion));
if (mcVersion && mcVersion->usesLegacyLauncher())
{
m_settings->set("InstanceType", "LegacyFTB");
inst.reset(new LegacyFTBInstance(m_globalSettings, m_settings, record.instanceDir));
}
else
{
m_settings->set("InstanceType", "OneSixFTB");
inst.reset(new OneSixFTBInstance(m_globalSettings, m_settings, record.instanceDir));
}
// initialize
{
SettingsObject::Lock lock(inst->settings());
inst->setIntendedVersionId(record.mcVersion);
inst->init();
inst->setGroupInitial("FTB");
inst->setName(record.name);
inst->setIconKey(record.iconKey);
inst->setNotes(record.description);
}
return inst;
}