NOISSUE significantly more reliable detection of modloaders for FTBA

This commit is contained in:
Petr Mrázek 2022-05-30 01:38:19 +02:00
parent 66c6e6e05d
commit 214d615d18
3 changed files with 135 additions and 18 deletions

View File

@ -19,6 +19,7 @@
#include <BuildConfig.h> #include <BuildConfig.h>
#include <FileSystem.h> #include <FileSystem.h>
#include <Json.h> #include <Json.h>
#include <minecraft/GradleSpecifier.h>
#if defined(Q_OS_WIN32) #if defined(Q_OS_WIN32)
#include <windows.h> #include <windows.h>
@ -71,26 +72,34 @@ QVariant Model::data(const QModelIndex &index, int role) const
namespace { namespace {
#if defined (Q_OS_OSX) #if defined (Q_OS_OSX)
QString getFTBASettingsPath() { QString getFTBAPath() {
return FS::PathCombine(QDir::homePath(), "Library/Application Support/.ftba/bin/settings.json"); return FS::PathCombine(QDir::homePath(), "Library/Application Support/.ftba");
} }
#elif defined(Q_OS_WIN32) #elif defined(Q_OS_WIN32)
QString getFTBASettingsPath() { QString getFTBAPath() {
wchar_t buf[BUFFER_SIZE]; wchar_t buf[BUFFER_SIZE];
if(!GetEnvironmentVariableW(L"LOCALAPPDATA", buf, BUFFER_SIZE)) if(!GetEnvironmentVariableW(L"LOCALAPPDATA", buf, BUFFER_SIZE))
{ {
return QString(); return QString();
} }
QString appDataLocal = QString::fromWCharArray(buf); QString appDataLocal = QString::fromWCharArray(buf);
QString settingsPath = FS::PathCombine(appDataLocal, ".ftba/bin/settings.json"); QString settingsPath = FS::PathCombine(appDataLocal, ".ftba");
return settingsPath; return settingsPath;
} }
#else #else
QString getFTBASettingsPath() { QString getFTBAPath() {
return FS::PathCombine(QDir::homePath(), ".ftba/bin/settings.json"); return FS::PathCombine(QDir::homePath(), ".ftba");
} }
#endif #endif
QString getFTBASettingsPath() {
return FS::PathCombine(getFTBAPath(), "bin/settings.json");
}
QString getFTBAVersionPath(const QString& id) {
return FS::PathCombine(getFTBAPath(), QString("bin/versions/%1/%1.json").arg(id));
}
QString getFTBAInstances() { QString getFTBAInstances() {
QByteArray data; QByteArray data;
auto settingsPath = getFTBASettingsPath(); auto settingsPath = getFTBASettingsPath();
@ -155,6 +164,90 @@ Reference from an FTB App file, as of 28.05.2022
} }
*/ */
void resolveModloader(QString mcVersion, ModLoader &loader) {
if(loader.id.isEmpty()) {
loader.type = ModLoaderType::None;
return;
}
auto path = getFTBAVersionPath(loader.id);
QByteArray data;
try
{
data = FS::read(path);
}
catch (const Exception &e)
{
qWarning() << "Could not resolve modloader ID: " << loader.id << "File cannot be loaded: " << path;
loader.type = ModLoaderType::Unresolved;
return;
}
try
{
QJsonDocument doc = Json::requireDocument(data);
QJsonObject root = Json::requireObject(doc, "version.json");
for (auto library: Json::ensureArray(root, "libraries", {}))
{
if (!library.isObject())
{
continue;
}
auto libraryObject = Json::ensureValueObject(library, {}, "");
GradleSpecifier name = Json::requireString(libraryObject, "name");
auto artifactPrefix = name.artifactPrefix();
if(artifactPrefix == "net.minecraftforge:forge") {
QString libraryVersion = name.version();
loader.type = ModLoaderType::Forge;
// remove any garbage 'minecraft version' prefix / suffix
libraryVersion.remove(QString("%1-").arg(mcVersion));
libraryVersion.remove(QString("-%1").arg(mcVersion));
loader.version = libraryVersion;
return;
}
else if(artifactPrefix == "net.minecraftforge:minecraftforge") {
loader.type = ModLoaderType::Forge;
loader.version = name.version();
return;
}
else if (artifactPrefix == "net.fabricmc:fabric-loader")
{
loader.type = ModLoaderType::Fabric;
loader.version = name.version();
return;
}
else if (artifactPrefix == "org.quiltmc:quilt-loader")
{
loader.type = ModLoaderType::Quilt;
loader.version = name.version();
return;
}
}
// Weird detection for 'modern' forge
QJsonObject arguments = Json::ensureObject(root, "arguments");
auto gameArgs = Json::ensureArray(arguments, "game");
bool versionIsNext = false;
for (auto arg: gameArgs) {
QString value = Json::ensureValueString(arg, QString());
if(versionIsNext) {
loader.type = ModLoaderType::Forge;
loader.version = value;
break;
}
if(value == "--fml.forgeVersion") {
versionIsNext = true;
}
}
return;
}
catch (const JSONValidationError &e)
{
qWarning() << "Could not resolve modloader ID: " << loader.id << "File cannot be understood: " << path << "Error: " << e.cause();
loader.type = ModLoaderType::Unresolved;
}
}
bool parseModpackJson(const QByteArray& data, Modpack & out) { bool parseModpackJson(const QByteArray& data, Modpack & out) {
try try
{ {
@ -173,9 +266,9 @@ bool parseModpackJson(const QByteArray& data, Modpack & out) {
out.authors.append(Json::requireValueString(author)); out.authors.append(Json::requireValueString(author));
} }
out.mcVersion = Json::requireString(object, "mcVersion"); out.mcVersion = Json::requireString(object, "mcVersion");
out.modLoader = Json::ensureString(object, "modLoader", QString()); out.modLoader.id = Json::ensureString(object, "modLoader", QString());
resolveModloader(out.mcVersion, out.modLoader);
out.hasInstMods = Json::ensureBoolean(object, "hasInstMods", false); out.hasInstMods = Json::ensureBoolean(object, "hasInstMods", false);
out.minMemory = Json::ensureInteger(object, "minMemory", 1024); out.minMemory = Json::ensureInteger(object, "minMemory", 1024);

View File

@ -21,8 +21,21 @@
namespace ImportFTB { namespace ImportFTB {
struct Modpack enum class ModLoaderType {
{ Unresolved,
None,
Forge,
Fabric,
Quilt
};
struct ModLoader {
QString id;
ModLoaderType type = ModLoaderType::Unresolved;
QString version;
};
struct Modpack {
int id = 0; int id = 0;
int versionId = 0; int versionId = 0;
@ -32,7 +45,7 @@ struct Modpack
QStringList authors; QStringList authors;
QString mcVersion; QString mcVersion;
QString modLoader; ModLoader modLoader;
bool hasInstMods = false; bool hasInstMods = false;
int minMemory = 1024; int minMemory = 1024;

View File

@ -53,16 +53,27 @@ void PackInstallTask::copyFinished() {
components->setComponentVersion("net.minecraft", m_pack.mcVersion, true); components->setComponentVersion("net.minecraft", m_pack.mcVersion, true);
auto modloader = m_pack.modLoader; auto modloader = m_pack.modLoader;
if(!modloader.isEmpty()) { switch(modloader.type) {
if(modloader.contains("-forge-")) { case ModLoaderType::None: {
auto forgeVersion = modloader.replace(m_pack.mcVersion, "").replace("-forge-", ""); // NOOP
components->setComponentVersion("net.minecraftforge", forgeVersion, true); break;
} }
else { case ModLoaderType::Forge: {
qWarning() << "Unknown modloader version: " << modloader; components->setComponentVersion("net.minecraftforge", modloader.version, true);
break;
}
case ModLoaderType::Fabric: {
components->setComponentVersion("net.fabricmc.fabric-loader", modloader.version, true);
break;
}
case ModLoaderType::Quilt: {
components->setComponentVersion("org.quiltmc.quilt-loader", modloader.version, true);
break;
}
case ModLoaderType::Unresolved: {
qWarning() << "Unknown modloader version: " << modloader.id;
} }
} }
components->saveNow(); components->saveNow();
instance.setName(m_instName); instance.setName(m_instName);