aboutsummaryrefslogtreecommitdiff
path: root/api/logic/minecraft
diff options
context:
space:
mode:
Diffstat (limited to 'api/logic/minecraft')
-rw-r--r--api/logic/minecraft/AssetsUtils.cpp2
-rw-r--r--api/logic/minecraft/AssetsUtils.h2
-rw-r--r--api/logic/minecraft/GradleSpecifier.h42
-rw-r--r--api/logic/minecraft/GradleSpecifier_test.cpp5
-rw-r--r--api/logic/minecraft/Library.cpp8
-rw-r--r--api/logic/minecraft/Library_test.cpp3
-rw-r--r--api/logic/minecraft/MinecraftInstance.cpp119
-rw-r--r--api/logic/minecraft/MinecraftInstance.h9
-rw-r--r--api/logic/minecraft/MinecraftLoadAndCheck.h2
-rw-r--r--api/logic/minecraft/MinecraftUpdate.cpp2
-rw-r--r--api/logic/minecraft/MinecraftUpdate.h2
-rw-r--r--api/logic/minecraft/MojangVersionFormat.cpp12
-rw-r--r--api/logic/minecraft/MojangVersionFormat.h3
-rw-r--r--api/logic/minecraft/OneSixVersionFormat.cpp34
-rw-r--r--api/logic/minecraft/OneSixVersionFormat.h9
-rw-r--r--api/logic/minecraft/OpSys.cpp2
-rw-r--r--api/logic/minecraft/OpSys.h2
-rw-r--r--api/logic/minecraft/PackProfile.cpp2
-rw-r--r--api/logic/minecraft/PackProfile.h8
-rw-r--r--api/logic/minecraft/Rule.cpp2
-rw-r--r--api/logic/minecraft/Rule.h2
-rw-r--r--api/logic/minecraft/VersionFilterData.cpp53
-rw-r--r--api/logic/minecraft/VersionFilterData.h5
-rw-r--r--api/logic/minecraft/World.cpp213
-rw-r--r--api/logic/minecraft/World.h35
-rw-r--r--api/logic/minecraft/WorldList.cpp21
-rw-r--r--api/logic/minecraft/WorldList.h8
-rw-r--r--api/logic/minecraft/auth/MojangAccount.cpp2
-rw-r--r--api/logic/minecraft/auth/MojangAccount.h2
-rw-r--r--api/logic/minecraft/auth/MojangAccountList.cpp2
-rw-r--r--api/logic/minecraft/auth/MojangAccountList.h2
-rw-r--r--api/logic/minecraft/auth/YggdrasilTask.cpp2
-rw-r--r--api/logic/minecraft/auth/YggdrasilTask.h2
-rw-r--r--api/logic/minecraft/auth/flows/AuthenticateTask.cpp2
-rw-r--r--api/logic/minecraft/auth/flows/AuthenticateTask.h2
-rw-r--r--api/logic/minecraft/auth/flows/RefreshTask.cpp2
-rw-r--r--api/logic/minecraft/auth/flows/RefreshTask.h2
-rw-r--r--api/logic/minecraft/auth/flows/ValidateTask.cpp2
-rw-r--r--api/logic/minecraft/auth/flows/ValidateTask.h2
-rw-r--r--api/logic/minecraft/launch/ClaimAccount.h2
-rw-r--r--api/logic/minecraft/launch/CreateGameFolders.cpp28
-rw-r--r--api/logic/minecraft/launch/CreateGameFolders.h (renamed from api/logic/minecraft/launch/CreateServerResourcePacksFolder.h)10
-rw-r--r--api/logic/minecraft/launch/CreateServerResourcePacksFolder.cpp19
-rw-r--r--api/logic/minecraft/launch/DirectJavaLaunch.cpp23
-rw-r--r--api/logic/minecraft/launch/DirectJavaLaunch.h11
-rw-r--r--api/logic/minecraft/launch/ExtractNatives.cpp23
-rw-r--r--api/logic/minecraft/launch/ExtractNatives.h2
-rw-r--r--api/logic/minecraft/launch/LauncherPartLaunch.cpp21
-rw-r--r--api/logic/minecraft/launch/LauncherPartLaunch.h11
-rw-r--r--api/logic/minecraft/launch/MinecraftServerTarget.cpp66
-rw-r--r--api/logic/minecraft/launch/MinecraftServerTarget.h30
-rw-r--r--api/logic/minecraft/launch/ModMinecraftJar.cpp2
-rw-r--r--api/logic/minecraft/launch/ModMinecraftJar.h2
-rw-r--r--api/logic/minecraft/launch/PrintInstanceInfo.cpp4
-rw-r--r--api/logic/minecraft/launch/PrintInstanceInfo.h7
-rw-r--r--api/logic/minecraft/launch/ReconstructAssets.cpp2
-rw-r--r--api/logic/minecraft/launch/ReconstructAssets.h2
-rw-r--r--api/logic/minecraft/launch/ScanModFolders.cpp11
-rw-r--r--api/logic/minecraft/launch/ScanModFolders.h2
-rw-r--r--api/logic/minecraft/launch/VerifyJavaInstall.cpp34
-rw-r--r--api/logic/minecraft/launch/VerifyJavaInstall.h17
-rw-r--r--api/logic/minecraft/legacy/LegacyInstance.cpp4
-rw-r--r--api/logic/minecraft/legacy/LegacyInstance.h7
-rw-r--r--api/logic/minecraft/legacy/LegacyModList.cpp2
-rw-r--r--api/logic/minecraft/legacy/LegacyModList.h2
-rw-r--r--api/logic/minecraft/mod/LocalModParseTask.cpp171
-rw-r--r--api/logic/minecraft/mod/Mod.cpp2
-rw-r--r--api/logic/minecraft/mod/Mod.h2
-rw-r--r--api/logic/minecraft/mod/ModFolderModel.cpp2
-rw-r--r--api/logic/minecraft/mod/ModFolderModel.h2
-rw-r--r--api/logic/minecraft/mod/ResourcePackFolderModel.cpp23
-rw-r--r--api/logic/minecraft/mod/ResourcePackFolderModel.h13
-rw-r--r--api/logic/minecraft/mod/TexturePackFolderModel.cpp23
-rw-r--r--api/logic/minecraft/mod/TexturePackFolderModel.h13
-rw-r--r--api/logic/minecraft/services/SkinDelete.cpp42
-rw-r--r--api/logic/minecraft/services/SkinDelete.h30
-rw-r--r--api/logic/minecraft/services/SkinUpload.cpp (renamed from api/logic/minecraft/SkinUpload.cpp)31
-rw-r--r--api/logic/minecraft/services/SkinUpload.h (renamed from api/logic/minecraft/SkinUpload.h)0
-rw-r--r--api/logic/minecraft/update/FMLLibrariesTask.cpp2
79 files changed, 1032 insertions, 299 deletions
diff --git a/api/logic/minecraft/AssetsUtils.cpp b/api/logic/minecraft/AssetsUtils.cpp
index 68089080..c01733b6 100644
--- a/api/logic/minecraft/AssetsUtils.cpp
+++ b/api/logic/minecraft/AssetsUtils.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/AssetsUtils.h b/api/logic/minecraft/AssetsUtils.h
index 356b8c8a..32e57060 100644
--- a/api/logic/minecraft/AssetsUtils.h
+++ b/api/logic/minecraft/AssetsUtils.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/GradleSpecifier.h b/api/logic/minecraft/GradleSpecifier.h
index 959325c6..60e0a726 100644
--- a/api/logic/minecraft/GradleSpecifier.h
+++ b/api/logic/minecraft/GradleSpecifier.h
@@ -18,32 +18,35 @@ struct GradleSpecifier
{
/*
org.gradle.test.classifiers : service : 1.0 : jdk15 @ jar
- DEBUG 0 "org.gradle.test.classifiers:service:1.0:jdk15@jar"
- DEBUG 1 "org.gradle.test.classifiers"
- DEBUG 2 "service"
- DEBUG 3 "1.0"
- DEBUG 4 ":jdk15"
- DEBUG 5 "jdk15"
- DEBUG 6 "@jar"
- DEBUG 7 "jar"
+ 0 "org.gradle.test.classifiers:service:1.0:jdk15@jar"
+ 1 "org.gradle.test.classifiers"
+ 2 "service"
+ 3 "1.0"
+ 4 "jdk15"
+ 5 "jar"
*/
- QRegExp matcher("([^:@]+):([^:@]+):([^:@]+)" "(:([^:@]+))?" "(@([^:@]+))?");
+ QRegExp matcher("([^:@]+):([^:@]+):([^:@]+)" "(?::([^:@]+))?" "(?:@([^:@]+))?");
m_valid = matcher.exactMatch(value);
+ if(!m_valid) {
+ m_invalidValue = value;
+ return *this;
+ }
auto elements = matcher.capturedTexts();
m_groupId = elements[1];
m_artifactId = elements[2];
m_version = elements[3];
- m_classifier = elements[5];
- if(!elements[7].isEmpty())
+ m_classifier = elements[4];
+ if(!elements[5].isEmpty())
{
- m_extension = elements[7];
+ m_extension = elements[5];
}
return *this;
}
- operator QString() const
+ QString serialize() const
{
- if(!m_valid)
- return "INVALID";
+ if(!m_valid) {
+ return m_invalidValue;
+ }
QString retval = m_groupId + ":" + m_artifactId + ":" + m_version;
if(!m_classifier.isEmpty())
{
@@ -57,6 +60,9 @@ struct GradleSpecifier
}
QString getFileName() const
{
+ if(!m_valid) {
+ return QString();
+ }
QString filename = m_artifactId + '-' + m_version;
if(!m_classifier.isEmpty())
{
@@ -67,8 +73,9 @@ struct GradleSpecifier
}
QString toPath(const QString & filenameOverride = QString()) const
{
- if(!m_valid)
- return "INVALID";
+ if(!m_valid) {
+ return QString();
+ }
QString filename;
if(filenameOverride.isEmpty())
{
@@ -134,6 +141,7 @@ struct GradleSpecifier
return true;
}
private:
+ QString m_invalidValue;
QString m_groupId;
QString m_artifactId;
QString m_version;
diff --git a/api/logic/minecraft/GradleSpecifier_test.cpp b/api/logic/minecraft/GradleSpecifier_test.cpp
index f49ec718..0900c9d8 100644
--- a/api/logic/minecraft/GradleSpecifier_test.cpp
+++ b/api/logic/minecraft/GradleSpecifier_test.cpp
@@ -31,7 +31,7 @@ slots:
{
QFETCH(QString, through);
- QString converted = GradleSpecifier(through);
+ QString converted = GradleSpecifier(through).serialize();
QCOMPARE(converted, through);
}
@@ -68,7 +68,8 @@ slots:
GradleSpecifier spec(input);
QVERIFY(!spec.valid());
- QCOMPARE(spec.operator QString(), QString("INVALID"));
+ QCOMPARE(spec.serialize(), input);
+ QCOMPARE(spec.toPath(), QString());
}
};
diff --git a/api/logic/minecraft/Library.cpp b/api/logic/minecraft/Library.cpp
index b3c7657c..f2293679 100644
--- a/api/logic/minecraft/Library.cpp
+++ b/api/logic/minecraft/Library.cpp
@@ -94,13 +94,13 @@ QList< std::shared_ptr< NetAction > > Library::getDownloads(
auto rawSha1 = QByteArray::fromHex(sha1.toLatin1());
auto dl = Net::Download::makeCached(url, entry, options);
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1));
- qDebug() << "Checksummed Download for:" << rawName() << "storage:" << storage << "url:" << url;
+ qDebug() << "Checksummed Download for:" << rawName().serialize() << "storage:" << storage << "url:" << url;
out.append(dl);
}
else
{
out.append(Net::Download::makeCached(url, entry, options));
- qDebug() << "Download for:" << rawName() << "storage:" << storage << "url:" << url;
+ qDebug() << "Download for:" << rawName().serialize() << "storage:" << storage << "url:" << url;
}
return true;
};
@@ -145,7 +145,7 @@ QList< std::shared_ptr< NetAction > > Library::getDownloads(
}
else
{
- qDebug() << "Ignoring native library" << m_name << "because it has no classifier for current OS";
+ qDebug() << "Ignoring native library" << m_name.serialize() << "because it has no classifier for current OS";
}
}
else
@@ -157,7 +157,7 @@ QList< std::shared_ptr< NetAction > > Library::getDownloads(
}
else
{
- qDebug() << "Ignoring java library" << m_name << "because it has no artifact";
+ qDebug() << "Ignoring java library" << m_name.serialize() << "because it has no artifact";
}
}
}
diff --git a/api/logic/minecraft/Library_test.cpp b/api/logic/minecraft/Library_test.cpp
index c3d6150d..75bb4db1 100644
--- a/api/logic/minecraft/Library_test.cpp
+++ b/api/logic/minecraft/Library_test.cpp
@@ -18,7 +18,8 @@ private:
jsonFile.open(QIODevice::ReadOnly);
auto data = jsonFile.readAll();
jsonFile.close();
- return MojangVersionFormat::libraryFromJson(QJsonDocument::fromJson(data).object(), file);
+ ProblemContainer problems;
+ return MojangVersionFormat::libraryFromJson(problems, QJsonDocument::fromJson(data).object(), file);
}
// get absolute path to expected storage, assuming default cache prefix
QStringList getStorage(QString relative)
diff --git a/api/logic/minecraft/MinecraftInstance.cpp b/api/logic/minecraft/MinecraftInstance.cpp
index db259395..dbf9f816 100644
--- a/api/logic/minecraft/MinecraftInstance.cpp
+++ b/api/logic/minecraft/MinecraftInstance.cpp
@@ -1,5 +1,5 @@
#include "MinecraftInstance.h"
-#include <minecraft/launch/CreateServerResourcePacksFolder.h>
+#include <minecraft/launch/CreateGameFolders.h>
#include <minecraft/launch/ExtractNatives.h>
#include <minecraft/launch/PrintInstanceInfo.h>
#include <settings/Setting.h>
@@ -12,6 +12,7 @@
#include <java/JavaVersion.h>
#include "launch/LaunchTask.h"
+#include "launch/steps/LookupServerAddress.h"
#include "launch/steps/PostLaunchCommand.h"
#include "launch/steps/Update.h"
#include "launch/steps/PreLaunchCommand.h"
@@ -22,12 +23,15 @@
#include "minecraft/launch/ClaimAccount.h"
#include "minecraft/launch/ReconstructAssets.h"
#include "minecraft/launch/ScanModFolders.h"
+#include "minecraft/launch/VerifyJavaInstall.h"
#include "java/launch/CheckJava.h"
#include "java/JavaUtils.h"
#include "meta/Index.h"
#include "meta/VersionList.h"
#include "mod/ModFolderModel.h"
+#include "mod/ResourcePackFolderModel.h"
+#include "mod/TexturePackFolderModel.h"
#include "WorldList.h"
#include "icons/IIconList.h"
@@ -38,6 +42,7 @@
#include "MinecraftUpdate.h"
#include "MinecraftLoadAndCheck.h"
#include <minecraft/gameoptions/GameOptions.h>
+#include <minecraft/update/FoldersTask.h>
#define IBUS "@im=ibus"
@@ -100,6 +105,20 @@ MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsO
auto launchMethodOverride = m_settings->registerSetting("OverrideMCLaunchMethod", false);
m_settings->registerOverride(globalSettings->getSetting("MCLaunchMethod"), launchMethodOverride);
+ // Native library workarounds
+ auto nativeLibraryWorkaroundsOverride = m_settings->registerSetting("OverrideNativeWorkarounds", false);
+ m_settings->registerOverride(globalSettings->getSetting("UseNativeOpenAL"), nativeLibraryWorkaroundsOverride);
+ m_settings->registerOverride(globalSettings->getSetting("UseNativeGLFW"), nativeLibraryWorkaroundsOverride);
+
+ // Game time
+ auto gameTimeOverride = m_settings->registerSetting("OverrideGameTime", false);
+ m_settings->registerOverride(globalSettings->getSetting("ShowGameTime"), gameTimeOverride);
+ m_settings->registerOverride(globalSettings->getSetting("RecordGameTime"), gameTimeOverride);
+
+ // Join server on launch, this does not have a global override
+ m_settings->registerSetting("JoinServerOnLaunch", false);
+ m_settings->registerSetting("JoinServerOnLaunchAddress", "");
+
// DEPRECATED: Read what versions the user configuration thinks should be used
m_settings->registerSetting({"IntendedVersion", "MinecraftVersion"}, "");
m_settings->registerSetting("LWJGLVersion", "");
@@ -384,7 +403,8 @@ static QString replaceTokensIn(QString text, QMap<QString, QString> with)
return result;
}
-QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session) const
+QStringList MinecraftInstance::processMinecraftArgs(
+ AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) const
{
auto profile = m_components->getProfile();
QString args_pattern = profile->getMinecraftArguments();
@@ -393,6 +413,12 @@ QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session) cons
args_pattern += " --tweakClass " + tweaker;
}
+ if (serverToJoin && !serverToJoin->address.isEmpty())
+ {
+ args_pattern += " --server " + serverToJoin->address;
+ args_pattern += " --port " + QString::number(serverToJoin->port);
+ }
+
QMap<QString, QString> token_mapping;
// yggdrasil!
if(session)
@@ -429,7 +455,7 @@ QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session) cons
return parts;
}
-QString MinecraftInstance::createLaunchScript(AuthSessionPtr session)
+QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
{
QString launchScript;
@@ -450,8 +476,17 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session)
launchScript += "appletClass " + appletClass + "\n";
}
+ if (serverToJoin && !serverToJoin->address.isEmpty())
+ {
+ launchScript += "serverAddress " + serverToJoin->address + "\n";
+ launchScript += "serverPort " + QString::number(serverToJoin->port) + "\n";
+ }
+
// generic minecraft params
- for (auto param : processMinecraftArgs(session))
+ for (auto param : processMinecraftArgs(
+ session,
+ nullptr /* When using a launch script, the server parameters are handled by it*/
+ ))
{
launchScript += "param " + param + "\n";
}
@@ -501,7 +536,7 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session)
return launchScript;
}
-QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session)
+QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
{
QStringList out;
out << "Main Class:" << " " + getMainClass() << "";
@@ -520,11 +555,23 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session)
out << "";
}
+ auto settings = this->settings();
+ bool nativeOpenAL = settings->get("UseNativeOpenAL").toBool();
+ bool nativeGLFW = settings->get("UseNativeGLFW").toBool();
+ if (nativeOpenAL || nativeGLFW)
+ {
+ if (nativeOpenAL)
+ out << "Using system OpenAL.";
+ if (nativeGLFW)
+ out << "Using system GLFW.";
+ out << "";
+ }
+
// libraries and class path.
{
out << "Libraries:";
QStringList jars, nativeJars;
- auto javaArchitecture = settings()->get("JavaArchitecture").toString();
+ auto javaArchitecture = settings->get("JavaArchitecture").toString();
profile->getLibraryFiles(javaArchitecture, jars, nativeJars, getLocalLibraryPath(), binRoot());
auto printLibFile = [&](const QString & path)
{
@@ -604,20 +651,20 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session)
out << "";
}
- auto params = processMinecraftArgs(nullptr);
+ auto params = processMinecraftArgs(nullptr, serverToJoin);
out << "Params:";
out << " " + params.join(' ');
out << "";
QString windowParams;
- if (settings()->get("LaunchMaximized").toBool())
+ if (settings->get("LaunchMaximized").toBool())
{
out << "Window size: max (if available)";
}
else
{
- auto width = settings()->get("MinecraftWinWidth").toInt();
- auto height = settings()->get("MinecraftWinHeight").toInt();
+ auto width = settings->get("MinecraftWinWidth").toInt();
+ auto height = settings->get("MinecraftWinHeight").toInt();
out << "Window size: " + QString::number(width) + " x " + QString::number(height);
}
out << "";
@@ -751,9 +798,15 @@ QString MinecraftInstance::getStatusbarDescription()
QString description;
description.append(tr("Minecraft %1 (%2)").arg(m_components->getComponentVersion("net.minecraft")).arg(typeName()));
- if(totalTimePlayed() > 0)
+ if(m_settings->get("ShowGameTime").toBool())
{
- description.append(tr(", played for %1").arg(prettifyTimeDuration(totalTimePlayed())));
+ if (lastTimePlayed() > 0) {
+ description.append(tr(", last played for %1").arg(prettifyTimeDuration(lastTimePlayed())));
+ }
+
+ if (totalTimePlayed() > 0) {
+ description.append(tr(", total played for %1").arg(prettifyTimeDuration(totalTimePlayed())));
+ }
}
if(hasCrashed())
{
@@ -778,7 +831,7 @@ shared_qobject_ptr<Task> MinecraftInstance::createUpdateTask(Net::Mode mode)
return nullptr;
}
-shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr session)
+shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
{
// FIXME: get rid of shared_from_this ...
auto process = LaunchTask::create(std::dynamic_pointer_cast<MinecraftInstance>(shared_from_this()));
@@ -805,6 +858,26 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
return process;
}
+ // create the .minecraft folder and server-resource-packs (workaround for Minecraft bug MCL-3732)
+ {
+ process->appendStep(new CreateGameFolders(pptr));
+ }
+
+ if (!serverToJoin && m_settings->get("JoinServerOnLaunch").toBool())
+ {
+ QString fullAddress = m_settings->get("JoinServerOnLaunchAddress").toString();
+ serverToJoin.reset(new MinecraftServerTarget(MinecraftServerTarget::parse(fullAddress)));
+ }
+
+ if(serverToJoin && serverToJoin->port == 25565)
+ {
+ // Resolve server address to join on launch
+ auto *step = new LookupServerAddress(pptr);
+ step->setLookupAddress(serverToJoin->address);
+ step->setOutputAddressPtr(serverToJoin);
+ process->appendStep(step);
+ }
+
// run pre-launch command if that's needed
if(getPreLaunchCommand().size())
{
@@ -829,19 +902,14 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
process->appendStep(new ModMinecraftJar(pptr));
}
- // if there are any jar mods
+ // Scan mods folders for mods
{
process->appendStep(new ScanModFolders(pptr));
}
// print some instance info here...
{
- process->appendStep(new PrintInstanceInfo(pptr, session));
- }
-
- // create the server-resource-packs folder (workaround for Minecraft bug MCL-3732)
- {
- process->appendStep(new CreateServerResourcePacksFolder(pptr));
+ process->appendStep(new PrintInstanceInfo(pptr, session, serverToJoin));
}
// extract native jars if needed
@@ -854,6 +922,11 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
process->appendStep(new ReconstructAssets(pptr));
}
+ // verify that minimum Java requirements are met
+ {
+ process->appendStep(new VerifyJavaInstall(pptr));
+ }
+
{
// actually launch the game
auto method = launchMethod();
@@ -862,6 +935,7 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
auto step = new LauncherPartLaunch(pptr);
step->setWorkingDirectory(gameRoot());
step->setAuthSession(session);
+ step->setServerToJoin(serverToJoin);
process->appendStep(step);
}
else if (method == "DirectJava")
@@ -869,6 +943,7 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
auto step = new DirectJavaLaunch(pptr);
step->setWorkingDirectory(gameRoot());
step->setAuthSession(session);
+ step->setServerToJoin(serverToJoin);
process->appendStep(step);
}
}
@@ -925,7 +1000,7 @@ std::shared_ptr<ModFolderModel> MinecraftInstance::resourcePackList() const
{
if (!m_resource_pack_list)
{
- m_resource_pack_list.reset(new ModFolderModel(resourcePacksDir()));
+ m_resource_pack_list.reset(new ResourcePackFolderModel(resourcePacksDir()));
m_resource_pack_list->disableInteraction(isRunning());
connect(this, &BaseInstance::runningStatusChanged, m_resource_pack_list.get(), &ModFolderModel::disableInteraction);
}
@@ -936,7 +1011,7 @@ std::shared_ptr<ModFolderModel> MinecraftInstance::texturePackList() const
{
if (!m_texture_pack_list)
{
- m_texture_pack_list.reset(new ModFolderModel(texturePacksDir()));
+ m_texture_pack_list.reset(new TexturePackFolderModel(texturePacksDir()));
m_texture_pack_list->disableInteraction(isRunning());
connect(this, &BaseInstance::runningStatusChanged, m_texture_pack_list.get(), &ModFolderModel::disableInteraction);
}
diff --git a/api/logic/minecraft/MinecraftInstance.h b/api/logic/minecraft/MinecraftInstance.h
index 985a8a76..05600797 100644
--- a/api/logic/minecraft/MinecraftInstance.h
+++ b/api/logic/minecraft/MinecraftInstance.h
@@ -5,6 +5,7 @@
#include <QProcess>
#include <QDir>
#include "multimc_logic_export.h"
+#include "minecraft/launch/MinecraftServerTarget.h"
class ModFolderModel;
class WorldList;
@@ -76,11 +77,11 @@ public:
////// Launch stuff //////
shared_qobject_ptr<Task> createUpdateTask(Net::Mode mode) override;
- shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account) override;
+ shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) override;
QStringList extraArguments() const override;
- QStringList verboseDescription(AuthSessionPtr session) override;
+ QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override;
QList<Mod> getJarMods() const;
- QString createLaunchScript(AuthSessionPtr session);
+ QString createLaunchScript(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin);
/// get arguments passed to java
QStringList javaArguments() const;
@@ -107,7 +108,7 @@ public:
virtual QString getMainClass() const;
// FIXME: remove
- virtual QStringList processMinecraftArgs(AuthSessionPtr account) const;
+ virtual QStringList processMinecraftArgs(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) const;
virtual JavaVersion getJavaVersion() const;
diff --git a/api/logic/minecraft/MinecraftLoadAndCheck.h b/api/logic/minecraft/MinecraftLoadAndCheck.h
index 6924ca2d..3435b52b 100644
--- a/api/logic/minecraft/MinecraftLoadAndCheck.h
+++ b/api/logic/minecraft/MinecraftLoadAndCheck.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/MinecraftUpdate.cpp b/api/logic/minecraft/MinecraftUpdate.cpp
index 68dd437d..8f1565b0 100644
--- a/api/logic/minecraft/MinecraftUpdate.cpp
+++ b/api/logic/minecraft/MinecraftUpdate.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/MinecraftUpdate.h b/api/logic/minecraft/MinecraftUpdate.h
index eb8e74db..fadebff9 100644
--- a/api/logic/minecraft/MinecraftUpdate.h
+++ b/api/logic/minecraft/MinecraftUpdate.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/MojangVersionFormat.cpp b/api/logic/minecraft/MojangVersionFormat.cpp
index 33d3c54c..f9cb2228 100644
--- a/api/logic/minecraft/MojangVersionFormat.cpp
+++ b/api/logic/minecraft/MojangVersionFormat.cpp
@@ -220,7 +220,7 @@ VersionFilePtr MojangVersionFormat::versionFileFromJson(const QJsonDocument &doc
{
auto libObj = requireObject(libVal);
- auto lib = MojangVersionFormat::libraryFromJson(libObj, filename);
+ auto lib = MojangVersionFormat::libraryFromJson(*out, libObj, filename);
out->libraries.append(lib);
}
}
@@ -283,14 +283,18 @@ QJsonDocument MojangVersionFormat::versionFileToJson(const VersionFilePtr &patch
}
}
-LibraryPtr MojangVersionFormat::libraryFromJson(const QJsonObject &libObj, const QString &filename)
+LibraryPtr MojangVersionFormat::libraryFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename)
{
LibraryPtr out(new Library());
if (!libObj.contains("name"))
{
throw JSONValidationError(filename + "contains a library that doesn't have a 'name' field");
}
- out->m_name = libObj.value("name").toString();
+ auto rawName = libObj.value("name").toString();
+ out->m_name = rawName;
+ if(!out->m_name.valid()) {
+ problems.addProblem(ProblemSeverity::Error, QObject::tr("Library %1 name is broken and cannot be processed.").arg(rawName));
+ }
Bits::readString(libObj, "url", out->m_repositoryURL);
if (libObj.contains("extract"))
@@ -333,7 +337,7 @@ LibraryPtr MojangVersionFormat::libraryFromJson(const QJsonObject &libObj, const
QJsonObject MojangVersionFormat::libraryToJson(Library *library)
{
QJsonObject libRoot;
- libRoot.insert("name", (QString)library->m_name);
+ libRoot.insert("name", library->m_name.serialize());
if (!library->m_repositoryURL.isEmpty())
{
libRoot.insert("url", library->m_repositoryURL);
diff --git a/api/logic/minecraft/MojangVersionFormat.h b/api/logic/minecraft/MojangVersionFormat.h
index 76c529e9..2871dae4 100644
--- a/api/logic/minecraft/MojangVersionFormat.h
+++ b/api/logic/minecraft/MojangVersionFormat.h
@@ -3,6 +3,7 @@
#include <minecraft/VersionFile.h>
#include <minecraft/Library.h>
#include <QJsonDocument>
+#include <ProblemProvider.h>
#include "multimc_logic_export.h"
@@ -20,6 +21,6 @@ public:
static QJsonDocument versionFileToJson(const VersionFilePtr &patch);
// libraries
- static LibraryPtr libraryFromJson(const QJsonObject &libObj, const QString &filename);
+ static LibraryPtr libraryFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename);
static QJsonObject libraryToJson(Library *library);
};
diff --git a/api/logic/minecraft/OneSixVersionFormat.cpp b/api/logic/minecraft/OneSixVersionFormat.cpp
index 7ac9e2db..d6aaa790 100644
--- a/api/logic/minecraft/OneSixVersionFormat.cpp
+++ b/api/logic/minecraft/OneSixVersionFormat.cpp
@@ -13,9 +13,9 @@ static void readString(const QJsonObject &root, const QString &key, QString &var
}
}
-LibraryPtr OneSixVersionFormat::libraryFromJson(const QJsonObject &libObj, const QString &filename)
+LibraryPtr OneSixVersionFormat::libraryFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename)
{
- LibraryPtr out = MojangVersionFormat::libraryFromJson(libObj, filename);
+ LibraryPtr out = MojangVersionFormat::libraryFromJson(problems, libObj, filename);
readString(libObj, "MMC-hint", out->m_hint);
readString(libObj, "MMC-absulute_url", out->m_absoluteURL);
readString(libObj, "MMC-absoluteUrl", out->m_absoluteURL);
@@ -115,7 +115,7 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc
{
QJsonObject libObj = requireObject(libVal);
// parse the jarmod
- auto lib = OneSixVersionFormat::jarModFromJson(libObj, filename);
+ auto lib = OneSixVersionFormat::jarModFromJson(*out, libObj, filename);
// and add to jar mods
out->jarMods.append(lib);
}
@@ -126,7 +126,7 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc
{
QJsonObject libObj = requireObject(libVal);
// parse the jarmod
- auto lib = OneSixVersionFormat::plusJarModFromJson(libObj, filename, out->name);
+ auto lib = OneSixVersionFormat::plusJarModFromJson(*out, libObj, filename, out->name);
// and add to jar mods
out->jarMods.append(lib);
}
@@ -138,20 +138,20 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc
{
QJsonObject libObj = requireObject(libVal);
// parse the jarmod
- auto lib = OneSixVersionFormat::modFromJson(libObj, filename);
+ auto lib = OneSixVersionFormat::modFromJson(*out, libObj, filename);
// and add to jar mods
out->mods.append(lib);
}
}
- auto readLibs = [&](const char * which, QList<LibraryPtr> & out)
+ auto readLibs = [&](const char * which, QList<LibraryPtr> & outList)
{
for (auto libVal : requireArray(root.value(which)))
{
QJsonObject libObj = requireObject(libVal);
// parse the library
- auto lib = libraryFromJson(libObj, filename);
- out.append(lib);
+ auto lib = libraryFromJson(*out, libObj, filename);
+ outList.append(lib);
}
};
bool hasPlusLibs = root.contains("+libraries");
@@ -180,7 +180,7 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc
if(root.contains("mainJar"))
{
QJsonObject libObj = requireObject(root, "mainJar");
- out->mainJar = libraryFromJson(libObj, filename);
+ out->mainJar = libraryFromJson(*out, libObj, filename);
}
// else reconstruct it from downloads and id ... if that's available
else if(!out->minecraftVersion.isEmpty())
@@ -330,8 +330,12 @@ QJsonDocument OneSixVersionFormat::versionFileToJson(const VersionFilePtr &patch
}
}
-LibraryPtr OneSixVersionFormat::plusJarModFromJson(const QJsonObject &libObj, const QString &filename, const QString &originalName)
-{
+LibraryPtr OneSixVersionFormat::plusJarModFromJson(
+ ProblemContainer & problems,
+ const QJsonObject &libObj,
+ const QString &filename,
+ const QString &originalName
+) {
LibraryPtr out(new Library());
if (!libObj.contains("name"))
{
@@ -366,9 +370,9 @@ LibraryPtr OneSixVersionFormat::plusJarModFromJson(const QJsonObject &libObj, co
return out;
}
-LibraryPtr OneSixVersionFormat::jarModFromJson(const QJsonObject& libObj, const QString& filename)
+LibraryPtr OneSixVersionFormat::jarModFromJson(ProblemContainer & problems, const QJsonObject& libObj, const QString& filename)
{
- return libraryFromJson(libObj, filename);
+ return libraryFromJson(problems, libObj, filename);
}
@@ -377,9 +381,9 @@ QJsonObject OneSixVersionFormat::jarModtoJson(Library *jarmod)
return libraryToJson(jarmod);
}
-LibraryPtr OneSixVersionFormat::modFromJson(const QJsonObject& libObj, const QString& filename)
+LibraryPtr OneSixVersionFormat::modFromJson(ProblemContainer & problems, const QJsonObject& libObj, const QString& filename)
{
- return libraryFromJson(libObj, filename);
+ return libraryFromJson(problems, libObj, filename);
}
QJsonObject OneSixVersionFormat::modtoJson(Library *jarmod)
diff --git a/api/logic/minecraft/OneSixVersionFormat.h b/api/logic/minecraft/OneSixVersionFormat.h
index 14ae385c..1a091d88 100644
--- a/api/logic/minecraft/OneSixVersionFormat.h
+++ b/api/logic/minecraft/OneSixVersionFormat.h
@@ -4,6 +4,7 @@
#include <minecraft/PackProfile.h>
#include <minecraft/Library.h>
#include <QJsonDocument>
+#include <ProblemProvider.h>
class OneSixVersionFormat
{
@@ -13,17 +14,17 @@ public:
static QJsonDocument versionFileToJson(const VersionFilePtr &patch);
// libraries
- static LibraryPtr libraryFromJson(const QJsonObject &libObj, const QString &filename);
+ static LibraryPtr libraryFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename);
static QJsonObject libraryToJson(Library *library);
// DEPRECATED: old 'plus' jar mods generated by the application
- static LibraryPtr plusJarModFromJson(const QJsonObject &libObj, const QString &filename, const QString &originalName);
+ static LibraryPtr plusJarModFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename, const QString &originalName);
// new jar mods derived from libraries
- static LibraryPtr jarModFromJson(const QJsonObject &libObj, const QString &filename);
+ static LibraryPtr jarModFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename);
static QJsonObject jarModtoJson(Library * jarmod);
// mods, also derived from libraries
- static LibraryPtr modFromJson(const QJsonObject &libObj, const QString &filename);
+ static LibraryPtr modFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename);
static QJsonObject modtoJson(Library * jarmod);
};
diff --git a/api/logic/minecraft/OpSys.cpp b/api/logic/minecraft/OpSys.cpp
index 5e1e6c2b..f6a4ed1c 100644
--- a/api/logic/minecraft/OpSys.cpp
+++ b/api/logic/minecraft/OpSys.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/OpSys.h b/api/logic/minecraft/OpSys.h
index 58852acb..63c750b1 100644
--- a/api/logic/minecraft/OpSys.h
+++ b/api/logic/minecraft/OpSys.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/PackProfile.cpp b/api/logic/minecraft/PackProfile.cpp
index 15f2f55d..f6918116 100644
--- a/api/logic/minecraft/PackProfile.cpp
+++ b/api/logic/minecraft/PackProfile.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/PackProfile.h b/api/logic/minecraft/PackProfile.h
index 66cd5e3e..e55e6a58 100644
--- a/api/logic/minecraft/PackProfile.h
+++ b/api/logic/minecraft/PackProfile.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -114,6 +114,10 @@ public:
/// get the profile component by index
Component * getComponent(int index);
+ /// Add the component to the internal list of patches
+ // todo(merged): is this the best approach
+ void appendComponent(ComponentPtr component);
+
private:
void scheduleSave();
bool saveIsScheduled() const;
@@ -121,8 +125,6 @@ private:
/// apply the component patches. Catches all the errors and returns true/false for success/failure
void invalidateLaunchProfile();
- /// Add the component to the internal list of patches
- void appendComponent(ComponentPtr component);
/// insert component so that its index is ideally the specified one (returns real index)
void insertComponent(size_t index, ComponentPtr component);
diff --git a/api/logic/minecraft/Rule.cpp b/api/logic/minecraft/Rule.cpp
index cd10504f..af2861e3 100644
--- a/api/logic/minecraft/Rule.cpp
+++ b/api/logic/minecraft/Rule.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/Rule.h b/api/logic/minecraft/Rule.h
index ef10a6c3..7aa34d96 100644
--- a/api/logic/minecraft/Rule.h
+++ b/api/logic/minecraft/Rule.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/VersionFilterData.cpp b/api/logic/minecraft/VersionFilterData.cpp
index 11f7eea9..38e7b60c 100644
--- a/api/logic/minecraft/VersionFilterData.cpp
+++ b/api/logic/minecraft/VersionFilterData.cpp
@@ -7,18 +7,18 @@ VersionFilterData::VersionFilterData()
{
// 1.3.*
auto libs13 =
- QList<FMLlib>{{"argo-2.25.jar", "bb672829fde76cb163004752b86b0484bd0a7f4b", false},
- {"guava-12.0.1.jar", "b8e78b9af7bf45900e14c6f958486b6ca682195f", false},
- {"asm-all-4.0.jar", "98308890597acb64047f7e896638e0d98753ae82", false}};
+ QList<FMLlib>{{"argo-2.25.jar", "bb672829fde76cb163004752b86b0484bd0a7f4b"},
+ {"guava-12.0.1.jar", "b8e78b9af7bf45900e14c6f958486b6ca682195f"},
+ {"asm-all-4.0.jar", "98308890597acb64047f7e896638e0d98753ae82"}};
fmlLibsMapping["1.3.2"] = libs13;
// 1.4.*
auto libs14 = QList<FMLlib>{
- {"argo-2.25.jar", "bb672829fde76cb163004752b86b0484bd0a7f4b", false},
- {"guava-12.0.1.jar", "b8e78b9af7bf45900e14c6f958486b6ca682195f", false},
- {"asm-all-4.0.jar", "98308890597acb64047f7e896638e0d98753ae82", false},
- {"bcprov-jdk15on-147.jar", "b6f5d9926b0afbde9f4dbe3db88c5247be7794bb", false}};
+ {"argo-2.25.jar", "bb672829fde76cb163004752b86b0484bd0a7f4b"},
+ {"guava-12.0.1.jar", "b8e78b9af7bf45900e14c6f958486b6ca682195f"},
+ {"asm-all-4.0.jar", "98308890597acb64047f7e896638e0d98753ae82"},
+ {"bcprov-jdk15on-147.jar", "b6f5d9926b0afbde9f4dbe3db88c5247be7794bb"}};
fmlLibsMapping["1.4"] = libs14;
fmlLibsMapping["1.4.1"] = libs14;
@@ -31,30 +31,30 @@ VersionFilterData::VersionFilterData()
// 1.5
fmlLibsMapping["1.5"] = QList<FMLlib>{
- {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51", false},
- {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a", false},
- {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58", false},
- {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65", true},
- {"deobfuscation_data_1.5.zip", "5f7c142d53776f16304c0bbe10542014abad6af8", false},
- {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85", true}};
+ {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51"},
+ {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a"},
+ {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58"},
+ {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65"},
+ {"deobfuscation_data_1.5.zip", "5f7c142d53776f16304c0bbe10542014abad6af8"},
+ {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85"}};
// 1.5.1
fmlLibsMapping["1.5.1"] = QList<FMLlib>{
- {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51", false},
- {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a", false},
- {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58", false},
- {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65", true},
- {"deobfuscation_data_1.5.1.zip", "22e221a0d89516c1f721d6cab056a7e37471d0a6", false},
- {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85", true}};
+ {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51"},
+ {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a"},
+ {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58"},
+ {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65"},
+ {"deobfuscation_data_1.5.1.zip", "22e221a0d89516c1f721d6cab056a7e37471d0a6"},
+ {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85"}};
// 1.5.2
fmlLibsMapping["1.5.2"] = QList<FMLlib>{
- {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51", false},
- {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a", false},
- {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58", false},
- {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65", true},
- {"deobfuscation_data_1.5.2.zip", "446e55cd986582c70fcf12cb27bc00114c5adfd9", false},
- {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85", true}};
+ {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51"},
+ {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a"},
+ {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58"},
+ {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65"},
+ {"deobfuscation_data_1.5.2.zip", "446e55cd986582c70fcf12cb27bc00114c5adfd9"},
+ {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85"}};
// don't use installers for those.
forgeInstallerBlacklist = QSet<QString>({"1.5.2"});
@@ -65,4 +65,7 @@ VersionFilterData::VersionFilterData()
QSet<QString>{"net.java.jinput:jinput", "net.java.jinput:jinput-platform",
"net.java.jutils:jutils", "org.lwjgl.lwjgl:lwjgl",
"org.lwjgl.lwjgl:lwjgl_util", "org.lwjgl.lwjgl:lwjgl-platform"};
+
+ java8BeginsDate = timeFromS3Time("2017-03-30T09:32:19+00:00");
+ java16BeginsDate = timeFromS3Time("2021-05-12T11:19:15+00:00");
}
diff --git a/api/logic/minecraft/VersionFilterData.h b/api/logic/minecraft/VersionFilterData.h
index 88e91f11..d100acc3 100644
--- a/api/logic/minecraft/VersionFilterData.h
+++ b/api/logic/minecraft/VersionFilterData.h
@@ -10,7 +10,6 @@ struct FMLlib
{
QString filename;
QString checksum;
- bool ours;
};
struct VersionFilterData
@@ -24,5 +23,9 @@ struct VersionFilterData
QDateTime legacyCutoffDate;
// Libraries that belong to LWJGL
QSet<QString> lwjglWhitelist;
+ // release date of first version to require Java 8 (17w13a)
+ QDateTime java8BeginsDate;
+ // release data of first version to require Java 16 (21w19a)
+ QDateTime java16BeginsDate;
};
extern VersionFilterData MULTIMC_LOGIC_EXPORT g_VersionFilterData;
diff --git a/api/logic/minecraft/World.cpp b/api/logic/minecraft/World.cpp
index 17dbf4ae..a2b4dac7 100644
--- a/api/logic/minecraft/World.cpp
+++ b/api/logic/minecraft/World.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2015-2019 MultiMC Contributors
+/* Copyright 2015-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,7 +32,36 @@
#include <QCoreApplication>
-QString gameTypeToString(GameType type)
+#include <nonstd/optional>
+
+using nonstd::optional;
+using nonstd::nullopt;
+
+GameType::GameType(nonstd::optional<int> original):
+ original(original)
+{
+ if(!original) {
+ return;
+ }
+ switch(*original) {
+ case 0:
+ type = GameType::Survival;
+ break;
+ case 1:
+ type = GameType::Creative;
+ break;
+ case 2:
+ type = GameType::Adventure;
+ break;
+ case 3:
+ type = GameType::Spectator;
+ break;
+ default:
+ break;
+ }
+}
+
+QString GameType::toTranslatedString() const
{
switch (type)
{
@@ -47,7 +76,31 @@ QString gameTypeToString(GameType type)
default:
break;
}
- return QObject::tr("Unknown");
+ if(original) {
+ return QCoreApplication::translate("GameType", "Unknown (%1)").arg(*original);
+ }
+ return QCoreApplication::translate("GameType", "Undefined");
+}
+
+QString GameType::toLogString() const
+{
+ switch (type)
+ {
+ case GameType::Survival:
+ return "Survival";
+ case GameType::Creative:
+ return "Creative";
+ case GameType::Adventure:
+ return "Adventure";
+ case GameType::Spectator:
+ return "Spectator";
+ default:
+ break;
+ }
+ if(original) {
+ return QString("Unknown (%1)").arg(*original);
+ }
+ return "Undefined";
}
std::unique_ptr <nbt::tag_compound> parseLevelDat(QByteArray data)
@@ -58,15 +111,22 @@ std::unique_ptr <nbt::tag_compound> parseLevelDat(QByteArray data)
return nullptr;
}
std::istringstream foo(std::string(output.constData(), output.size()));
- auto pair = nbt::io::read_compound(foo);
+ try {
+ auto pair = nbt::io::read_compound(foo);
- if(pair.first != "")
- return nullptr;
+ if(pair.first != "")
+ return nullptr;
- if(pair.second == nullptr)
- return nullptr;
+ if(pair.second == nullptr)
+ return nullptr;
- return std::move(pair.second);
+ return std::move(pair.second);
+ }
+ catch (const nbt::io::input_error &e)
+ {
+ qWarning() << "Unable to parse level.dat:" << e.what();
+ return nullptr;
+ }
}
QByteArray serializeLevelDat(nbt::tag_compound * levelInfo)
@@ -138,14 +198,31 @@ void World::repath(const QFileInfo &file)
m_folderName = file.fileName();
if(file.isFile() && file.suffix() == "zip")
{
+ m_iconFile = QString();
readFromZip(file);
}
else if(file.isDir())
{
+ QFileInfo assumedIconPath(file.absoluteFilePath() + "/icon.png");
+ if(assumedIconPath.exists()) {
+ m_iconFile = assumedIconPath.absoluteFilePath();
+ }
readFromFS(file);
}
}
+bool World::resetIcon()
+{
+ if(m_iconFile.isNull()) {
+ return false;
+ }
+ if(QFile(m_iconFile).remove()) {
+ m_iconFile = QString();
+ return true;
+ }
+ return false;
+}
+
void World::readFromFS(const QFileInfo &file)
{
auto bytes = getLevelDatDataFromFS(file);
@@ -212,7 +289,7 @@ bool World::install(const QString &to, const QString &name)
{
return false;
}
- ok = !MMCZip::extractSubDir(&zip, m_containerOffsetPath, finalPath).isEmpty();
+ ok = !MMCZip::extractSubDir(&zip, m_containerOffsetPath, finalPath);
}
else if(m_containerFile.isDir())
{
@@ -271,14 +348,16 @@ bool World::rename(const QString &newName)
return true;
}
-static QString read_string (nbt::value& parent, const char * name, const QString & fallback = QString())
+namespace {
+
+optional<QString> read_string (nbt::value& parent, const char * name)
{
try
{
auto &namedValue = parent.at(name);
if(namedValue.get_type() != nbt::tag_type::String)
{
- return fallback;
+ return nullopt;
}
auto & tag_str = namedValue.as<nbt::tag_string>();
return QString::fromStdString(tag_str.get());
@@ -286,25 +365,25 @@ static QString read_string (nbt::value& parent, const char * name, const QString
catch (const std::out_of_range &e)
{
// fallback for old world formats
- qWarning() << "String NBT tag" << name << "could not be found. Defaulting to" << fallback;
- return fallback;
+ qWarning() << "String NBT tag" << name << "could not be found.";
+ return nullopt;
}
catch (const std::bad_cast &e)
{
// type mismatch
- qWarning() << "NBT tag" << name << "could not be converted to string. Defaulting to" << fallback;
- return fallback;
+ qWarning() << "NBT tag" << name << "could not be converted to string.";
+ return nullopt;
}
}
-static int64_t read_long (nbt::value& parent, const char * name, const int64_t & fallback = 0)
+optional<int64_t> read_long (nbt::value& parent, const char * name)
{
try
{
auto &namedValue = parent.at(name);
if(namedValue.get_type() != nbt::tag_type::Long)
{
- return fallback;
+ return nullopt;
}
auto & tag_str = namedValue.as<nbt::tag_long>();
return tag_str.get();
@@ -312,25 +391,25 @@ static int64_t read_long (nbt::value& parent, const char * name, const int64_t &
catch (const std::out_of_range &e)
{
// fallback for old world formats
- qWarning() << "Long NBT tag" << name << "could not be found. Defaulting to" << fallback;
- return fallback;
+ qWarning() << "Long NBT tag" << name << "could not be found.";
+ return nullopt;
}
catch (const std::bad_cast &e)
{
// type mismatch
- qWarning() << "NBT tag" << name << "could not be converted to long. Defaulting to" << fallback;
- return fallback;
+ qWarning() << "NBT tag" << name << "could not be converted to long.";
+ return nullopt;
}
}
-static int read_int (nbt::value& parent, const char * name, const int & fallback = 0)
+optional<int> read_int (nbt::value& parent, const char * name)
{
try
{
auto &namedValue = parent.at(name);
if(namedValue.get_type() != nbt::tag_type::Int)
{
- return fallback;
+ return nullopt;
}
auto & tag_str = namedValue.as<nbt::tag_int>();
return tag_str.get();
@@ -338,62 +417,72 @@ static int read_int (nbt::value& parent, const char * name, const int & fallback
catch (const std::out_of_range &e)
{
// fallback for old world formats
- qWarning() << "Int NBT tag" << name << "could not be found. Defaulting to" << fallback;
- return fallback;
+ qWarning() << "Int NBT tag" << name << "could not be found.";
+ return nullopt;
}
catch (const std::bad_cast &e)
{
// type mismatch
- qWarning() << "NBT tag" << name << "could not be converted to int. Defaulting to" << fallback;
- return fallback;
+ qWarning() << "NBT tag" << name << "could not be converted to int.";
+ return nullopt;
}
}
+GameType read_gametype(nbt::value& parent, const char * name) {
+ return GameType(read_int(parent, name));
+}
+
+}
+
void World::loadFromLevelDat(QByteArray data)
{
- try
+ auto levelData = parseLevelDat(data);
+ if(!levelData)
{
- auto levelData = parseLevelDat(data);
- if(!levelData)
- {
- is_valid = false;
- return;
- }
-
- auto &val = levelData->at("Data");
- is_valid = val.get_type() == nbt::tag_type::Compound;
- if(!is_valid)
- return;
+ is_valid = false;
+ return;
+ }
- m_actualName = read_string(val, "LevelName", m_folderName);
+ nbt::value * valPtr = nullptr;
+ try {
+ valPtr = &levelData->at("Data");
+ }
+ catch (const std::out_of_range &e) {
+ qWarning() << "Unable to read NBT tags from " << m_folderName << ":" << e.what();
+ is_valid = false;
+ return;
+ }
+ nbt::value &val = *valPtr;
+ is_valid = val.get_type() == nbt::tag_type::Compound;
+ if(!is_valid)
+ return;
- int64_t temp = read_long(val, "LastPlayed", 0);
- if(temp == 0)
- {
- m_lastPlayed = levelDatTime;
- }
- else
- {
- m_lastPlayed = QDateTime::fromMSecsSinceEpoch(temp);
- }
+ auto name = read_string(val, "LevelName");
+ m_actualName = name ? *name : m_folderName;
- int GameType_val = read_int(val, "GameType", 0);
- m_gameType = (GameType) GameType_val;
+ auto timestamp = read_long(val, "LastPlayed");
+ m_lastPlayed = timestamp ? QDateTime::fromMSecsSinceEpoch(*timestamp) : levelDatTime;
- m_randomSeed = read_long(val, "RandomSeed", 0);
+ m_gameType = read_gametype(val, "GameType");
- qDebug() << "World Name:" << m_actualName;
- qDebug() << "Last Played:" << m_lastPlayed.toString();
- qDebug() << "Seed:" << m_randomSeed;
- qDebug() << "GameMode:" << GameType_val;
+ optional<int64_t> randomSeed;
+ try {
+ auto &WorldGen_val = val.at("WorldGenSettings");
+ randomSeed = read_long(WorldGen_val, "seed");
}
- catch (const nbt::io::input_error &e)
- {
- qWarning() << "Unable to load" << m_folderName << ":" << e.what();
- is_valid = false;
- return;
+ catch (const std::out_of_range &) {}
+ if(!randomSeed) {
+ randomSeed = read_long(val, "RandomSeed");
+ }
+ m_randomSeed = randomSeed ? *randomSeed : 0;
+
+ qDebug() << "World Name:" << m_actualName;
+ qDebug() << "Last Played:" << m_lastPlayed.toString();
+ if(randomSeed) {
+ qDebug() << "Seed:" << *randomSeed;
}
+ qDebug() << "GameType:" << m_gameType.toLogString();
}
bool World::replace(World &with)
diff --git a/api/logic/minecraft/World.h b/api/logic/minecraft/World.h
index 818701fa..1d94d54d 100644
--- a/api/logic/minecraft/World.h
+++ b/api/logic/minecraft/World.h
@@ -1,4 +1,4 @@
-/* Copyright 2015-2019 MultiMC Contributors
+/* Copyright 2015-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,17 +16,27 @@
#pragma once
#include <QFileInfo>
#include <QDateTime>
+#include <nonstd/optional>
#include "multimc_logic_export.h"
-enum class GameType
-{
- Survival,
- Creative,
- Adventure,
- Spectator
+struct MULTIMC_LOGIC_EXPORT GameType {
+ GameType() = default;
+ GameType (nonstd::optional<int> original);
+
+ QString toTranslatedString() const;
+ QString toLogString() const;
+
+ enum
+ {
+ Unknown = -1,
+ Survival = 0,
+ Creative,
+ Adventure,
+ Spectator
+ } type = Unknown;
+ nonstd::optional<int> original;
};
-QString MULTIMC_LOGIC_EXPORT gameTypeToString(GameType type);
class MULTIMC_LOGIC_EXPORT World
{
@@ -40,6 +50,10 @@ public:
{
return m_actualName;
}
+ QString iconFile() const
+ {
+ return m_iconFile;
+ }
QDateTime lastPlayed() const
{
return m_lastPlayed;
@@ -70,6 +84,8 @@ public:
bool replace(World &with);
// change the world's filesystem path (used by world lists for *MAGIC* purposes)
void repath(const QFileInfo &file);
+ // remove the icon file, if any
+ bool resetIcon();
bool rename(const QString &to);
bool install(const QString &to, const QString &name= QString());
@@ -88,9 +104,10 @@ protected:
QString m_containerOffsetPath;
QString m_folderName;
QString m_actualName;
+ QString m_iconFile;
QDateTime levelDatTime;
QDateTime m_lastPlayed;
int64_t m_randomSeed = 0;
- GameType m_gameType = GameType::Survival;
+ GameType m_gameType;
bool is_valid = false;
};
diff --git a/api/logic/minecraft/WorldList.cpp b/api/logic/minecraft/WorldList.cpp
index b7a24434..f6309dbd 100644
--- a/api/logic/minecraft/WorldList.cpp
+++ b/api/logic/minecraft/WorldList.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2015-2019 MultiMC Contributors
+/* Copyright 2015-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -136,6 +136,19 @@ bool WorldList::deleteWorlds(int first, int last)
return true;
}
+bool WorldList::resetIcon(int row)
+{
+ if (row >= worlds.size() || row < 0)
+ return false;
+ World &m = worlds[row];
+ if(m.resetIcon()) {
+ emit dataChanged(index(row), index(row), {WorldList::IconFileRole});
+ return true;
+ }
+ return false;
+}
+
+
int WorldList::columnCount(const QModelIndex &parent) const
{
return 3;
@@ -162,7 +175,7 @@ QVariant WorldList::data(const QModelIndex &index, int role) const
return world.name();
case GameModeColumn:
- return gameTypeToString(world.gameType());
+ return world.gameType().toTranslatedString();
case LastPlayedColumn:
return world.lastPlayed();
@@ -195,6 +208,10 @@ QVariant WorldList::data(const QModelIndex &index, int role) const
{
return world.lastPlayed();
}
+ case IconFileRole:
+ {
+ return world.iconFile();
+ }
default:
return QVariant();
}
diff --git a/api/logic/minecraft/WorldList.h b/api/logic/minecraft/WorldList.h
index 37ad330a..740b1461 100644
--- a/api/logic/minecraft/WorldList.h
+++ b/api/logic/minecraft/WorldList.h
@@ -1,4 +1,4 @@
-/* Copyright 2015-2019 MultiMC Contributors
+/* Copyright 2015-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,7 +44,8 @@ public:
SeedRole,
NameRole,
GameModeRole,
- LastPlayedRole
+ LastPlayedRole,
+ IconFileRole
};
WorldList(const QString &dir);
@@ -81,6 +82,9 @@ public:
/// Deletes the mod at the given index.
virtual bool deleteWorld(int index);
+ /// Removes the world icon, if any
+ virtual bool resetIcon(int index);
+
/// Deletes all the selected mods
virtual bool deleteWorlds(int first, int last);
diff --git a/api/logic/minecraft/auth/MojangAccount.cpp b/api/logic/minecraft/auth/MojangAccount.cpp
index 657e0009..f5853fe3 100644
--- a/api/logic/minecraft/auth/MojangAccount.cpp
+++ b/api/logic/minecraft/auth/MojangAccount.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
*
diff --git a/api/logic/minecraft/auth/MojangAccount.h b/api/logic/minecraft/auth/MojangAccount.h
index 7006435e..30a5f2ff 100644
--- a/api/logic/minecraft/auth/MojangAccount.h
+++ b/api/logic/minecraft/auth/MojangAccount.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/auth/MojangAccountList.cpp b/api/logic/minecraft/auth/MojangAccountList.cpp
index b594c652..e584cb3b 100644
--- a/api/logic/minecraft/auth/MojangAccountList.cpp
+++ b/api/logic/minecraft/auth/MojangAccountList.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/auth/MojangAccountList.h b/api/logic/minecraft/auth/MojangAccountList.h
index 7760b32f..cc3a61a2 100644
--- a/api/logic/minecraft/auth/MojangAccountList.h
+++ b/api/logic/minecraft/auth/MojangAccountList.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/auth/YggdrasilTask.cpp b/api/logic/minecraft/auth/YggdrasilTask.cpp
index 570fe1ea..0857b46b 100644
--- a/api/logic/minecraft/auth/YggdrasilTask.cpp
+++ b/api/logic/minecraft/auth/YggdrasilTask.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/auth/YggdrasilTask.h b/api/logic/minecraft/auth/YggdrasilTask.h
index c5352386..8af2e132 100644
--- a/api/logic/minecraft/auth/YggdrasilTask.h
+++ b/api/logic/minecraft/auth/YggdrasilTask.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/auth/flows/AuthenticateTask.cpp b/api/logic/minecraft/auth/flows/AuthenticateTask.cpp
index 8286c7a4..2e8dc859 100644
--- a/api/logic/minecraft/auth/flows/AuthenticateTask.cpp
+++ b/api/logic/minecraft/auth/flows/AuthenticateTask.cpp
@@ -1,5 +1,5 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/auth/flows/AuthenticateTask.h b/api/logic/minecraft/auth/flows/AuthenticateTask.h
index e95837a9..4c14eec7 100644
--- a/api/logic/minecraft/auth/flows/AuthenticateTask.h
+++ b/api/logic/minecraft/auth/flows/AuthenticateTask.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/auth/flows/RefreshTask.cpp b/api/logic/minecraft/auth/flows/RefreshTask.cpp
index 7a789f42..ecba178d 100644
--- a/api/logic/minecraft/auth/flows/RefreshTask.cpp
+++ b/api/logic/minecraft/auth/flows/RefreshTask.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/auth/flows/RefreshTask.h b/api/logic/minecraft/auth/flows/RefreshTask.h
index b2dfd261..f0840dda 100644
--- a/api/logic/minecraft/auth/flows/RefreshTask.h
+++ b/api/logic/minecraft/auth/flows/RefreshTask.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/auth/flows/ValidateTask.cpp b/api/logic/minecraft/auth/flows/ValidateTask.cpp
index 01f0f819..6b3f0a65 100644
--- a/api/logic/minecraft/auth/flows/ValidateTask.cpp
+++ b/api/logic/minecraft/auth/flows/ValidateTask.cpp
@@ -1,5 +1,5 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/auth/flows/ValidateTask.h b/api/logic/minecraft/auth/flows/ValidateTask.h
index dcb76b2b..986c2e9f 100644
--- a/api/logic/minecraft/auth/flows/ValidateTask.h
+++ b/api/logic/minecraft/auth/flows/ValidateTask.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/launch/ClaimAccount.h b/api/logic/minecraft/launch/ClaimAccount.h
index d0892981..c5bd75f3 100644
--- a/api/logic/minecraft/launch/ClaimAccount.h
+++ b/api/logic/minecraft/launch/ClaimAccount.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/launch/CreateGameFolders.cpp b/api/logic/minecraft/launch/CreateGameFolders.cpp
new file mode 100644
index 00000000..4081e72e
--- /dev/null
+++ b/api/logic/minecraft/launch/CreateGameFolders.cpp
@@ -0,0 +1,28 @@
+#include "CreateGameFolders.h"
+#include "minecraft/MinecraftInstance.h"
+#include "launch/LaunchTask.h"
+#include "FileSystem.h"
+
+CreateGameFolders::CreateGameFolders(LaunchTask* parent): LaunchStep(parent)
+{
+}
+
+void CreateGameFolders::executeTask()
+{
+ auto instance = m_parent->instance();
+ std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance);
+
+ if(!FS::ensureFolderPathExists(minecraftInstance->gameRoot()))
+ {
+ emit logLine("Couldn't create the main game folder", MessageLevel::Error);
+ emitFailed(tr("Couldn't create the main game folder"));
+ return;
+ }
+
+ // HACK: this is a workaround for MCL-3732 - 'server-resource-packs' folder is created.
+ if(!FS::ensureFolderPathExists(FS::PathCombine(minecraftInstance->gameRoot(), "server-resource-packs")))
+ {
+ emit logLine("Couldn't create the 'server-resource-packs' folder", MessageLevel::Error);
+ }
+ emitSucceeded();
+}
diff --git a/api/logic/minecraft/launch/CreateServerResourcePacksFolder.h b/api/logic/minecraft/launch/CreateGameFolders.h
index 00ab2f2d..9c7d3c94 100644
--- a/api/logic/minecraft/launch/CreateServerResourcePacksFolder.h
+++ b/api/logic/minecraft/launch/CreateGameFolders.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,13 +19,13 @@
#include <LoggedProcess.h>
#include <minecraft/auth/AuthSession.h>
-// HACK: this is a workaround for MCL-3732 - 'server-resource-packs' folder is created.
-class CreateServerResourcePacksFolder: public LaunchStep
+// Create the main .minecraft for the instance and any other necessary folders
+class CreateGameFolders: public LaunchStep
{
Q_OBJECT
public:
- explicit CreateServerResourcePacksFolder(LaunchTask *parent);
- virtual ~CreateServerResourcePacksFolder() {};
+ explicit CreateGameFolders(LaunchTask *parent);
+ virtual ~CreateGameFolders() {};
virtual void executeTask();
virtual bool canAbort() const
diff --git a/api/logic/minecraft/launch/CreateServerResourcePacksFolder.cpp b/api/logic/minecraft/launch/CreateServerResourcePacksFolder.cpp
deleted file mode 100644
index ae426e31..00000000
--- a/api/logic/minecraft/launch/CreateServerResourcePacksFolder.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "CreateServerResourcePacksFolder.h"
-#include "minecraft/MinecraftInstance.h"
-#include "launch/LaunchTask.h"
-#include "FileSystem.h"
-
-CreateServerResourcePacksFolder::CreateServerResourcePacksFolder(LaunchTask* parent): LaunchStep(parent)
-{
-}
-
-void CreateServerResourcePacksFolder::executeTask()
-{
- auto instance = m_parent->instance();
- std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance);
- if(!FS::ensureFolderPathExists(FS::PathCombine(minecraftInstance->gameRoot(), "server-resource-packs")))
- {
- emit logLine(tr("Couldn't create the 'server-resource-packs' folder"), MessageLevel::Error);
- }
- emitSucceeded();
-}
diff --git a/api/logic/minecraft/launch/DirectJavaLaunch.cpp b/api/logic/minecraft/launch/DirectJavaLaunch.cpp
index 5c2bb91e..2110384f 100644
--- a/api/logic/minecraft/launch/DirectJavaLaunch.cpp
+++ b/api/logic/minecraft/launch/DirectJavaLaunch.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -55,7 +55,7 @@ void DirectJavaLaunch::executeTask()
// make detachable - this will keep the process running even if the object is destroyed
m_process.setDetachable(true);
- auto mcArgs = minecraftInstance->processMinecraftArgs(m_session);
+ auto mcArgs = minecraftInstance->processMinecraftArgs(m_session, m_serverToJoin);
args.append(mcArgs);
QString wrapperCommandStr = instance->getWrapperCommand().trimmed();
@@ -66,9 +66,9 @@ void DirectJavaLaunch::executeTask()
auto realWrapperCommand = QStandardPaths::findExecutable(wrapperCommand);
if (realWrapperCommand.isEmpty())
{
- QString reason = tr("The wrapper command \"%1\" couldn't be found.").arg(wrapperCommand);
- emit logLine(reason, MessageLevel::Fatal);
- emitFailed(reason);
+ const char *reason = QT_TR_NOOP("The wrapper command \"%1\" couldn't be found.");
+ emit logLine(QString(reason).arg(wrapperCommand), MessageLevel::Fatal);
+ emitFailed(tr(reason).arg(wrapperCommand));
return;
}
emit logLine("Wrapper command is:\n" + wrapperCommandStr + "\n\n", MessageLevel::MultiMC);
@@ -87,18 +87,17 @@ void DirectJavaLaunch::on_state(LoggedProcess::State state)
{
case LoggedProcess::FailedToStart:
{
- //: Error message displayed if instace can't start
- QString reason = tr("Could not launch minecraft!");
+ //: Error message displayed if instance can't start
+ const char *reason = QT_TR_NOOP("Could not launch minecraft!");
emit logLine(reason, MessageLevel::Fatal);
- emitFailed(reason);
+ emitFailed(tr(reason));
return;
}
case LoggedProcess::Aborted:
case LoggedProcess::Crashed:
-
{
m_parent->setPid(-1);
- emitFailed("Game crashed.");
+ emitFailed(tr("Game crashed."));
return;
}
case LoggedProcess::Finished:
@@ -108,7 +107,7 @@ void DirectJavaLaunch::on_state(LoggedProcess::State state)
auto exitCode = m_process.exitCode();
if(exitCode != 0)
{
- emitFailed("Game crashed.");
+ emitFailed(tr("Game crashed."));
return;
}
//FIXME: make this work again
@@ -118,7 +117,7 @@ void DirectJavaLaunch::on_state(LoggedProcess::State state)
break;
}
case LoggedProcess::Running:
- emit logLine(tr("Minecraft process ID: %1\n\n").arg(m_process.processId()), MessageLevel::MultiMC);
+ emit logLine(QString("Minecraft process ID: %1\n\n").arg(m_process.processId()), MessageLevel::MultiMC);
m_parent->setPid(m_process.processId());
m_parent->instance()->setLastLaunch();
break;
diff --git a/api/logic/minecraft/launch/DirectJavaLaunch.h b/api/logic/minecraft/launch/DirectJavaLaunch.h
index 9f57272c..58b119b8 100644
--- a/api/logic/minecraft/launch/DirectJavaLaunch.h
+++ b/api/logic/minecraft/launch/DirectJavaLaunch.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,8 @@
#include <LoggedProcess.h>
#include <minecraft/auth/AuthSession.h>
+#include "MinecraftServerTarget.h"
+
class DirectJavaLaunch: public LaunchStep
{
Q_OBJECT
@@ -38,6 +40,12 @@ public:
{
m_session = session;
}
+
+ void setServerToJoin(MinecraftServerTargetPtr serverToJoin)
+ {
+ m_serverToJoin = std::move(serverToJoin);
+ }
+
private slots:
void on_state(LoggedProcess::State state);
@@ -45,5 +53,6 @@ private:
LoggedProcess m_process;
QString m_command;
AuthSessionPtr m_session;
+ MinecraftServerTargetPtr m_serverToJoin;
};
diff --git a/api/logic/minecraft/launch/ExtractNatives.cpp b/api/logic/minecraft/launch/ExtractNatives.cpp
index 253d13bc..d57499aa 100644
--- a/api/logic/minecraft/launch/ExtractNatives.cpp
+++ b/api/logic/minecraft/launch/ExtractNatives.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@ static QString replaceSuffix (QString target, const QString &suffix, const QStri
return target + replacement;
}
-static bool unzipNatives(QString source, QString targetFolder, bool applyJnilibHack)
+static bool unzipNatives(QString source, QString targetFolder, bool applyJnilibHack, bool nativeOpenAL, bool nativeGLFW)
{
QuaZip zip(source);
if(!zip.open(QuaZip::mdUnzip))
@@ -48,6 +48,13 @@ static bool unzipNatives(QString source, QString targetFolder, bool applyJnilibH
do
{
QString name = zip.getCurrentFileName();
+ auto lowercase = name.toLower();
+ if (nativeGLFW && name.contains("glfw")) {
+ continue;
+ }
+ if (nativeOpenAL && name.contains("openal")) {
+ continue;
+ }
if(applyJnilibHack)
{
name = replaceSuffix(name, ".jnilib", ".dylib");
@@ -76,16 +83,20 @@ void ExtractNatives::executeTask()
emitSucceeded();
return;
}
+ auto settings = minecraftInstance->settings();
+ bool nativeOpenAL = settings->get("UseNativeOpenAL").toBool();
+ bool nativeGLFW = settings->get("UseNativeGLFW").toBool();
+
auto outputPath = minecraftInstance->getNativePath();
auto javaVersion = minecraftInstance->getJavaVersion();
bool jniHackEnabled = javaVersion.major() >= 8;
for(const auto &source: toExtract)
{
- if(!unzipNatives(source, outputPath, jniHackEnabled))
+ if(!unzipNatives(source, outputPath, jniHackEnabled, nativeOpenAL, nativeGLFW))
{
- auto reason = tr("Couldn't extract native jar '%1' to destination '%2'").arg(source, outputPath);
- emit logLine(reason, MessageLevel::Fatal);
- emitFailed(reason);
+ const char *reason = QT_TR_NOOP("Couldn't extract native jar '%1' to destination '%2'");
+ emit logLine(QString(reason).arg(source, outputPath), MessageLevel::Fatal);
+ emitFailed(tr(reason).arg(source, outputPath));
}
}
emitSucceeded();
diff --git a/api/logic/minecraft/launch/ExtractNatives.h b/api/logic/minecraft/launch/ExtractNatives.h
index abb3bd7a..094fcd6b 100644
--- a/api/logic/minecraft/launch/ExtractNatives.h
+++ b/api/logic/minecraft/launch/ExtractNatives.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/launch/LauncherPartLaunch.cpp b/api/logic/minecraft/launch/LauncherPartLaunch.cpp
index e854a3a6..ee469770 100644
--- a/api/logic/minecraft/launch/LauncherPartLaunch.cpp
+++ b/api/logic/minecraft/launch/LauncherPartLaunch.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,7 +59,7 @@ void LauncherPartLaunch::executeTask()
auto instance = m_parent->instance();
std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance);
- m_launchScript = minecraftInstance->createLaunchScript(m_session);
+ m_launchScript = minecraftInstance->createLaunchScript(m_session, m_serverToJoin);
QStringList args = minecraftInstance->javaArguments();
QString allArgs = args.join(", ");
emit logLine("Java Arguments:\n[" + m_parent->censorPrivateInfo(allArgs) + "]\n\n", MessageLevel::MultiMC);
@@ -118,9 +118,9 @@ void LauncherPartLaunch::executeTask()
auto realWrapperCommand = QStandardPaths::findExecutable(wrapperCommand);
if (realWrapperCommand.isEmpty())
{
- QString reason = tr("The wrapper command \"%1\" couldn't be found.").arg(wrapperCommand);
- emit logLine(reason, MessageLevel::Fatal);
- emitFailed(reason);
+ const char *reason = QT_TR_NOOP("The wrapper command \"%1\" couldn't be found.");
+ emit logLine(QString(reason).arg(wrapperCommand), MessageLevel::Fatal);
+ emitFailed(tr(reason).arg(wrapperCommand));
return;
}
emit logLine("Wrapper command is:\n" + wrapperCommandStr + "\n\n", MessageLevel::MultiMC);
@@ -140,17 +140,16 @@ void LauncherPartLaunch::on_state(LoggedProcess::State state)
case LoggedProcess::FailedToStart:
{
//: Error message displayed if instace can't start
- QString reason = tr("Could not launch minecraft!");
+ const char *reason = QT_TR_NOOP("Could not launch minecraft!");
emit logLine(reason, MessageLevel::Fatal);
- emitFailed(reason);
+ emitFailed(tr(reason));
return;
}
case LoggedProcess::Aborted:
case LoggedProcess::Crashed:
-
{
m_parent->setPid(-1);
- emitFailed("Game crashed.");
+ emitFailed(tr("Game crashed."));
return;
}
case LoggedProcess::Finished:
@@ -160,7 +159,7 @@ void LauncherPartLaunch::on_state(LoggedProcess::State state)
auto exitCode = m_process.exitCode();
if(exitCode != 0)
{
- emitFailed("Game crashed.");
+ emitFailed(tr("Game crashed."));
return;
}
//FIXME: make this work again
@@ -170,7 +169,7 @@ void LauncherPartLaunch::on_state(LoggedProcess::State state)
break;
}
case LoggedProcess::Running:
- emit logLine(tr("Minecraft process ID: %1\n\n").arg(m_process.processId()), MessageLevel::MultiMC);
+ emit logLine(QString("Minecraft process ID: %1\n\n").arg(m_process.processId()), MessageLevel::MultiMC);
m_parent->setPid(m_process.processId());
m_parent->instance()->setLastLaunch();
// send the launch script to the launcher part
diff --git a/api/logic/minecraft/launch/LauncherPartLaunch.h b/api/logic/minecraft/launch/LauncherPartLaunch.h
index 1bc4a5f8..6a7ee0e5 100644
--- a/api/logic/minecraft/launch/LauncherPartLaunch.h
+++ b/api/logic/minecraft/launch/LauncherPartLaunch.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,8 @@
#include <LoggedProcess.h>
#include <minecraft/auth/AuthSession.h>
+#include "MinecraftServerTarget.h"
+
class LauncherPartLaunch: public LaunchStep
{
Q_OBJECT
@@ -39,6 +41,11 @@ public:
m_session = session;
}
+ void setServerToJoin(MinecraftServerTargetPtr serverToJoin)
+ {
+ m_serverToJoin = std::move(serverToJoin);
+ }
+
private slots:
void on_state(LoggedProcess::State state);
@@ -47,5 +54,7 @@ private:
QString m_command;
AuthSessionPtr m_session;
QString m_launchScript;
+ MinecraftServerTargetPtr m_serverToJoin;
+
bool mayProceed = false;
};
diff --git a/api/logic/minecraft/launch/MinecraftServerTarget.cpp b/api/logic/minecraft/launch/MinecraftServerTarget.cpp
new file mode 100644
index 00000000..569273b6
--- /dev/null
+++ b/api/logic/minecraft/launch/MinecraftServerTarget.cpp
@@ -0,0 +1,66 @@
+/* Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MinecraftServerTarget.h"
+
+#include <QStringList>
+
+MinecraftServerTarget MinecraftServerTarget::parse(const QString &fullAddress) {
+ QStringList split = fullAddress.split(":");
+
+ // The logic below replicates the exact logic minecraft uses for parsing server addresses.
+ // While the conversion is not lossless and eats errors, it ensures the same behavior
+ // within Minecraft and MultiMC when entering server addresses.
+ if (fullAddress.startsWith("["))
+ {
+ int bracket = fullAddress.indexOf("]");
+ if (bracket > 0)
+ {
+ QString ipv6 = fullAddress.mid(1, bracket - 1);
+ QString port = fullAddress.mid(bracket + 1).trimmed();
+
+ if (port.startsWith(":") && !ipv6.isEmpty())
+ {
+ port = port.mid(1);
+ split = QStringList({ ipv6, port });
+ }
+ else
+ {
+ split = QStringList({ipv6});
+ }
+ }
+ }
+
+ if (split.size() > 2)
+ {
+ split = QStringList({fullAddress});
+ }
+
+ QString realAddress = split[0];
+
+ quint16 realPort = 25565;
+ if (split.size() > 1)
+ {
+ bool ok;
+ realPort = split[1].toUInt(&ok);
+
+ if (!ok)
+ {
+ realPort = 25565;
+ }
+ }
+
+ return MinecraftServerTarget { realAddress, realPort };
+}
diff --git a/api/logic/minecraft/launch/MinecraftServerTarget.h b/api/logic/minecraft/launch/MinecraftServerTarget.h
new file mode 100644
index 00000000..3c5786f4
--- /dev/null
+++ b/api/logic/minecraft/launch/MinecraftServerTarget.h
@@ -0,0 +1,30 @@
+/* Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <QString>
+#include <multimc_logic_export.h>
+
+struct MinecraftServerTarget {
+ QString address;
+ quint16 port;
+
+ static MULTIMC_LOGIC_EXPORT MinecraftServerTarget parse(const QString &fullAddress);
+};
+
+typedef std::shared_ptr<MinecraftServerTarget> MinecraftServerTargetPtr;
diff --git a/api/logic/minecraft/launch/ModMinecraftJar.cpp b/api/logic/minecraft/launch/ModMinecraftJar.cpp
index ba43a68d..93de9d59 100644
--- a/api/logic/minecraft/launch/ModMinecraftJar.cpp
+++ b/api/logic/minecraft/launch/ModMinecraftJar.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/launch/ModMinecraftJar.h b/api/logic/minecraft/launch/ModMinecraftJar.h
index bed5079f..081c6a91 100644
--- a/api/logic/minecraft/launch/ModMinecraftJar.h
+++ b/api/logic/minecraft/launch/ModMinecraftJar.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/launch/PrintInstanceInfo.cpp b/api/logic/minecraft/launch/PrintInstanceInfo.cpp
index 4cc180fd..0b9611ad 100644
--- a/api/logic/minecraft/launch/PrintInstanceInfo.cpp
+++ b/api/logic/minecraft/launch/PrintInstanceInfo.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -101,6 +101,6 @@ void PrintInstanceInfo::executeTask()
#endif
logLines(log, MessageLevel::MultiMC);
- logLines(instance->verboseDescription(m_session), MessageLevel::MultiMC);
+ logLines(instance->verboseDescription(m_session, m_serverToJoin), MessageLevel::MultiMC);
emitSucceeded();
}
diff --git a/api/logic/minecraft/launch/PrintInstanceInfo.h b/api/logic/minecraft/launch/PrintInstanceInfo.h
index 1d081f3e..fdc30f31 100644
--- a/api/logic/minecraft/launch/PrintInstanceInfo.h
+++ b/api/logic/minecraft/launch/PrintInstanceInfo.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,13 +18,15 @@
#include <launch/LaunchStep.h>
#include <memory>
#include "minecraft/auth/AuthSession.h"
+#include "minecraft/launch/MinecraftServerTarget.h"
// FIXME: temporary wrapper for existing task.
class PrintInstanceInfo: public LaunchStep
{
Q_OBJECT
public:
- explicit PrintInstanceInfo(LaunchTask *parent, AuthSessionPtr session) : LaunchStep(parent), m_session(session) {};
+ explicit PrintInstanceInfo(LaunchTask *parent, AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) :
+ LaunchStep(parent), m_session(session), m_serverToJoin(serverToJoin) {};
virtual ~PrintInstanceInfo(){};
virtual void executeTask();
@@ -34,5 +36,6 @@ public:
}
private:
AuthSessionPtr m_session;
+ MinecraftServerTargetPtr m_serverToJoin;
};
diff --git a/api/logic/minecraft/launch/ReconstructAssets.cpp b/api/logic/minecraft/launch/ReconstructAssets.cpp
index 3ac320bd..4d206665 100644
--- a/api/logic/minecraft/launch/ReconstructAssets.cpp
+++ b/api/logic/minecraft/launch/ReconstructAssets.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/launch/ReconstructAssets.h b/api/logic/minecraft/launch/ReconstructAssets.h
index 228fa083..58d7febd 100644
--- a/api/logic/minecraft/launch/ReconstructAssets.h
+++ b/api/logic/minecraft/launch/ReconstructAssets.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/launch/ScanModFolders.cpp b/api/logic/minecraft/launch/ScanModFolders.cpp
index 485c3dc4..2a0e21b3 100644
--- a/api/logic/minecraft/launch/ScanModFolders.cpp
+++ b/api/logic/minecraft/launch/ScanModFolders.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,11 +27,16 @@ void ScanModFolders::executeTask()
auto loaders = m_inst->loaderModList();
connect(loaders.get(), &ModFolderModel::updateFinished, this, &ScanModFolders::modsDone);
- loaders->update();
+ if(!loaders->update()) {
+ m_modsDone = true;
+ }
auto cores = m_inst->coreModList();
connect(cores.get(), &ModFolderModel::updateFinished, this, &ScanModFolders::coreModsDone);
- cores->update();
+ if(!cores->update()) {
+ m_coreModsDone = true;
+ }
+ checkDone();
}
void ScanModFolders::modsDone()
diff --git a/api/logic/minecraft/launch/ScanModFolders.h b/api/logic/minecraft/launch/ScanModFolders.h
index 360df98d..d5989170 100644
--- a/api/logic/minecraft/launch/ScanModFolders.h
+++ b/api/logic/minecraft/launch/ScanModFolders.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/launch/VerifyJavaInstall.cpp b/api/logic/minecraft/launch/VerifyJavaInstall.cpp
new file mode 100644
index 00000000..657669af
--- /dev/null
+++ b/api/logic/minecraft/launch/VerifyJavaInstall.cpp
@@ -0,0 +1,34 @@
+#include "VerifyJavaInstall.h"
+
+#include <launch/LaunchTask.h>
+#include <minecraft/MinecraftInstance.h>
+#include <minecraft/PackProfile.h>
+#include <minecraft/VersionFilterData.h>
+
+void VerifyJavaInstall::executeTask() {
+ auto m_inst = std::dynamic_pointer_cast<MinecraftInstance>(m_parent->instance());
+
+ auto javaVersion = m_inst->getJavaVersion();
+ auto minecraftComponent = m_inst->getPackProfile()->getComponent("net.minecraft");
+
+ // Java 16 requirement
+ if (minecraftComponent->getReleaseDateTime() >= g_VersionFilterData.java16BeginsDate) {
+ if (javaVersion.major() < 16) {
+ emit logLine("Minecraft 21w19a and above require the use of Java 16",
+ MessageLevel::Fatal);
+ emitFailed(tr("Minecraft 21w19a and above require the use of Java 16"));
+ return;
+ }
+ }
+ // Java 8 requirement
+ else if (minecraftComponent->getReleaseDateTime() >= g_VersionFilterData.java8BeginsDate) {
+ if (javaVersion.major() < 8) {
+ emit logLine("Minecraft 17w13a and above require the use of Java 8",
+ MessageLevel::Fatal);
+ emitFailed(tr("Minecraft 17w13a and above require the use of Java 8"));
+ return;
+ }
+ }
+
+ emitSucceeded();
+}
diff --git a/api/logic/minecraft/launch/VerifyJavaInstall.h b/api/logic/minecraft/launch/VerifyJavaInstall.h
new file mode 100644
index 00000000..a553106d
--- /dev/null
+++ b/api/logic/minecraft/launch/VerifyJavaInstall.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <launch/LaunchStep.h>
+
+class VerifyJavaInstall : public LaunchStep {
+ Q_OBJECT
+
+public:
+ explicit VerifyJavaInstall(LaunchTask *parent) : LaunchStep(parent) {
+ };
+ ~VerifyJavaInstall() override = default;
+
+ void executeTask() override;
+ bool canAbort() const override {
+ return false;
+ }
+};
diff --git a/api/logic/minecraft/legacy/LegacyInstance.cpp b/api/logic/minecraft/legacy/LegacyInstance.cpp
index b9d68a9c..9f9bda5a 100644
--- a/api/logic/minecraft/legacy/LegacyInstance.cpp
+++ b/api/logic/minecraft/legacy/LegacyInstance.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -225,7 +225,7 @@ QString LegacyInstance::getStatusbarDescription()
return tr("Instance from previous versions.");
}
-QStringList LegacyInstance::verboseDescription(AuthSessionPtr session)
+QStringList LegacyInstance::verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
{
QStringList out;
diff --git a/api/logic/minecraft/legacy/LegacyInstance.h b/api/logic/minecraft/legacy/LegacyInstance.h
index 7c0b94e8..325bac7a 100644
--- a/api/logic/minecraft/legacy/LegacyInstance.h
+++ b/api/logic/minecraft/legacy/LegacyInstance.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -111,7 +111,8 @@ public:
{
return false;
}
- shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account) override
+ shared_qobject_ptr<LaunchTask> createLaunchTask(
+ AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) override
{
return nullptr;
}
@@ -125,7 +126,7 @@ public:
}
QString getStatusbarDescription() override;
- QStringList verboseDescription(AuthSessionPtr session) override;
+ QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override;
QProcessEnvironment createEnvironment() override
{
diff --git a/api/logic/minecraft/legacy/LegacyModList.cpp b/api/logic/minecraft/legacy/LegacyModList.cpp
index 23b837c1..7301eb8c 100644
--- a/api/logic/minecraft/legacy/LegacyModList.cpp
+++ b/api/logic/minecraft/legacy/LegacyModList.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/legacy/LegacyModList.h b/api/logic/minecraft/legacy/LegacyModList.h
index 9a7bea50..8881d471 100644
--- a/api/logic/minecraft/legacy/LegacyModList.h
+++ b/api/logic/minecraft/legacy/LegacyModList.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/mod/LocalModParseTask.cpp b/api/logic/minecraft/mod/LocalModParseTask.cpp
index 22ebd7d4..0d6972fb 100644
--- a/api/logic/minecraft/mod/LocalModParseTask.cpp
+++ b/api/logic/minecraft/mod/LocalModParseTask.cpp
@@ -6,6 +6,7 @@
#include <QJsonValue>
#include <quazip.h>
#include <quazipfile.h>
+#include <toml.h>
#include "settings/INIFile.h"
#include "FileSystem.h"
@@ -90,6 +91,124 @@ std::shared_ptr<ModDetails> ReadMCModInfo(QByteArray contents)
return nullptr;
}
+// https://github.com/MinecraftForge/Documentation/blob/5ab4ba6cf9abc0ac4c0abd96ad187461aefd72af/docs/gettingstarted/structuring.md
+std::shared_ptr<ModDetails> ReadMCModTOML(QByteArray contents)
+{
+ std::shared_ptr<ModDetails> details = std::make_shared<ModDetails>();
+
+ char errbuf[200];
+ // top-level table
+ toml_table_t* tomlData = toml_parse(contents.data(), errbuf, sizeof(errbuf));
+
+ if(!tomlData)
+ {
+ return nullptr;
+ }
+
+ // array defined by [[mods]]
+ toml_array_t* tomlModsArr = toml_array_in(tomlData, "mods");
+ // we only really care about the first element, since multiple mods in one file is not supported by us at the moment
+ toml_table_t* tomlModsTable0 = toml_table_at(tomlModsArr, 0);
+
+ // mandatory properties - always in [[mods]]
+ toml_datum_t modIdDatum = toml_string_in(tomlModsTable0, "modId");
+ if(modIdDatum.ok)
+ {
+ details->mod_id = modIdDatum.u.s;
+ // library says this is required for strings
+ free(modIdDatum.u.s);
+ }
+ toml_datum_t versionDatum = toml_string_in(tomlModsTable0, "version");
+ if(versionDatum.ok)
+ {
+ details->version = versionDatum.u.s;
+ free(versionDatum.u.s);
+ }
+ toml_datum_t displayNameDatum = toml_string_in(tomlModsTable0, "displayName");
+ if(displayNameDatum.ok)
+ {
+ details->name = displayNameDatum.u.s;
+ free(displayNameDatum.u.s);
+ }
+ toml_datum_t descriptionDatum = toml_string_in(tomlModsTable0, "description");
+ if(descriptionDatum.ok)
+ {
+ details->description = descriptionDatum.u.s;
+ free(descriptionDatum.u.s);
+ }
+
+ // optional properties - can be in the root table or [[mods]]
+ toml_datum_t authorsDatum = toml_string_in(tomlData, "authors");
+ QString authors = "";
+ if(authorsDatum.ok)
+ {
+ authors = authorsDatum.u.s;
+ free(authorsDatum.u.s);
+ }
+ else
+ {
+ authorsDatum = toml_string_in(tomlModsTable0, "authors");
+ if(authorsDatum.ok)
+ {
+ authors = authorsDatum.u.s;
+ free(authorsDatum.u.s);
+ }
+ }
+ if(!authors.isEmpty())
+ {
+ // author information is stored as a string now, not a list
+ details->authors.append(authors);
+ }
+ // is credits even used anywhere? including this for completion/parity with old data version
+ toml_datum_t creditsDatum = toml_string_in(tomlData, "credits");
+ QString credits = "";
+ if(creditsDatum.ok)
+ {
+ authors = creditsDatum.u.s;
+ free(creditsDatum.u.s);
+ }
+ else
+ {
+ creditsDatum = toml_string_in(tomlModsTable0, "credits");
+ if(creditsDatum.ok)
+ {
+ credits = creditsDatum.u.s;
+ free(creditsDatum.u.s);
+ }
+ }
+ details->credits = credits;
+ toml_datum_t homeurlDatum = toml_string_in(tomlData, "displayURL");
+ QString homeurl = "";
+ if(homeurlDatum.ok)
+ {
+ homeurl = homeurlDatum.u.s;
+ free(homeurlDatum.u.s);
+ }
+ else
+ {
+ homeurlDatum = toml_string_in(tomlModsTable0, "displayURL");
+ if(homeurlDatum.ok)
+ {
+ homeurl = homeurlDatum.u.s;
+ free(homeurlDatum.u.s);
+ }
+ }
+ if(!homeurl.isEmpty())
+ {
+ // fix up url.
+ if (!homeurl.startsWith("http://") && !homeurl.startsWith("https://") && !homeurl.startsWith("ftp://"))
+ {
+ homeurl.prepend("http://");
+ }
+ }
+ details->homeurl = homeurl;
+
+ // this seems to be recursive, so it should free everything
+ toml_free(tomlData);
+
+ return details;
+}
+
// https://fabricmc.net/wiki/documentation:fabric_mod_json
std::shared_ptr<ModDetails> ReadFabricModInfo(QByteArray contents)
{
@@ -198,7 +317,57 @@ void LocalModParseTask::processAsZip()
QuaZipFile file(&zip);
- if (zip.setCurrentFile("mcmod.info"))
+ if (zip.setCurrentFile("META-INF/mods.toml"))
+ {
+ if (!file.open(QIODevice::ReadOnly))
+ {
+ zip.close();
+ return;
+ }
+
+ m_result->details = ReadMCModTOML(file.readAll());
+ file.close();
+
+ // to replace ${file.jarVersion} with the actual version, as needed
+ if (m_result->details && m_result->details->version == "${file.jarVersion}")
+ {
+ if (zip.setCurrentFile("META-INF/MANIFEST.MF"))
+ {
+ if (!file.open(QIODevice::ReadOnly))
+ {
+ zip.close();
+ return;
+ }
+
+ // quick and dirty line-by-line parser
+ auto manifestLines = file.readAll().split('\n');
+ QString manifestVersion = "";
+ for (auto &line : manifestLines)
+ {
+ if (QString(line).startsWith("Implementation-Version: "))
+ {
+ manifestVersion = QString(line).remove("Implementation-Version: ");
+ break;
+ }
+ }
+
+ // some mods use ${projectversion} in their build.gradle, causing this mess to show up in MANIFEST.MF
+ // also keep with forge's behavior of setting the version to "NONE" if none is found
+ if (manifestVersion.contains("task ':jar' property 'archiveVersion'") || manifestVersion == "")
+ {
+ manifestVersion = "NONE";
+ }
+
+ m_result->details->version = manifestVersion;
+
+ file.close();
+ }
+ }
+
+ zip.close();
+ return;
+ }
+ else if (zip.setCurrentFile("mcmod.info"))
{
if (!file.open(QIODevice::ReadOnly))
{
diff --git a/api/logic/minecraft/mod/Mod.cpp b/api/logic/minecraft/mod/Mod.cpp
index df8b406d..b6bff29b 100644
--- a/api/logic/minecraft/mod/Mod.cpp
+++ b/api/logic/minecraft/mod/Mod.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/mod/Mod.h b/api/logic/minecraft/mod/Mod.h
index d787fb48..f77ffd41 100644
--- a/api/logic/minecraft/mod/Mod.h
+++ b/api/logic/minecraft/mod/Mod.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/mod/ModFolderModel.cpp b/api/logic/minecraft/mod/ModFolderModel.cpp
index 59ccaaba..031eebe5 100644
--- a/api/logic/minecraft/mod/ModFolderModel.cpp
+++ b/api/logic/minecraft/mod/ModFolderModel.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/mod/ModFolderModel.h b/api/logic/minecraft/mod/ModFolderModel.h
index 03c584a9..b0a76121 100644
--- a/api/logic/minecraft/mod/ModFolderModel.h
+++ b/api/logic/minecraft/mod/ModFolderModel.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2019 MultiMC Contributors
+/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/api/logic/minecraft/mod/ResourcePackFolderModel.cpp b/api/logic/minecraft/mod/ResourcePackFolderModel.cpp
new file mode 100644
index 00000000..f3d7f566
--- /dev/null
+++ b/api/logic/minecraft/mod/ResourcePackFolderModel.cpp
@@ -0,0 +1,23 @@
+#include "ResourcePackFolderModel.h"
+
+ResourcePackFolderModel::ResourcePackFolderModel(const QString &dir) : ModFolderModel(dir) {
+}
+
+QVariant ResourcePackFolderModel::headerData(int section, Qt::Orientation orientation, int role) const {
+ if (role == Qt::ToolTipRole) {
+ switch (section) {
+ case ActiveColumn:
+ return tr("Is the resource pack enabled?");
+ case NameColumn:
+ return tr("The name of the resource pack.");
+ case VersionColumn:
+ return tr("The version of the resource pack.");
+ case DateColumn:
+ return tr("The date and time this resource pack was last changed (or added).");
+ default:
+ return QVariant();
+ }
+ }
+
+ return ModFolderModel::headerData(section, orientation, role);
+}
diff --git a/api/logic/minecraft/mod/ResourcePackFolderModel.h b/api/logic/minecraft/mod/ResourcePackFolderModel.h
new file mode 100644
index 00000000..47eb4bb2
--- /dev/null
+++ b/api/logic/minecraft/mod/ResourcePackFolderModel.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "ModFolderModel.h"
+
+class MULTIMC_LOGIC_EXPORT ResourcePackFolderModel : public ModFolderModel
+{
+ Q_OBJECT
+
+public:
+ explicit ResourcePackFolderModel(const QString &dir);
+
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+};
diff --git a/api/logic/minecraft/mod/TexturePackFolderModel.cpp b/api/logic/minecraft/mod/TexturePackFolderModel.cpp
new file mode 100644
index 00000000..d5956da1
--- /dev/null
+++ b/api/logic/minecraft/mod/TexturePackFolderModel.cpp
@@ -0,0 +1,23 @@
+#include "TexturePackFolderModel.h"
+
+TexturePackFolderModel::TexturePackFolderModel(const QString &dir) : ModFolderModel(dir) {
+}
+
+QVariant TexturePackFolderModel::headerData(int section, Qt::Orientation orientation, int role) const {
+ if (role == Qt::ToolTipRole) {
+ switch (section) {
+ case ActiveColumn:
+ return tr("Is the texture pack enabled?");
+ case NameColumn:
+ return tr("The name of the texture pack.");
+ case VersionColumn:
+ return tr("The version of the texture pack.");
+ case DateColumn:
+ return tr("The date and time this texture pack was last changed (or added).");
+ default:
+ return QVariant();
+ }
+ }
+
+ return ModFolderModel::headerData(section, orientation, role);
+}
diff --git a/api/logic/minecraft/mod/TexturePackFolderModel.h b/api/logic/minecraft/mod/TexturePackFolderModel.h
new file mode 100644
index 00000000..d773b17b
--- /dev/null
+++ b/api/logic/minecraft/mod/TexturePackFolderModel.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "ModFolderModel.h"
+
+class MULTIMC_LOGIC_EXPORT TexturePackFolderModel : public ModFolderModel
+{
+ Q_OBJECT
+
+public:
+ explicit TexturePackFolderModel(const QString &dir);
+
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+};
diff --git a/api/logic/minecraft/services/SkinDelete.cpp b/api/logic/minecraft/services/SkinDelete.cpp
new file mode 100644
index 00000000..34977257
--- /dev/null
+++ b/api/logic/minecraft/services/SkinDelete.cpp
@@ -0,0 +1,42 @@
+#include "SkinDelete.h"
+#include <QNetworkRequest>
+#include <QHttpMultiPart>
+#include <Env.h>
+
+SkinDelete::SkinDelete(QObject *parent, AuthSessionPtr session)
+ : Task(parent), m_session(session)
+{
+}
+
+void SkinDelete::executeTask()
+{
+ QNetworkRequest request(QUrl("https://api.minecraftservices.com/minecraft/profile/skins/active"));
+ request.setRawHeader("Authorization", QString("Bearer %1").arg(m_session->access_token).toLocal8Bit());
+ QNetworkReply *rep = ENV.qnam().deleteResource(request);
+ m_reply = std::shared_ptr<QNetworkReply>(rep);
+
+ setStatus(tr("Deleting skin"));
+ connect(rep, &QNetworkReply::uploadProgress, this, &Task::setProgress);
+ connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError)));
+ connect(rep, SIGNAL(finished()), this, SLOT(downloadFinished()));
+}
+
+void SkinDelete::downloadError(QNetworkReply::NetworkError error)
+{
+ // error happened during download.
+ qCritical() << "Network error: " << error;
+ emitFailed(m_reply->errorString());
+}
+
+void SkinDelete::downloadFinished()
+{
+ // if the download failed
+ if (m_reply->error() != QNetworkReply::NetworkError::NoError)
+ {
+ emitFailed(QString("Network error: %1").arg(m_reply->errorString()));
+ m_reply.reset();
+ return;
+ }
+ emitSucceeded();
+}
+
diff --git a/api/logic/minecraft/services/SkinDelete.h b/api/logic/minecraft/services/SkinDelete.h
new file mode 100644
index 00000000..705ce8ef
--- /dev/null
+++ b/api/logic/minecraft/services/SkinDelete.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <QFile>
+#include <QtNetwork/QtNetwork>
+#include <memory>
+#include <minecraft/auth/AuthSession.h>
+#include "tasks/Task.h"
+#include "multimc_logic_export.h"
+
+typedef std::shared_ptr<class SkinDelete> SkinDeletePtr;
+
+class MULTIMC_LOGIC_EXPORT SkinDelete : public Task
+{
+ Q_OBJECT
+public:
+ SkinDelete(QObject *parent, AuthSessionPtr session);
+ virtual ~SkinDelete() = default;
+
+private:
+ AuthSessionPtr m_session;
+ std::shared_ptr<QNetworkReply> m_reply;
+
+protected:
+ virtual void executeTask();
+
+public slots:
+ void downloadError(QNetworkReply::NetworkError);
+ void downloadFinished();
+};
+
diff --git a/api/logic/minecraft/SkinUpload.cpp b/api/logic/minecraft/services/SkinUpload.cpp
index 83bdf592..4e5a1698 100644
--- a/api/logic/minecraft/SkinUpload.cpp
+++ b/api/logic/minecraft/services/SkinUpload.cpp
@@ -3,15 +3,14 @@
#include <QHttpMultiPart>
#include <Env.h>
-QByteArray getModelString(SkinUpload::Model model) {
+QByteArray getVariant(SkinUpload::Model model) {
switch (model) {
- case SkinUpload::STEVE:
- return "";
- case SkinUpload::ALEX:
- return "slim";
default:
qDebug() << "Unknown skin type!";
- return "";
+ case SkinUpload::STEVE:
+ return "CLASSIC";
+ case SkinUpload::ALEX:
+ return "SLIM";
}
}
@@ -22,25 +21,23 @@ SkinUpload::SkinUpload(QObject *parent, AuthSessionPtr session, QByteArray skin,
void SkinUpload::executeTask()
{
- QNetworkRequest request(QUrl(QString("https://api.mojang.com/user/profile/%1/skin").arg(m_session->uuid)));
- request.setRawHeader("Authorization", QString("Bearer: %1").arg(m_session->access_token).toLocal8Bit());
-
+ QNetworkRequest request(QUrl("https://api.minecraftservices.com/minecraft/profile/skins"));
+ request.setRawHeader("Authorization", QString("Bearer %1").arg(m_session->access_token).toLocal8Bit());
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
- QHttpPart model;
- model.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"model\""));
- model.setBody(getModelString(m_model));
-
QHttpPart skin;
skin.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/png"));
- skin.setHeader(QNetworkRequest::ContentDispositionHeader,
- QVariant("form-data; name=\"file\"; filename=\"skin.png\""));
+ skin.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"file\"; filename=\"skin.png\""));
skin.setBody(m_skin);
- multiPart->append(model);
+ QHttpPart model;
+ model.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"variant\""));
+ model.setBody(getVariant(m_model));
+
multiPart->append(skin);
+ multiPart->append(model);
- QNetworkReply *rep = ENV.qnam().put(request, multiPart);
+ QNetworkReply *rep = ENV.qnam().post(request, multiPart);
m_reply = std::shared_ptr<QNetworkReply>(rep);
setStatus(tr("Uploading skin"));
diff --git a/api/logic/minecraft/SkinUpload.h b/api/logic/minecraft/services/SkinUpload.h
index c77abb03..c77abb03 100644
--- a/api/logic/minecraft/SkinUpload.h
+++ b/api/logic/minecraft/services/SkinUpload.h
diff --git a/api/logic/minecraft/update/FMLLibrariesTask.cpp b/api/logic/minecraft/update/FMLLibrariesTask.cpp
index 85993e81..a05a7c2a 100644
--- a/api/logic/minecraft/update/FMLLibrariesTask.cpp
+++ b/api/logic/minecraft/update/FMLLibrariesTask.cpp
@@ -64,7 +64,7 @@ void FMLLibrariesTask::executeTask()
for (auto &lib : fmlLibsToProcess)
{
auto entry = metacache->resolveEntry("fmllibs", lib.filename);
- QString urlString = (lib.ours ? BuildConfig.FMLLIBS_OUR_BASE_URL : BuildConfig.FMLLIBS_FORGE_BASE_URL) + lib.filename;
+ QString urlString = BuildConfig.FMLLIBS_BASE_URL + lib.filename;
dljob->addNetAction(Net::Download::makeCached(QUrl(urlString), entry));
}