aboutsummaryrefslogtreecommitdiff
path: root/launcher
diff options
context:
space:
mode:
Diffstat (limited to 'launcher')
-rw-r--r--launcher/Application.cpp1
-rw-r--r--launcher/CMakeLists.txt4
-rw-r--r--launcher/java/JavaChecker.cpp2
-rw-r--r--launcher/java/JavaInstallList.cpp2
-rw-r--r--launcher/launch/steps/CheckJava.cpp6
-rw-r--r--launcher/minecraft/Agent.h36
-rw-r--r--launcher/minecraft/LaunchProfile.cpp78
-rw-r--r--launcher/minecraft/LaunchProfile.h54
-rw-r--r--launcher/minecraft/MinecraftInstance.cpp12
-rw-r--r--launcher/minecraft/MojangVersionFormat.cpp44
-rw-r--r--launcher/minecraft/OneSixVersionFormat.cpp24
-rw-r--r--launcher/minecraft/VersionFile.cpp41
-rw-r--r--launcher/minecraft/VersionFile.h45
-rw-r--r--launcher/minecraft/World.cpp23
-rw-r--r--launcher/minecraft/World.h5
-rw-r--r--launcher/minecraft/WorldList.cpp18
-rw-r--r--launcher/minecraft/WorldList.h4
-rw-r--r--launcher/minecraft/launch/VerifyJavaInstall.cpp109
-rw-r--r--launcher/minecraft/launch/VerifyJavaInstall.h36
-rw-r--r--launcher/minecraft/update/LibrariesTask.cpp4
-rw-r--r--launcher/modplatform/modrinth/ModrinthPackIndex.cpp8
-rw-r--r--launcher/modplatform/technic/SolderPackInstallTask.cpp137
-rw-r--r--launcher/modplatform/technic/SolderPackInstallTask.h47
-rw-r--r--launcher/modplatform/technic/SolderPackManifest.cpp58
-rw-r--r--launcher/modplatform/technic/SolderPackManifest.h49
-rw-r--r--launcher/tasks/SequentialTask.cpp50
-rw-r--r--launcher/tasks/SequentialTask.h28
-rw-r--r--launcher/tasks/Task.h68
-rw-r--r--launcher/ui/dialogs/AboutDialog.ui2
-rw-r--r--launcher/ui/dialogs/ProgressDialog.cpp22
-rw-r--r--launcher/ui/dialogs/ProgressDialog.h5
-rw-r--r--launcher/ui/dialogs/ProgressDialog.ui45
-rw-r--r--launcher/ui/dialogs/UpdateDialog.ui2
-rw-r--r--launcher/ui/pages/global/JavaPage.cpp3
-rw-r--r--launcher/ui/pages/global/JavaPage.ui16
-rw-r--r--launcher/ui/pages/global/MinecraftPage.ui8
-rw-r--r--launcher/ui/pages/instance/InstanceSettingsPage.cpp3
-rw-r--r--launcher/ui/pages/instance/InstanceSettingsPage.ui10
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.cpp37
-rw-r--r--launcher/ui/pages/modplatform/technic/TechnicData.h46
-rw-r--r--launcher/ui/pages/modplatform/technic/TechnicModel.cpp130
-rw-r--r--launcher/ui/pages/modplatform/technic/TechnicModel.h44
-rw-r--r--launcher/ui/pages/modplatform/technic/TechnicPage.cpp143
-rw-r--r--launcher/ui/pages/modplatform/technic/TechnicPage.h11
-rw-r--r--launcher/ui/pages/modplatform/technic/TechnicPage.ui132
-rw-r--r--launcher/ui/widgets/CustomCommands.ui2
46 files changed, 1283 insertions, 371 deletions
diff --git a/launcher/Application.cpp b/launcher/Application.cpp
index 91b7b82c..690a7ee4 100644
--- a/launcher/Application.cpp
+++ b/launcher/Application.cpp
@@ -682,6 +682,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_settings->registerSetting("JavaVendor", "");
m_settings->registerSetting("LastHostname", "");
m_settings->registerSetting("JvmArgs", "");
+ m_settings->registerSetting("IgnoreJavaCompatibility", false);
// Native library workarounds
m_settings->registerSetting("UseNativeOpenAL", false);
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index 692aebe5..05af3503 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -348,7 +348,7 @@ set(MINECRAFT_SOURCES
mojang/PackageManifest.h
mojang/PackageManifest.cpp
- )
+ minecraft/Agent.h)
add_unit_test(GradleSpecifier
SOURCES minecraft/GradleSpecifier_test.cpp
@@ -539,6 +539,8 @@ set(TECHNIC_SOURCES
modplatform/technic/SingleZipPackInstallTask.cpp
modplatform/technic/SolderPackInstallTask.h
modplatform/technic/SolderPackInstallTask.cpp
+ modplatform/technic/SolderPackManifest.h
+ modplatform/technic/SolderPackManifest.cpp
modplatform/technic/TechnicPackProcessor.h
modplatform/technic/TechnicPackProcessor.cpp
)
diff --git a/launcher/java/JavaChecker.cpp b/launcher/java/JavaChecker.cpp
index 35ddc35c..946599c5 100644
--- a/launcher/java/JavaChecker.cpp
+++ b/launcher/java/JavaChecker.cpp
@@ -129,7 +129,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
auto os_arch = results["os.arch"];
auto java_version = results["java.version"];
auto java_vendor = results["java.vendor"];
- bool is_64 = os_arch == "x86_64" || os_arch == "amd64";
+ bool is_64 = os_arch == "x86_64" || os_arch == "amd64" || os_arch == "aarch64" || os_arch == "arm64";
result.validity = JavaCheckResult::Validity::Valid;
diff --git a/launcher/java/JavaInstallList.cpp b/launcher/java/JavaInstallList.cpp
index a0a60871..9b745095 100644
--- a/launcher/java/JavaInstallList.cpp
+++ b/launcher/java/JavaInstallList.cpp
@@ -183,7 +183,7 @@ void JavaListLoadTask::javaCheckerFinished()
JavaInstallPtr javaVersion(new JavaInstall());
javaVersion->id = result.javaVersion;
- javaVersion->arch = result.mojangPlatform;
+ javaVersion->arch = result.realPlatform;
javaVersion->path = result.path;
candidates.append(javaVersion);
diff --git a/launcher/launch/steps/CheckJava.cpp b/launcher/launch/steps/CheckJava.cpp
index c2ebb334..3226fae7 100644
--- a/launcher/launch/steps/CheckJava.cpp
+++ b/launcher/launch/steps/CheckJava.cpp
@@ -124,7 +124,8 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
case JavaCheckResult::Validity::Valid:
{
auto instance = m_parent->instance();
- printJavaInfo(result.javaVersion.toString(), result.mojangPlatform, result.javaVendor);
+ printJavaInfo(result.javaVersion.toString(), result.realPlatform, result.javaVendor);
+ printSystemInfo(true, result.is_64bit);
instance->settings()->set("JavaVersion", result.javaVersion.toString());
instance->settings()->set("JavaArchitecture", result.mojangPlatform);
instance->settings()->set("JavaVendor", result.javaVendor);
@@ -137,8 +138,7 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
void CheckJava::printJavaInfo(const QString& version, const QString& architecture, const QString & vendor)
{
- emit logLine(QString("Java is version %1, using %2-bit architecture, from %3.\n\n").arg(version, architecture, vendor), MessageLevel::Launcher);
- printSystemInfo(true, architecture == "64");
+ emit logLine(QString("Java is version %1, using %2 architecture, from %3.\n\n").arg(version, architecture, vendor), MessageLevel::Launcher);
}
void CheckJava::printSystemInfo(bool javaIsKnown, bool javaIs64bit)
diff --git a/launcher/minecraft/Agent.h b/launcher/minecraft/Agent.h
new file mode 100644
index 00000000..01109daf
--- /dev/null
+++ b/launcher/minecraft/Agent.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <QString>
+
+#include "Library.h"
+
+class Agent;
+
+typedef std::shared_ptr<Agent> AgentPtr;
+
+class Agent {
+public:
+ Agent(LibraryPtr library, QString &argument)
+ {
+ m_library = library;
+ m_argument = argument;
+ }
+
+public: /* methods */
+
+ LibraryPtr library() {
+ return m_library;
+ }
+ QString argument() {
+ return m_argument;
+ }
+
+protected: /* data */
+
+ /// The library pointing to the jar this Java agent is contained within
+ LibraryPtr m_library;
+
+ /// The argument to the Java agent, passed after an = if present
+ QString m_argument;
+
+};
diff --git a/launcher/minecraft/LaunchProfile.cpp b/launcher/minecraft/LaunchProfile.cpp
index 41705187..39a342ca 100644
--- a/launcher/minecraft/LaunchProfile.cpp
+++ b/launcher/minecraft/LaunchProfile.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * 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 "LaunchProfile.h"
#include <Version.h>
@@ -7,11 +42,13 @@ void LaunchProfile::clear()
m_minecraftVersionType.clear();
m_minecraftAssets.reset();
m_minecraftArguments.clear();
+ m_addnJvmArguments.clear();
m_tweakers.clear();
m_mainClass.clear();
m_appletClass.clear();
m_libraries.clear();
m_mavenFiles.clear();
+ m_agents.clear();
m_traits.clear();
m_jarMods.clear();
m_mainJar.reset();
@@ -45,6 +82,11 @@ void LaunchProfile::applyMinecraftArguments(const QString& minecraftArguments)
applyString(minecraftArguments, this->m_minecraftArguments);
}
+void LaunchProfile::applyAddnJvmArguments(const QStringList& addnJvmArguments)
+{
+ this->m_addnJvmArguments.append(addnJvmArguments);
+}
+
void LaunchProfile::applyMinecraftVersionType(const QString& type)
{
applyString(type, this->m_minecraftVersionType);
@@ -126,6 +168,11 @@ void LaunchProfile::applyMods(const QList<LibraryPtr>& mods)
}
}
+void LaunchProfile::applyCompatibleJavaMajors(QList<int>& javaMajor)
+{
+ m_compatibleJavaMajors.append(javaMajor);
+}
+
void LaunchProfile::applyLibrary(LibraryPtr library)
{
if(!library->isActive())
@@ -174,6 +221,22 @@ void LaunchProfile::applyMavenFile(LibraryPtr mavenFile)
m_mavenFiles.append(Library::limitedCopy(mavenFile));
}
+void LaunchProfile::applyAgent(AgentPtr agent)
+{
+ auto lib = agent->library();
+ if(!lib->isActive())
+ {
+ return;
+ }
+
+ if(lib->isNative())
+ {
+ return;
+ }
+
+ m_agents.append(agent);
+}
+
const LibraryPtr LaunchProfile::getMainJar() const
{
return m_mainJar;
@@ -255,6 +318,11 @@ QString LaunchProfile::getMinecraftArguments() const
return m_minecraftArguments;
}
+const QStringList & LaunchProfile::getAddnJvmArguments() const
+{
+ return m_addnJvmArguments;
+}
+
const QList<LibraryPtr> & LaunchProfile::getJarMods() const
{
return m_jarMods;
@@ -275,6 +343,16 @@ const QList<LibraryPtr> & LaunchProfile::getMavenFiles() const
return m_mavenFiles;
}
+const QList<AgentPtr> & LaunchProfile::getAgents() const
+{
+ return m_agents;
+}
+
+const QList<int> & LaunchProfile::getCompatibleJavaMajors() const
+{
+ return m_compatibleJavaMajors;
+}
+
void LaunchProfile::getLibraryFiles(
const QString& architecture,
QStringList& jars,
diff --git a/launcher/minecraft/LaunchProfile.h b/launcher/minecraft/LaunchProfile.h
index c1752531..b55cf661 100644
--- a/launcher/minecraft/LaunchProfile.h
+++ b/launcher/minecraft/LaunchProfile.h
@@ -1,6 +1,42 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * 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 <QString>
#include "Library.h"
+#include "Agent.h"
#include <ProblemProvider.h>
class LaunchProfile: public ProblemProvider
@@ -13,6 +49,7 @@ public: /* application of profile variables from patches */
void applyMainClass(const QString& mainClass);
void applyAppletClass(const QString& appletClass);
void applyMinecraftArguments(const QString& minecraftArguments);
+ void applyAddnJvmArguments(const QStringList& minecraftArguments);
void applyMinecraftVersionType(const QString& type);
void applyMinecraftAssets(MojangAssetIndexInfo::Ptr assets);
void applyTraits(const QSet<QString> &traits);
@@ -21,6 +58,8 @@ public: /* application of profile variables from patches */
void applyMods(const QList<LibraryPtr> &jarMods);
void applyLibrary(LibraryPtr library);
void applyMavenFile(LibraryPtr library);
+ void applyAgent(AgentPtr agent);
+ void applyCompatibleJavaMajors(QList<int>& javaMajor);
void applyMainJar(LibraryPtr jar);
void applyProblemSeverity(ProblemSeverity severity);
/// clear the profile
@@ -33,12 +72,15 @@ public: /* getters for profile variables */
QString getMinecraftVersionType() const;
MojangAssetIndexInfo::Ptr getMinecraftAssets() const;
QString getMinecraftArguments() const;
+ const QStringList & getAddnJvmArguments() const;
const QSet<QString> & getTraits() const;
const QStringList & getTweakers() const;
const QList<LibraryPtr> & getJarMods() const;
const QList<LibraryPtr> & getLibraries() const;
const QList<LibraryPtr> & getNativeLibraries() const;
const QList<LibraryPtr> & getMavenFiles() const;
+ const QList<AgentPtr> & getAgents() const;
+ const QList<int> & getCompatibleJavaMajors() const;
const LibraryPtr getMainJar() const;
void getLibraryFiles(
const QString & architecture,
@@ -69,6 +111,12 @@ private:
*/
QString m_minecraftArguments;
+ /**
+ * Additional arguments to pass to the JVM in addition to those the user has configured,
+ * memory settings, etc.
+ */
+ QStringList m_addnJvmArguments;
+
/// A list of all tweaker classes
QStringList m_tweakers;
@@ -84,6 +132,9 @@ private:
/// the list of maven files to be placed in the libraries folder, but not acted upon
QList<LibraryPtr> m_mavenFiles;
+ /// the list of java agents to add to JVM arguments
+ QList<AgentPtr> m_agents;
+
/// the main jar
LibraryPtr m_mainJar;
@@ -99,6 +150,9 @@ private:
/// the list of mods
QList<LibraryPtr> m_mods;
+ /// compatible java major versions
+ QList<int> m_compatibleJavaMajors;
+
ProblemSeverity m_problemSeverity = ProblemSeverity::None;
};
diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp
index c7e60fda..3ba79178 100644
--- a/launcher/minecraft/MinecraftInstance.cpp
+++ b/launcher/minecraft/MinecraftInstance.cpp
@@ -125,6 +125,7 @@ MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsO
m_settings->registerOverride(globalSettings->getSetting("JavaPath"), javaOrLocation);
m_settings->registerOverride(globalSettings->getSetting("JvmArgs"), javaOrArgs);
+ m_settings->registerOverride(globalSettings->getSetting("IgnoreJavaCompatibility"), javaOrLocation);
// special!
m_settings->registerPassthrough(globalSettings->getSetting("JavaTimestamp"), javaOrLocation);
@@ -329,6 +330,17 @@ QStringList MinecraftInstance::extraArguments() const
list.append({"-Dfml.ignoreInvalidMinecraftCertificates=true",
"-Dfml.ignorePatchDiscrepancies=true"});
}
+ auto addn = m_components->getProfile()->getAddnJvmArguments();
+ if (!addn.isEmpty()) {
+ list.append(addn);
+ }
+ auto agents = m_components->getProfile()->getAgents();
+ for (auto agent : agents)
+ {
+ QStringList jar, temp1, temp2, temp3;
+ agent->library()->getApplicableFiles(currentSystem, jar, temp1, temp2, temp3, getLocalLibraryPath());
+ list.append("-javaagent:"+jar[0]+(agent->argument().isEmpty() ? "" : "="+agent->argument()));
+ }
return list;
}
diff --git a/launcher/minecraft/MojangVersionFormat.cpp b/launcher/minecraft/MojangVersionFormat.cpp
index ff5409fd..94c58676 100644
--- a/launcher/minecraft/MojangVersionFormat.cpp
+++ b/launcher/minecraft/MojangVersionFormat.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * 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 "MojangVersionFormat.h"
#include "OneSixVersionFormat.h"
#include "MojangDownloadInfo.h"
@@ -183,6 +218,15 @@ void MojangVersionFormat::readVersionProperties(const QJsonObject &in, VersionFi
);
}
}
+
+ if (in.contains("compatibleJavaMajors"))
+ {
+ for (auto compatible : requireArray(in.value("compatibleJavaMajors")))
+ {
+ out->compatibleJavaMajors.append(requireInteger(compatible));
+ }
+ }
+
if(in.contains("downloads"))
{
auto downloadsObj = requireObject(in, "downloads");
diff --git a/launcher/minecraft/OneSixVersionFormat.cpp b/launcher/minecraft/OneSixVersionFormat.cpp
index 0329d70e..879f18c1 100644
--- a/launcher/minecraft/OneSixVersionFormat.cpp
+++ b/launcher/minecraft/OneSixVersionFormat.cpp
@@ -1,5 +1,6 @@
#include "OneSixVersionFormat.h"
#include <Json.h>
+#include "minecraft/Agent.h"
#include "minecraft/ParseUtils.h"
#include <minecraft/MojangVersionFormat.h>
@@ -108,6 +109,14 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc
}
}
+ if (root.contains("+jvmArgs"))
+ {
+ for (auto arg : requireArray(root.value("+jvmArgs")))
+ {
+ out->addnJvmArguments.append(requireString(arg));
+ }
+ }
+
if (root.contains("jarMods"))
{
@@ -176,6 +185,21 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc
readLibs("mavenFiles", out->mavenFiles);
}
+ if(root.contains("+agents")) {
+ for (auto agentVal : requireArray(root.value("+agents")))
+ {
+ QJsonObject agentObj = requireObject(agentVal);
+ auto lib = libraryFromJson(*out, agentObj, filename);
+ QString arg = "";
+ if (agentObj.contains("argument"))
+ {
+ readString(agentObj, "argument", arg);
+ }
+ AgentPtr agent(new Agent(lib, arg));
+ out->agents.append(agent);
+ }
+ }
+
// if we have mainJar, just use it
if(root.contains("mainJar"))
{
diff --git a/launcher/minecraft/VersionFile.cpp b/launcher/minecraft/VersionFile.cpp
index d0a1a507..9db30ba2 100644
--- a/launcher/minecraft/VersionFile.cpp
+++ b/launcher/minecraft/VersionFile.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * 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 <QJsonArray>
#include <QJsonDocument>
@@ -32,10 +67,12 @@ void VersionFile::applyTo(LaunchProfile *profile)
profile->applyMainClass(mainClass);
profile->applyAppletClass(appletClass);
profile->applyMinecraftArguments(minecraftArguments);
+ profile->applyAddnJvmArguments(addnJvmArguments);
profile->applyTweakers(addTweakers);
profile->applyJarMods(jarMods);
profile->applyMods(mods);
profile->applyTraits(traits);
+ profile->applyCompatibleJavaMajors(compatibleJavaMajors);
for (auto library : libraries)
{
@@ -45,6 +82,10 @@ void VersionFile::applyTo(LaunchProfile *profile)
{
profile->applyMavenFile(mavenFile);
}
+ for (auto agent : agents)
+ {
+ profile->applyAgent(agent);
+ }
profile->applyProblemSeverity(getProblemSeverity());
}
diff --git a/launcher/minecraft/VersionFile.h b/launcher/minecraft/VersionFile.h
index 239a4069..d4b29719 100644
--- a/launcher/minecraft/VersionFile.h
+++ b/launcher/minecraft/VersionFile.h
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * 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 <QString>
@@ -10,6 +45,7 @@
#include "minecraft/Rule.h"
#include "ProblemProvider.h"
#include "Library.h"
+#include "Agent.h"
#include <meta/JsonFormat.h>
class PackProfile;
@@ -57,6 +93,12 @@ public: /* data */
/// Mojang: Minecraft launch arguments (may contain placeholders for variable substitution)
QString minecraftArguments;
+ /// PolyMC: Additional JVM launch arguments
+ QStringList addnJvmArguments;
+
+ /// Mojang: list of compatible java majors
+ QList<int> compatibleJavaMajors;
+
/// Mojang: type of the Minecraft version
QString type;
@@ -78,6 +120,9 @@ public: /* data */
/// PolyMC: list of maven files to put in the libraries folder, but not in classpath
QList<LibraryPtr> mavenFiles;
+ /// PolyMC: list of agents to add to JVM arguments
+ QList<AgentPtr> agents;
+
/// The main jar (Minecraft version library, normally)
LibraryPtr mainJar;
diff --git a/launcher/minecraft/World.cpp b/launcher/minecraft/World.cpp
index 2937c116..dc756e06 100644
--- a/launcher/minecraft/World.cpp
+++ b/launcher/minecraft/World.cpp
@@ -17,6 +17,7 @@
#include <QString>
#include <QDebug>
#include <QSaveFile>
+#include <QDirIterator>
#include "World.h"
#include "GZip.h"
@@ -187,6 +188,26 @@ bool putLevelDatDataToFS(const QFileInfo &file, QByteArray & data)
return f.commit();
}
+int64_t calculateWorldSize(const QFileInfo &file)
+{
+ if (file.isFile() && file.suffix() == "zip")
+ {
+ return file.size();
+ }
+ else if(file.isDir())
+ {
+ QDirIterator it(file.absoluteFilePath(), QDir::Files, QDirIterator::Subdirectories);
+ int64_t total = 0;
+ while (it.hasNext())
+ {
+ total += it.fileInfo().size();
+ it.next();
+ }
+ return total;
+ }
+ return -1;
+}
+
World::World(const QFileInfo &file)
{
repath(file);
@@ -196,6 +217,7 @@ void World::repath(const QFileInfo &file)
{
m_containerFile = file;
m_folderName = file.fileName();
+ m_size = calculateWorldSize(file);
if(file.isFile() && file.suffix() == "zip")
{
m_iconFile = QString();
@@ -482,6 +504,7 @@ void World::loadFromLevelDat(QByteArray data)
if(randomSeed) {
qDebug() << "Seed:" << *randomSeed;
}
+ qDebug() << "Size:" << m_size;
qDebug() << "GameType:" << m_gameType.toLogString();
}
diff --git a/launcher/minecraft/World.h b/launcher/minecraft/World.h
index 35e32788..0f587620 100644
--- a/launcher/minecraft/World.h
+++ b/launcher/minecraft/World.h
@@ -52,6 +52,10 @@ public:
{
return m_iconFile;
}
+ int64_t bytes() const
+ {
+ return m_size;
+ }
QDateTime lastPlayed() const
{
return m_lastPlayed;
@@ -105,6 +109,7 @@ protected:
QString m_iconFile;
QDateTime levelDatTime;
QDateTime m_lastPlayed;
+ int64_t m_size;
int64_t m_randomSeed = 0;
GameType m_gameType;
bool is_valid = false;
diff --git a/launcher/minecraft/WorldList.cpp b/launcher/minecraft/WorldList.cpp
index dcdbc321..344bea63 100644
--- a/launcher/minecraft/WorldList.cpp
+++ b/launcher/minecraft/WorldList.cpp
@@ -14,6 +14,8 @@
*/
#include "WorldList.h"
+
+#include "Application.h"
#include <FileSystem.h>
#include <QMimeData>
#include <QUrl>
@@ -150,7 +152,7 @@ bool WorldList::resetIcon(int row)
int WorldList::columnCount(const QModelIndex &parent) const
{
- return 3;
+ return 4;
}
QVariant WorldList::data(const QModelIndex &index, int role) const
@@ -164,6 +166,8 @@ QVariant WorldList::data(const QModelIndex &index, int role) const
if (row < 0 || row >= worlds.size())
return QVariant();
+ QLocale locale;
+
auto & world = worlds[row];
switch (role)
{
@@ -179,6 +183,9 @@ QVariant WorldList::data(const QModelIndex &index, int role) const
case LastPlayedColumn:
return world.lastPlayed();
+ case SizeColumn:
+ return locale.formattedDataSize(world.bytes());
+
default:
return QVariant();
}
@@ -207,6 +214,10 @@ QVariant WorldList::data(const QModelIndex &index, int role) const
{
return world.lastPlayed();
}
+ case SizeRole:
+ {
+ return locale.formattedDataSize(world.bytes());
+ }
case IconFileRole:
{
return world.iconFile();
@@ -229,6 +240,9 @@ QVariant WorldList::headerData(int section, Qt::Orientation orientation, int rol
return tr("Game Mode");
case LastPlayedColumn:
return tr("Last Played");
+ case SizeColumn:
+ //: World size on disk
+ return tr("Size");
default:
return QVariant();
}
@@ -242,6 +256,8 @@ QVariant WorldList::headerData(int section, Qt::Orientation orientation, int rol
return tr("Game mode of the world.");
case LastPlayedColumn:
return tr("Date and time the world was last played.");
+ case SizeColumn:
+ return tr("Size of the world on disk.");
default:
return QVariant();
}
diff --git a/launcher/minecraft/WorldList.h b/launcher/minecraft/WorldList.h
index 8e238ee3..5138e583 100644
--- a/launcher/minecraft/WorldList.h
+++ b/launcher/minecraft/WorldList.h
@@ -32,7 +32,8 @@ public:
{
NameColumn,
GameModeColumn,
- LastPlayedColumn
+ LastPlayedColumn,
+ SizeColumn
};
enum Roles
@@ -43,6 +44,7 @@ public:
NameRole,
GameModeRole,
LastPlayedRole,
+ SizeRole,
IconFileRole
};
diff --git a/launcher/minecraft/launch/VerifyJavaInstall.cpp b/launcher/minecraft/launch/VerifyJavaInstall.cpp
index 15acf678..99809f82 100644
--- a/launcher/minecraft/launch/VerifyJavaInstall.cpp
+++ b/launcher/minecraft/launch/VerifyJavaInstall.cpp
@@ -1,50 +1,75 @@
-#include "VerifyJavaInstall.h"
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * 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 <launch/LaunchTask.h>
-#include <minecraft/MinecraftInstance.h>
-#include <minecraft/PackProfile.h>
-#include <minecraft/VersionFilterData.h>
+#include "VerifyJavaInstall.h"
-#ifdef major
- #undef major
-#endif
-#ifdef minor
- #undef minor
-#endif
+#include "java/JavaVersion.h"
+#include "minecraft/PackProfile.h"
+#include "minecraft/MinecraftInstance.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 17 requirement
- if (minecraftComponent->getReleaseDateTime() >= g_VersionFilterData.java17BeginsDate) {
- if (javaVersion.major() < 17) {
- emit logLine("Minecraft 1.18 Pre Release 2 and above require the use of Java 17",
- MessageLevel::Fatal);
- emitFailed(tr("Minecraft 1.18 Pre Release 2 and above require the use of Java 17"));
- return;
- }
- }
- // Java 16 requirement
- else 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;
- }
+ auto instance = std::dynamic_pointer_cast<MinecraftInstance>(m_parent->instance());
+ auto packProfile = instance->getPackProfile();
+ auto settings = instance->settings();
+ auto storedVersion = settings->get("JavaVersion").toString();
+ auto ignoreCompatibility = settings->get("IgnoreJavaCompatibility").toBool();
+
+ auto compatibleMajors = packProfile->getProfile()->getCompatibleJavaMajors();
+
+ JavaVersion javaVersion(storedVersion);
+
+ if (compatibleMajors.isEmpty() || compatibleMajors.contains(javaVersion.major()))
+ {
+ emitSucceeded();
+ 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;
- }
+
+
+ if (ignoreCompatibility)
+ {
+ emit logLine(tr("Java major version is incompatible. Things might break."), MessageLevel::Warning);
+ emitSucceeded();
+ return;
}
- emitSucceeded();
+ emit logLine(tr("This instance is not compatible with Java version %1.\n"
+ "Please switch to one of the following Java versions for this instance:").arg(javaVersion.major()),
+ MessageLevel::Error);
+ for (auto major : compatibleMajors)
+ {
+ emit logLine(tr("Java version %1").arg(major), MessageLevel::Error);
+ }
+ emitFailed(QString("Incompatible Java major version"));
}
diff --git a/launcher/minecraft/launch/VerifyJavaInstall.h b/launcher/minecraft/launch/VerifyJavaInstall.h
index a553106d..9139c0fa 100644
--- a/launcher/minecraft/launch/VerifyJavaInstall.h
+++ b/launcher/minecraft/launch/VerifyJavaInstall.h
@@ -1,6 +1,42 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * 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 <launch/LaunchStep.h>
+#include <launch/LaunchTask.h>
class VerifyJavaInstall : public LaunchStep {
Q_OBJECT
diff --git a/launcher/minecraft/update/LibrariesTask.cpp b/launcher/minecraft/update/LibrariesTask.cpp
index 667dd5d9..26679110 100644
--- a/launcher/minecraft/update/LibrariesTask.cpp
+++ b/launcher/minecraft/update/LibrariesTask.cpp
@@ -48,6 +48,10 @@ void LibrariesTask::executeTask()
libArtifactPool.append(profile->getLibraries());
libArtifactPool.append(profile->getNativeLibraries());
libArtifactPool.append(profile->getMavenFiles());
+ for (auto agent : profile->getAgents())
+ {
+ libArtifactPool.append(agent->library());
+ }
libArtifactPool.append(profile->getMainJar());
processArtifactPool(libArtifactPool, failedLocalLibraries, inst->getLocalLibraryPath());
diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp
index 5b75f034..a3c2f166 100644
--- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp
+++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp
@@ -12,7 +12,13 @@ void Modrinth::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj)
{
pack.addonId = Json::requireString(obj, "project_id");
pack.name = Json::requireString(obj, "title");
- pack.websiteUrl = "https://modrinth.com/mod/" + Json::ensureString(obj, "slug", "");
+
+ QString slug = Json::ensureString(obj, "slug", "");
+ if (!slug.isEmpty())
+ pack.websiteUrl = "https://modrinth.com/mod/" + Json::ensureString(obj, "slug", "");
+ else
+ pack.websiteUrl = "";
+
pack.description = Json::ensureString(obj, "description", "");
pack.logoUrl = Json::requireString(obj, "icon_url");
diff --git a/launcher/modplatform/technic/SolderPackInstallTask.cpp b/launcher/modplatform/technic/SolderPackInstallTask.cpp
index b5c91582..89dbf4ca 100644
--- a/launcher/modplatform/technic/SolderPackInstallTask.cpp
+++ b/launcher/modplatform/technic/SolderPackInstallTask.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (c) 2021-2022 Jamie Mansfield <jmansfield@cadixdev.org>
*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * 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 "SolderPackInstallTask.h"
@@ -19,16 +39,23 @@
#include <Json.h>
#include <QtConcurrentRun>
#include <MMCZip.h>
+
#include "TechnicPackProcessor.h"
+#include "SolderPackManifest.h"
+#include "net/ChecksumValidator.h"
Technic::SolderPackInstallTask::SolderPackInstallTask(
shared_qobject_ptr<QNetworkAccessManager> network,
- const QUrl &sourceUrl,
+ const QUrl &solderUrl,
+ const QString &pack,
+ const QString &version,
const QString &minecraftVersion
) {
- m_sourceUrl = sourceUrl;
- m_minecraftVersion = minecraftVersion;
+ m_solderUrl = solderUrl;
+ m_pack = pack;
+ m_version = version;
m_network = network;
+ m_minecraftVersion = minecraftVersion;
}
bool Technic::SolderPackInstallTask::abort() {
@@ -41,34 +68,12 @@ bool Technic::SolderPackInstallTask::abort() {
void Technic::SolderPackInstallTask::executeTask()
{
- setStatus(tr("Finding recommended version:\n%1").arg(m_sourceUrl.toString()));
- m_filesNetJob = new NetJob(tr("Finding recommended version"), m_network);
- m_filesNetJob->addNetAction(Net::Download::makeByteArray(m_sourceUrl, &m_response));
- auto job = m_filesNetJob.get();
- connect(job, &NetJob::succeeded, this, &Technic::SolderPackInstallTask::versionSucceeded);
- connect(job, &NetJob::failed, this, &Technic::SolderPackInstallTask::downloadFailed);
- m_filesNetJob->start();
-}
-
-void Technic::SolderPackInstallTask::versionSucceeded()
-{
- try
- {
- QJsonDocument doc = Json::requireDocument(m_response);
- QJsonObject obj = Json::requireObject(doc);
- QString version = Json::requireString(obj, "recommended", "__placeholder__");
- m_sourceUrl = m_sourceUrl.toString() + '/' + version;
- }
- catch (const JSONValidationError &e)
- {
- emitFailed(e.cause());
- m_filesNetJob.reset();
- return;
- }
+ setStatus(tr("Resolving modpack files"));
- setStatus(tr("Resolving modpack files:\n%1").arg(m_sourceUrl.toString()));
m_filesNetJob = new NetJob(tr("Resolving modpack files"), m_network);
- m_filesNetJob->addNetAction(Net::Download::makeByteArray(m_sourceUrl, &m_response));
+ auto sourceUrl = QString("%1/modpack/%2/%3").arg(m_solderUrl.toString(), m_pack, m_version);
+ m_filesNetJob->addNetAction(Net::Download::makeByteArray(sourceUrl, &m_response));
+
auto job = m_filesNetJob.get();
connect(job, &NetJob::succeeded, this, &Technic::SolderPackInstallTask::fileListSucceeded);
connect(job, &NetJob::failed, this, &Technic::SolderPackInstallTask::downloadFailed);
@@ -77,38 +82,47 @@ void Technic::SolderPackInstallTask::versionSucceeded()
void Technic::SolderPackInstallTask::fileListSucceeded()
{
- setStatus(tr("Downloading modpack:"));
- QStringList modUrls;
- try
- {
- QJsonDocument doc = Json::requireDocument(m_response);
- QJsonObject obj = Json::requireObject(doc);
- QString minecraftVersion = Json::ensureString(obj, "minecraft", QString(), "__placeholder__");
- if (!minecraftVersion.isEmpty())
- m_minecraftVersion = minecraftVersion;
- QJsonArray mods = Json::requireArray(obj, "mods", "'mods'");
- for (auto mod: mods)
- {
- QJsonObject modObject = Json::requireObject(mod);
- modUrls.append(Json::requireString(modObject, "url", "'url'"));
- }
+ setStatus(tr("Downloading modpack"));
+
+ QJsonParseError parse_error {};
+ QJsonDocument doc = QJsonDocument::fromJson(m_response, &parse_error);
+ if (parse_error.error != QJsonParseError::NoError) {
+ qWarning() << "Error while parsing JSON response from Solder at " << parse_error.offset << " reason: " << parse_error.errorString();
+ qWarning() << m_response;
+ return;
}
- catch (const JSONValidationError &e)
- {
- emitFailed(e.cause());
+ auto obj = doc.object();
+
+ TechnicSolder::PackBuild build;
+ try {
+ TechnicSolder::loadPackBuild(build, obj);
+ }
+ catch (const JSONValidationError& e) {
+ emitFailed(tr("Could not understand pack manifest:\n") + e.cause());
m_filesNetJob.reset();
return;
}
+
+ if (!build.minecraft.isEmpty())
+ m_minecraftVersion = build.minecraft;
+
m_filesNetJob = new NetJob(tr("Downloading modpack"), m_network);
+
int i = 0;
- for (auto &modUrl: modUrls)
- {
+ for (const auto &mod : build.mods) {
auto path = FS::PathCombine(m_outputDir.path(), QString("%1").arg(i));
- m_filesNetJob->addNetAction(Net::Download::makeFile(modUrl, path));
+
+ auto dl = Net::Download::makeFile(mod.url, path);
+ if (!mod.md5.isEmpty()) {
+ auto rawMd5 = QByteArray::fromHex(mod.md5.toLatin1());
+ dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Md5, rawMd5));
+ }
+ m_filesNetJob->addNetAction(dl);
+
i++;
}
- m_modCount = modUrls.size();
+ m_modCount = build.mods.size();
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &Technic::SolderPackInstallTask::downloadSucceeded);
connect(m_filesNetJob.get(), &NetJob::progress, this, &Technic::SolderPackInstallTask::downloadProgressChanged);
@@ -206,6 +220,5 @@ void Technic::SolderPackInstallTask::extractFinished()
void Technic::SolderPackInstallTask::extractAborted()
{
emitFailed(tr("Instance import has been aborted."));
- return;
}
diff --git a/launcher/modplatform/technic/SolderPackInstallTask.h b/launcher/modplatform/technic/SolderPackInstallTask.h
index 9b2058d8..117a7bd6 100644
--- a/launcher/modplatform/technic/SolderPackInstallTask.h
+++ b/launcher/modplatform/technic/SolderPackInstallTask.h
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (c) 2021-2022 Jamie Mansfield <jmansfield@cadixdev.org>
*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * 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
@@ -27,7 +47,7 @@ namespace Technic
{
Q_OBJECT
public:
- explicit SolderPackInstallTask(shared_qobject_ptr<QNetworkAccessManager> network, const QUrl &sourceUrl, const QString &minecraftVersion);
+ explicit SolderPackInstallTask(shared_qobject_ptr<QNetworkAccessManager> network, const QUrl &solderUrl, const QString& pack, const QString& version, const QString &minecraftVersion);
bool canAbort() const override { return true; }
bool abort() override;
@@ -37,7 +57,6 @@ namespace Technic
virtual void executeTask() override;
private slots:
- void versionSucceeded();
void fileListSucceeded();
void downloadSucceeded();
void downloadFailed(QString reason);
@@ -51,7 +70,9 @@ namespace Technic
shared_qobject_ptr<QNetworkAccessManager> m_network;
NetJob::Ptr m_filesNetJob;
- QUrl m_sourceUrl;
+ QUrl m_solderUrl;
+ QString m_pack;
+ QString m_version;
QString m_minecraftVersion;
QByteArray m_response;
QTemporaryDir m_outputDir;
diff --git a/launcher/modplatform/technic/SolderPackManifest.cpp b/launcher/modplatform/technic/SolderPackManifest.cpp
new file mode 100644
index 00000000..16fe0b0e
--- /dev/null
+++ b/launcher/modplatform/technic/SolderPackManifest.cpp
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "SolderPackManifest.h"
+
+#include "Json.h"
+
+namespace TechnicSolder {
+
+void loadPack(Pack& v, QJsonObject& obj)
+{
+ v.recommended = Json::requireString(obj, "recommended");
+ v.latest = Json::requireString(obj, "latest");
+
+ auto builds = Json::requireArray(obj, "builds");
+ for (const auto buildRaw : builds) {
+ auto build = Json::requireString(buildRaw);
+ v.builds.append(build);
+ }
+}
+
+static void loadPackBuildMod(PackBuildMod& b, QJsonObject& obj)
+{
+ b.name = Json::requireString(obj, "name");
+ b.version = Json::requireString(obj, "version");
+ b.md5 = Json::requireString(obj, "md5");
+ b.url = Json::requireString(obj, "url");
+}
+
+void loadPackBuild(PackBuild& v, QJsonObject& obj)
+{
+ v.minecraft = Json::requireString(obj, "minecraft");
+
+ auto mods = Json::requireArray(obj, "mods");
+ for (const auto modRaw : mods) {
+ auto modObj = Json::requireObject(modRaw);
+ PackBuildMod mod;
+ loadPackBuildMod(mod, modObj);
+ v.mods.append(mod);
+ }
+}
+
+}
diff --git a/launcher/modplatform/technic/SolderPackManifest.h b/launcher/modplatform/technic/SolderPackManifest.h
new file mode 100644
index 00000000..09f18df0
--- /dev/null
+++ b/launcher/modplatform/technic/SolderPackManifest.h
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <QString>
+#include <QVector>
+#include <QJsonObject>
+
+namespace TechnicSolder {
+
+struct Pack {
+ QString recommended;
+ QString latest;
+ QVector<QString> builds;
+};
+
+void loadPack(Pack& v, QJsonObject& obj);
+
+struct PackBuildMod {
+ QString name;
+ QString version;
+ QString md5;
+ QString url;
+};
+
+struct PackBuild {
+ QString minecraft;
+ QVector<PackBuildMod> mods;
+};
+
+void loadPackBuild(PackBuild& v, QJsonObject& obj);
+
+}
diff --git a/launcher/tasks/SequentialTask.cpp b/launcher/tasks/SequentialTask.cpp
index a66b9d78..1573e476 100644
--- a/launcher/tasks/SequentialTask.cpp
+++ b/launcher/tasks/SequentialTask.cpp
@@ -1,7 +1,23 @@
#include "SequentialTask.h"
-SequentialTask::SequentialTask(QObject *parent) : Task(parent), m_currentIndex(-1)
+SequentialTask::SequentialTask(QObject* parent, const QString& task_name) : Task(parent), m_name(task_name), m_currentIndex(-1) {}
+
+SequentialTask::~SequentialTask()
+{
+ for(auto task : m_queue){
+ if(task)
+ task->deleteLater();
+ }
+}
+
+auto SequentialTask::getStepProgress() const -> qint64
+{
+ return m_stepProgress;
+}
+
+auto SequentialTask::getStepTotalProgress() const -> qint64
{
+ return m_stepTotalProgress;
}
void SequentialTask::addTask(Task::Ptr task)
@@ -15,16 +31,24 @@ void SequentialTask::executeTask()
startNext();
}
+bool SequentialTask::abort()
+{
+ bool succeeded = true;
+ for (auto& task : m_queue) {
+ if (!task->abort()) succeeded = false;
+ }
+
+ return succeeded;
+}
+
void SequentialTask::startNext()
{
- if (m_currentIndex != -1)
- {
+ if (m_currentIndex != -1) {
Task::Ptr previous = m_queue[m_currentIndex];
disconnect(previous.get(), 0, this, 0);
}
m_currentIndex++;
- if (m_queue.isEmpty() || m_currentIndex >= m_queue.size())
- {
+ if (m_queue.isEmpty() || m_currentIndex >= m_queue.size()) {
emitSucceeded();
return;
}
@@ -33,23 +57,27 @@ void SequentialTask::startNext()
connect(next.get(), SIGNAL(status(QString)), this, SLOT(subTaskStatus(QString)));
connect(next.get(), SIGNAL(progress(qint64, qint64)), this, SLOT(subTaskProgress(qint64, qint64)));
connect(next.get(), SIGNAL(succeeded()), this, SLOT(startNext()));
+
+ setStatus(tr("Executing task %1 out of %2").arg(m_currentIndex + 1).arg(m_queue.size()));
next->start();
}
-void SequentialTask::subTaskFailed(const QString &msg)
+void SequentialTask::subTaskFailed(const QString& msg)
{
emitFailed(msg);
}
-void SequentialTask::subTaskStatus(const QString &msg)
+void SequentialTask::subTaskStatus(const QString& msg)
{
- setStatus(msg);
+ setStepStatus(m_queue[m_currentIndex]->getStatus());
}
void SequentialTask::subTaskProgress(qint64 current, qint64 total)
{
- if(total == 0)
- {
+ if (total == 0) {
setProgress(0, 100);
return;
}
- setProgress(current, total);
+ setProgress(m_currentIndex, m_queue.count());
+
+ m_stepProgress = current;
+ m_stepTotalProgress = total;
}
diff --git a/launcher/tasks/SequentialTask.h b/launcher/tasks/SequentialTask.h
index 027744f3..5b3c0111 100644
--- a/launcher/tasks/SequentialTask.h
+++ b/launcher/tasks/SequentialTask.h
@@ -9,13 +9,21 @@ class SequentialTask : public Task
{
Q_OBJECT
public:
- explicit SequentialTask(QObject *parent = 0);
- virtual ~SequentialTask() {};
+ explicit SequentialTask(QObject *parent = nullptr, const QString& task_name = "");
+ virtual ~SequentialTask();
+
+ inline auto isMultiStep() const -> bool override { return m_queue.size() > 1; };
+ auto getStepProgress() const -> qint64 override;
+ auto getStepTotalProgress() const -> qint64 override;
+
+ inline auto getStepStatus() const -> QString override { return m_step_status; }
void addTask(Task::Ptr task);
-protected:
- void executeTask();
+protected slots:
+ void executeTask() override;
+public slots:
+ bool abort() override;
private
slots:
@@ -24,7 +32,19 @@ slots:
void subTaskStatus(const QString &msg);
void subTaskProgress(qint64 current, qint64 total);
+signals:
+ void stepStatus(QString status);
+
private:
+ void setStepStatus(QString status) { m_step_status = status; };
+
+private:
+ QString m_name;
+ QString m_step_status;
+
QQueue<Task::Ptr > m_queue;
int m_currentIndex;
+
+ qint64 m_stepProgress = 0;
+ qint64 m_stepTotalProgress = 100;
};
diff --git a/launcher/tasks/Task.h b/launcher/tasks/Task.h
index 9cf08dbd..47c249b3 100644
--- a/launcher/tasks/Task.h
+++ b/launcher/tasks/Task.h
@@ -21,29 +21,27 @@
#include "QObjectPtr.h"
-class Task : public QObject
-{
+class Task : public QObject {
Q_OBJECT
-public:
+ public:
using Ptr = shared_qobject_ptr<Task>;
- enum class State
- {
- Inactive,
- Running,
- Succeeded,
- Failed,
- AbortedByUser
- };
+ enum class State { Inactive, Running, Succeeded, Failed, AbortedByUser };
-public:
- explicit Task(QObject *parent = 0);
- virtual ~Task() {};
+ public:
+ explicit Task(QObject* parent = 0);
+ virtual ~Task() = default;
bool isRunning() const;
bool isFinished() const;
bool wasSuccessful() const;
+ /*!
+ * MultiStep tasks are combinations of multiple tasks into a single logical task.
+ * The main usage of this is in SequencialTask.
+ */
+ virtual auto isMultiStep() const -> bool { return false; }
+
/*!
* Returns the string that was passed to emitFailed as the error message when the task failed.
* If the task hasn't failed, returns an empty string.
@@ -54,52 +52,45 @@ public:
virtual bool canAbort() const { return false; }
- QString getStatus()
- {
- return m_status;
- }
+ QString getStatus() { return m_status; }
+ virtual auto getStepStatus() const -> QString { return {}; }
- qint64 getProgress()
- {
- return m_progress;
- }
+ qint64 getProgress() { return m_progress; }
+ qint64 getTotalProgress() { return m_progressTotal; }
+ virtual auto getStepProgress() const -> qint64 { return 0; }
+ virtual auto getStepTotalProgress() const -> qint64 { return 100; }
- qint64 getTotalProgress()
- {
- return m_progressTotal;
- }
+ protected:
+ void logWarning(const QString& line);
-protected:
- void logWarning(const QString & line);
-
-private:
+ private:
QString describe();
-signals:
+ signals:
void started();
- void progress(qint64 current, qint64 total);
+ virtual void progress(qint64 current, qint64 total);
void finished();
void succeeded();
void failed(QString reason);
void status(QString status);
-public slots:
+ public slots:
virtual void start();
virtual bool abort() { return false; };
-protected:
+ protected:
virtual void executeTask() = 0;
-protected slots:
+ protected slots:
virtual void emitSucceeded();
virtual void emitAborted();
virtual void emitFailed(QString reason);
-public slots:
- void setStatus(const QString &status);
+ public slots:
+ void setStatus(const QString& status);
void setProgress(qint64 current, qint64 total);
-private:
+ private:
State m_state = State::Inactive;
QStringList m_Warnings;
QString m_failReason = "";
@@ -107,4 +98,3 @@ private:
int m_progress = 0;
int m_progressTotal = 100;
};
-
diff --git a/launcher/ui/dialogs/AboutDialog.ui b/launcher/ui/dialogs/AboutDialog.ui
index f9665c30..70c5009d 100644
--- a/launcher/ui/dialogs/AboutDialog.ui
+++ b/launcher/ui/dialogs/AboutDialog.ui
@@ -80,7 +80,7 @@
</font>
</property>
<property name="text">
- <string notr="true">PolyMC</string>
+ <string notr="true">Launcher</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
diff --git a/launcher/ui/dialogs/ProgressDialog.cpp b/launcher/ui/dialogs/ProgressDialog.cpp
index 4b092859..648bd88b 100644
--- a/launcher/ui/dialogs/ProgressDialog.cpp
+++ b/launcher/ui/dialogs/ProgressDialog.cpp
@@ -81,6 +81,12 @@ int ProgressDialog::execWithTask(Task *task)
connect(task, SIGNAL(status(QString)), SLOT(changeStatus(const QString &)));
connect(task, SIGNAL(progress(qint64, qint64)), SLOT(changeProgress(qint64, qint64)));
+ m_is_multi_step = task->isMultiStep();
+ if(!m_is_multi_step){
+ ui->globalStatusLabel->setHidden(true);
+ ui->globalProgressBar->setHidden(true);
+ }
+
// if this didn't connect to an already running task, invoke start
if(!task->isRunning())
{
@@ -152,14 +158,24 @@ void ProgressDialog::onTaskSucceeded()
void ProgressDialog::changeStatus(const QString &status)
{
- ui->statusLabel->setText(status);
+ ui->statusLabel->setText(task->getStepStatus());
+ ui->globalStatusLabel->setText(status);
updateSize();
}
void ProgressDialog::changeProgress(qint64 current, qint64 total)
{
- ui->taskProgressBar->setMaximum(total);
- ui->taskProgressBar->setValue(current);
+ ui->globalProgressBar->setMaximum(total);
+ ui->globalProgressBar->setValue(current);
+
+ if(!m_is_multi_step){
+ ui->taskProgressBar->setMaximum(total);
+ ui->taskProgressBar->setValue(current);
+ }
+ else{
+ ui->taskProgressBar->setMaximum(task->getStepProgress());
+ ui->taskProgressBar->setValue(task->getStepTotalProgress());
+ }
}
void ProgressDialog::keyPressEvent(QKeyEvent *e)
diff --git a/launcher/ui/dialogs/ProgressDialog.h b/launcher/ui/dialogs/ProgressDialog.h
index b28ad4fa..0b4b78a4 100644
--- a/launcher/ui/dialogs/ProgressDialog.h
+++ b/launcher/ui/dialogs/ProgressDialog.h
@@ -19,6 +19,7 @@
#include <memory>
class Task;
+class SequentialTask;
namespace Ui
{
@@ -35,7 +36,7 @@ public:
void updateSize();
- int execWithTask(Task *task);
+ int execWithTask(Task* task);
int execWithTask(std::unique_ptr<Task> &&task);
int execWithTask(std::unique_ptr<Task> &task);
@@ -68,4 +69,6 @@ private:
Ui::ProgressDialog *ui;
Task *task;
+
+ bool m_is_multi_step = false;
};
diff --git a/launcher/ui/dialogs/ProgressDialog.ui b/launcher/ui/dialogs/ProgressDialog.ui
index 04b8fef3..bf119a78 100644
--- a/launcher/ui/dialogs/ProgressDialog.ui
+++ b/launcher/ui/dialogs/ProgressDialog.ui
@@ -2,14 +2,6 @@
<ui version="4.0">
<class>ProgressDialog</class>
<widget class="QDialog" name="ProgressDialog">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>400</width>
- <height>100</height>
- </rect>
- </property>
<property name="minimumSize">
<size>
<width>400</width>
@@ -26,7 +18,27 @@
<string>Please wait...</string>
</property>
<layout class="QGridLayout" name="gridLayout">
+ <item row="4" column="0">
+ <widget class="QPushButton" name="skipButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Skip</string>
+ </property>
+ </widget>
+ </item>
<item row="0" column="0">
+ <widget class="QLabel" name="globalStatusLabel">
+ <property name="text">
+ <string>Global Task Status...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
<widget class="QLabel" name="statusLabel">
<property name="text">
<string>Task Status...</string>
@@ -36,7 +48,7 @@
</property>
</widget>
</item>
- <item row="1" column="0">
+ <item row="3" column="0">
<widget class="QProgressBar" name="taskProgressBar">
<property name="value">
<number>24</number>
@@ -46,16 +58,13 @@
</property>
</widget>
</item>
- <item row="2" column="0">
- <widget class="QPushButton" name="skipButton">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <item row="1" column="0">
+ <widget class="QProgressBar" name="globalProgressBar">
+ <property name="enabled">
+ <bool>true</bool>
</property>
- <property name="text">
- <string>Skip</string>
+ <property name="value">
+ <number>24</number>
</property>
</widget>
</item>
diff --git a/launcher/ui/dialogs/UpdateDialog.ui b/launcher/ui/dialogs/UpdateDialog.ui
index bd94a554..5eb9d88a 100644
--- a/launcher/ui/dialogs/UpdateDialog.ui
+++ b/launcher/ui/dialogs/UpdateDialog.ui
@@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
- <string>PolyMC Update</string>
+ <string>Launcher Update</string>
</property>
<property name="windowIcon">
<iconset>
diff --git a/launcher/ui/pages/global/JavaPage.cpp b/launcher/ui/pages/global/JavaPage.cpp
index 3eb4bd59..f0616db1 100644
--- a/launcher/ui/pages/global/JavaPage.cpp
+++ b/launcher/ui/pages/global/JavaPage.cpp
@@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -95,6 +96,7 @@ void JavaPage::applySettings()
// Java Settings
s->set("JavaPath", ui->javaPathTextBox->text());
s->set("JvmArgs", ui->jvmArgsTextBox->text());
+ s->set("IgnoreJavaCompatibility", ui->skipCompatibilityCheckbox->isChecked());
JavaCommon::checkJVMArgs(s->get("JvmArgs").toString(), this->parentWidget());
}
void JavaPage::loadSettings()
@@ -118,6 +120,7 @@ void JavaPage::loadSettings()
// Java Settings
ui->javaPathTextBox->setText(s->get("JavaPath").toString());
ui->jvmArgsTextBox->setText(s->get("JvmArgs").toString());
+ ui->skipCompatibilityCheckbox->setChecked(s->get("IgnoreJavaCompatibility").toBool());
}
void JavaPage::on_javaDetectBtn_clicked()
diff --git a/launcher/ui/pages/global/JavaPage.ui b/launcher/ui/pages/global/JavaPage.ui
index b67e9994..d27b200f 100644
--- a/launcher/ui/pages/global/JavaPage.ui
+++ b/launcher/ui/pages/global/JavaPage.ui
@@ -222,6 +222,22 @@
</property>
</widget>
</item>
+ <item row="4" column="1">
+ <widget class="QCheckBox" name="skipCompatibilityCheckbox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>If enabled, the launcher will not check if an instance is compatible with the selected Java version.</string>
+ </property>
+ <property name="text">
+ <string>Skip Java compatibility checks</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
diff --git a/launcher/ui/pages/global/MinecraftPage.ui b/launcher/ui/pages/global/MinecraftPage.ui
index decc9b8b..c18ab34b 100644
--- a/launcher/ui/pages/global/MinecraftPage.ui
+++ b/launcher/ui/pages/global/MinecraftPage.ui
@@ -173,20 +173,20 @@
<item>
<widget class="QCheckBox" name="closeAfterLaunchCheck">
<property name="toolTip">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;PolyMC will automatically reopen when the game crashes or exits.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The launcher will automatically reopen when the game crashes or exits.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
- <string>Close PolyMC after game window opens</string>
+ <string>Close the launcher after game window opens</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="quitAfterGameStopCheck">
<property name="toolTip">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;PolyMC will automatically exit if the game crashes or exists.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The launcher will automatically quit after the game exits or crashes.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
- <string>Quit PolyMC after game window stops</string>
+ <string>Quit the launcher after game window closes</string>
</property>
</widget>
</item>
diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp
index e68a7124..a5985741 100644
--- a/launcher/ui/pages/instance/InstanceSettingsPage.cpp
+++ b/launcher/ui/pages/instance/InstanceSettingsPage.cpp
@@ -165,10 +165,12 @@ void InstanceSettingsPage::applySettings()
if (javaInstall)
{
m_settings->set("JavaPath", ui->javaPathTextBox->text());
+ m_settings->set("IgnoreJavaCompatibility", ui->skipCompatibilityCheckbox->isChecked());
}
else
{
m_settings->reset("JavaPath");
+ m_settings->reset("IgnoreJavaCompatibility");
}
// Java arguments
@@ -286,6 +288,7 @@ void InstanceSettingsPage::loadSettings()
ui->javaSettingsGroupBox->setChecked(overrideLocation);
ui->javaPathTextBox->setText(m_settings->get("JavaPath").toString());
+ ui->skipCompatibilityCheckbox->setChecked(m_settings->get("IgnoreJavaCompatibility").toBool());
ui->javaArgumentsGroupBox->setChecked(overrideArgs);
ui->jvmArgsTextBox->setPlainText(m_settings->get("JvmArgs").toString());
diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui
index 729f8e2a..5db2d147 100644
--- a/launcher/ui/pages/instance/InstanceSettingsPage.ui
+++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui
@@ -85,6 +85,16 @@
</property>
</widget>
</item>
+ <item row="2" column="0">
+ <widget class="QCheckBox" name="skipCompatibilityCheckbox">
+ <property name="toolTip">
+ <string>If enabled, the launcher will not check if an instance is compatible with the selected Java version.</string>
+ </property>
+ <property name="text">
+ <string>Skip Java compatibility checks</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
diff --git a/launcher/ui/pages/instance/ModFolderPage.cpp b/launcher/ui/pages/instance/ModFolderPage.cpp
index 599f0e11..fcb6022d 100644
--- a/launcher/ui/pages/instance/ModFolderPage.cpp
+++ b/launcher/ui/pages/instance/ModFolderPage.cpp
@@ -58,6 +58,7 @@
#include "Version.h"
#include "ui/dialogs/ProgressDialog.h"
+#include "tasks/SequentialTask.h"
namespace {
// FIXME: wasteful
@@ -394,25 +395,25 @@ void ModFolderPage::on_actionInstall_mods_triggered()
return;
}
ModDownloadDialog mdownload(m_mods, this, m_inst);
- if(mdownload.exec()) {
- for(auto task : mdownload.getTasks()){
- connect(task, &Task::failed, [this, task](QString reason) {
- task->deleteLater();
- CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
- });
- connect(task, &Task::succeeded, [this, task]() {
- QStringList warnings = task->warnings();
- if (warnings.count()) {
- CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'),
- QMessageBox::Warning)->show();
- }
- task->deleteLater();
- });
- ProgressDialog loadDialog(this);
- loadDialog.setSkipButton(true, tr("Abort"));
- loadDialog.execWithTask(task);
- m_mods->update();
+ if (mdownload.exec()) {
+ SequentialTask* tasks = new SequentialTask(this);
+ connect(tasks, &Task::failed, [this, tasks](QString reason) {
+ CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
+ tasks->deleteLater();
+ });
+ connect(tasks, &Task::succeeded, [this, tasks]() {
+ QStringList warnings = tasks->warnings();
+ if (warnings.count()) { CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show(); }
+ tasks->deleteLater();
+ });
+
+ for (auto task : mdownload.getTasks()) {
+ tasks->addTask(task);
}
+ ProgressDialog loadDialog(this);
+ loadDialog.setSkipButton(true, tr("Abort"));
+ loadDialog.execWithTask(tasks);
+ m_mods->update();
}
}
diff --git a/launcher/ui/pages/modplatform/technic/TechnicData.h b/launcher/ui/pages/modplatform/technic/TechnicData.h
index 50fd75e8..cd2ea8e1 100644
--- a/launcher/ui/pages/modplatform/technic/TechnicData.h
+++ b/launcher/ui/pages/modplatform/technic/TechnicData.h
@@ -1,22 +1,43 @@
-/* Copyright 2020-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (c) 2021-2022 Jamie Mansfield <jmansfield@cadixdev.org>
*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2020-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 <QList>
#include <QString>
+#include <QVector>
namespace Technic {
struct Modpack {
@@ -36,6 +57,11 @@ struct Modpack {
QString websiteUrl;
QString author;
QString description;
+ QString currentVersion;
+
+ bool versionsLoaded = false;
+ QString recommended;
+ QVector<QString> versions;
};
}
diff --git a/launcher/ui/pages/modplatform/technic/TechnicModel.cpp b/launcher/ui/pages/modplatform/technic/TechnicModel.cpp
index 0167f746..9c9d1e75 100644
--- a/launcher/ui/pages/modplatform/technic/TechnicModel.cpp
+++ b/launcher/ui/pages/modplatform/technic/TechnicModel.cpp
@@ -1,20 +1,41 @@
-/* Copyright 2020-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (c) 2021 Jamie Mansfield <jmansfield@cadixdev.org>
*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2020-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 "TechnicModel.h"
#include "Application.h"
+#include "BuildConfig.h"
#include "Json.h"
#include <QIcon>
@@ -94,13 +115,24 @@ void Technic::ListModel::performSearch()
NetJob *netJob = new NetJob("Technic::Search", APPLICATION->network());
QString searchUrl = "";
if (currentSearchTerm.isEmpty()) {
- searchUrl = "https://api.technicpack.net/trending?build=multimc";
+ searchUrl = QString("%1trending?build=%2")
+ .arg(BuildConfig.TECHNIC_API_BASE_URL, BuildConfig.TECHNIC_API_BUILD);
+ searchMode = List;
}
- else
- {
+ else if (currentSearchTerm.startsWith("http://api.technicpack.net/modpack/")) {
+ searchUrl = QString("https://%1?build=%2")
+ .arg(currentSearchTerm.mid(7), BuildConfig.TECHNIC_API_BUILD);
+ searchMode = Single;
+ }
+ else if (currentSearchTerm.startsWith("https://api.technicpack.net/modpack/")) {
+ searchUrl = QString("%1?build=%2").arg(currentSearchTerm, BuildConfig.TECHNIC_API_BUILD);
+ searchMode = Single;
+ }
+ else {
searchUrl = QString(
- "https://api.technicpack.net/search?build=multimc&q=%1"
- ).arg(currentSearchTerm);
+ "%1search?build=%2&q=%3"
+ ).arg(BuildConfig.TECHNIC_API_BASE_URL, BuildConfig.TECHNIC_API_BUILD, currentSearchTerm);
+ searchMode = List;
}
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response));
jobPtr = netJob;
@@ -125,26 +157,58 @@ void Technic::ListModel::searchRequestFinished()
QList<Modpack> newList;
try {
auto root = Json::requireObject(doc);
- auto objs = Json::requireArray(root, "modpacks");
- for (auto technicPack: objs) {
- Modpack pack;
- auto technicPackObject = Json::requireObject(technicPack);
- pack.name = Json::requireString(technicPackObject, "name");
- pack.slug = Json::requireString(technicPackObject, "slug");
- if (pack.slug == "vanilla")
- continue;
-
- auto rawURL = Json::ensureString(technicPackObject, "iconUrl", "null");
- if(rawURL == "null") {
- pack.logoUrl = "null";
- pack.logoName = "null";
+
+ switch (searchMode) {
+ case List: {
+ auto objs = Json::requireArray(root, "modpacks");
+ for (auto technicPack: objs) {
+ Modpack pack;
+ auto technicPackObject = Json::requireObject(technicPack);
+ pack.name = Json::requireString(technicPackObject, "name");
+ pack.slug = Json::requireString(technicPackObject, "slug");
+ if (pack.slug == "vanilla")
+ continue;
+
+ auto rawURL = Json::ensureString(technicPackObject, "iconUrl", "null");
+ if(rawURL == "null") {
+ pack.logoUrl = "null";
+ pack.logoName = "null";
+ }
+ else {
+ pack.logoUrl = rawURL;
+ pack.logoName = rawURL.section(QLatin1Char('/'), -1).section(QLatin1Char('.'), 0, 0);
+ }
+ pack.broken = false;
+ newList.append(pack);
+ }
+ break;
}
- else {
- pack.logoUrl = rawURL;
- pack.logoName = rawURL.section(QLatin1Char('/'), -1).section(QLatin1Char('.'), 0, 0);
+ case Single: {
+ if (root.contains("error")) {
+ // Invalid API url
+ break;
+ }
+
+ Modpack pack;
+ pack.name = Json::requireString(root, "displayName");
+ pack.slug = Json::requireString(root, "name");
+
+ if (root.contains("icon")) {
+ auto iconObj = Json::requireObject(root, "icon");
+ auto iconUrl = Json::requireString(iconObj, "url");
+
+ pack.logoUrl = iconUrl;
+ pack.logoName = iconUrl.section(QLatin1Char('/'), -1).section(QLatin1Char('.'), 0, 0);
+ }
+ else {
+ pack.logoUrl = "null";
+ pack.logoName = "null";
+ }
+
+ pack.broken = false;
+ newList.append(pack);
+ break;
}
- pack.broken = false;
- newList.append(pack);
}
}
catch (const JSONValidationError &err)
diff --git a/launcher/ui/pages/modplatform/technic/TechnicModel.h b/launcher/ui/pages/modplatform/technic/TechnicModel.h
index e80e6e7c..5eea124c 100644
--- a/launcher/ui/pages/modplatform/technic/TechnicModel.h
+++ b/launcher/ui/pages/modplatform/technic/TechnicModel.h
@@ -1,16 +1,36 @@
-/* Copyright 2020-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (c) 2021 Jamie Mansfield <jmansfield@cadixdev.org>
*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2020-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
@@ -63,6 +83,10 @@ private:
ResetRequested,
Finished
} searchState = None;
+ enum SearchMode {
+ List,
+ Single,
+ } searchMode = List;
NetJob::Ptr jobPtr;
QByteArray response;
};
diff --git a/launcher/ui/pages/modplatform/technic/TechnicPage.cpp b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp
index c3807269..b8c1e00a 100644
--- a/launcher/ui/pages/modplatform/technic/TechnicPage.cpp
+++ b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
- * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ * Copyright (c) 2021-2022 Jamie Mansfield <jmansfield@cadixdev.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -40,12 +40,14 @@
#include "ui/dialogs/NewInstanceDialog.h"
+#include "BuildConfig.h"
#include "TechnicModel.h"
#include "modplatform/technic/SingleZipPackInstallTask.h"
#include "modplatform/technic/SolderPackInstallTask.h"
#include "Json.h"
#include "Application.h"
+#include "modplatform/technic/SolderPackManifest.h"
TechnicPage::TechnicPage(NewInstanceDialog* dialog, QWidget *parent)
: QWidget(parent), ui(new Ui::TechnicPage), dialog(dialog)
@@ -55,7 +57,9 @@ TechnicPage::TechnicPage(NewInstanceDialog* dialog, QWidget *parent)
ui->searchEdit->installEventFilter(this);
model = new Technic::ListModel(this);
ui->packView->setModel(model);
+
connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &TechnicPage::onSelectionChanged);
+ connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &TechnicPage::onVersionSelectionChanged);
}
bool TechnicPage::eventFilter(QObject* watched, QEvent* event)
@@ -98,13 +102,14 @@ void TechnicPage::triggerSearch() {
void TechnicPage::onSelectionChanged(QModelIndex first, QModelIndex second)
{
+ ui->versionSelectionBox->clear();
+
if(!first.isValid())
{
if(isOpened)
{
dialog->setSuggestedPack();
}
- //ui->frame->clear();
return;
}
@@ -137,17 +142,19 @@ void TechnicPage::suggestCurrent()
}
NetJob *netJob = new NetJob(QString("Technic::PackMeta(%1)").arg(current.name), APPLICATION->network());
- std::shared_ptr<QByteArray> response = std::make_shared<QByteArray>();
QString slug = current.slug;
- netJob->addNetAction(Net::Download::makeByteArray(QString("https://api.technicpack.net/modpack/%1?build=multimc").arg(slug), response.get()));
- QObject::connect(netJob, &NetJob::succeeded, this, [this, response, slug]
+ netJob->addNetAction(Net::Download::makeByteArray(QString("%1modpack/%2?build=%3").arg(BuildConfig.TECHNIC_API_BASE_URL, slug, BuildConfig.TECHNIC_API_BUILD), &response));
+ QObject::connect(netJob, &NetJob::succeeded, this, [this, slug]
{
+ jobPtr.reset();
+
if (current.slug != slug)
{
return;
}
- QJsonParseError parse_error;
- QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
+
+ QJsonParseError parse_error {};
+ QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error);
QJsonObject obj = doc.object();
if(parse_error.error != QJsonParseError::NoError)
{
@@ -189,10 +196,14 @@ void TechnicPage::suggestCurrent()
current.websiteUrl = Json::ensureString(obj, "platformUrl", QString(), "__placeholder__");
current.author = Json::ensureString(obj, "user", QString(), "__placeholder__");
current.description = Json::ensureString(obj, "description", QString(), "__placeholder__");
+ current.currentVersion = Json::ensureString(obj, "version", QString(), "__placeholder__");
current.metadataLoaded = true;
+
metadataLoaded();
});
- netJob->start();
+
+ jobPtr = netJob;
+ jobPtr->start();
}
// expects current.metadataLoaded to be true
@@ -202,25 +213,119 @@ void TechnicPage::metadataLoaded()
QString name = current.name;
if (current.websiteUrl.isEmpty())
- // This allows injecting HTML here.
- text = name;
+ text = name.toHtmlEscaped();
else
- // URL not properly escaped for inclusion in HTML. The name allows for injecting HTML.
- text = "<a href=\"" + current.websiteUrl + "\">" + name + "</a>";
+ text = "<a href=\"" + current.websiteUrl.toHtmlEscaped() + "\">" + name.toHtmlEscaped() + "</a>";
+
if (!current.author.isEmpty()) {
- // This allows injecting HTML here
- text += tr(" by ") + current.author;
+ text += "<br>" + tr(" by ") + current.author.toHtmlEscaped();
+ }
+
+ text += "<br><br>";
+
+ ui->packDescription->setHtml(text + current.description);
+
+ // Strip trailing forward-slashes from Solder URL's
+ if (current.isSolder) {
+ while (current.url.endsWith('/')) current.url.chop(1);
+ }
+
+ // Display versions from Solder
+ if (!current.isSolder) {
+ // If the pack isn't a Solder pack, it only has the single version
+ ui->versionSelectionBox->addItem(current.currentVersion);
+ }
+ else if (current.versionsLoaded) {
+ // reverse foreach, so that the newest versions are first
+ for (auto i = current.versions.size(); i--;) {
+ ui->versionSelectionBox->addItem(current.versions.at(i));
+ }
+ ui->versionSelectionBox->setCurrentText(current.recommended);
+ }
+ else {
+ // For now, until the versions are pulled from the Solder instance, display the current
+ // version so we can display something quicker
+ ui->versionSelectionBox->addItem(current.currentVersion);
+
+ auto* netJob = new NetJob(QString("Technic::SolderMeta(%1)").arg(current.name), APPLICATION->network());
+ auto url = QString("%1/modpack/%2").arg(current.url, current.slug);
+ netJob->addNetAction(Net::Download::makeByteArray(QUrl(url), &response));
+
+ QObject::connect(netJob, &NetJob::succeeded, this, &TechnicPage::onSolderLoaded);
+
+ jobPtr = netJob;
+ jobPtr->start();
+ }
+
+ selectVersion();
+}
+
+void TechnicPage::selectVersion() {
+ if (!isOpened) {
+ return;
+ }
+ if (current.broken) {
+ dialog->setSuggestedPack();
+ return;
}
- ui->frame->setModText(text);
- ui->frame->setModDescription(current.description);
if (!current.isSolder)
{
- dialog->setSuggestedPack(current.name, new Technic::SingleZipPackInstallTask(current.url, current.minecraftVersion));
+ dialog->setSuggestedPack(current.name + " " + selectedVersion, new Technic::SingleZipPackInstallTask(current.url, current.minecraftVersion));
}
else
{
- while (current.url.endsWith('/')) current.url.chop(1);
- dialog->setSuggestedPack(current.name, new Technic::SolderPackInstallTask(APPLICATION->network(), current.url + "/modpack/" + current.slug, current.minecraftVersion));
+ dialog->setSuggestedPack(current.name + " " + selectedVersion, new Technic::SolderPackInstallTask(APPLICATION->network(), current.url, current.slug, selectedVersion, current.minecraftVersion));
+ }
+}
+
+void TechnicPage::onSolderLoaded() {
+ jobPtr.reset();
+
+ auto fallback = [this]() {
+ current.versionsLoaded = true;
+
+ current.versions.clear();
+ current.versions.append(current.currentVersion);
+ };
+
+ current.versions.clear();
+
+ QJsonParseError parse_error {};
+ auto doc = QJsonDocument::fromJson(response, &parse_error);
+ if (parse_error.error != QJsonParseError::NoError) {
+ qWarning() << "Error while parsing JSON response from Solder at " << parse_error.offset << " reason: " << parse_error.errorString();
+ qWarning() << response;
+ fallback();
+ return;
+ }
+ auto obj = doc.object();
+
+ TechnicSolder::Pack pack;
+ try {
+ TechnicSolder::loadPack(pack, obj);
+ }
+ catch (const JSONValidationError& err) {
+ qCritical() << "Couldn't parse Solder pack metadata:" << err.cause();
+ fallback();
+ return;
+ }
+
+ current.versionsLoaded = true;
+ current.recommended = pack.recommended;
+ current.versions.append(pack.builds);
+
+ // Finally, let's reload :)
+ ui->versionSelectionBox->clear();
+ metadataLoaded();
+}
+
+void TechnicPage::onVersionSelectionChanged(QString data) {
+ if (data.isNull() || data.isEmpty()) {
+ selectedVersion = "";
+ return;
}
+
+ selectedVersion = data;
+ selectVersion();
}
diff --git a/launcher/ui/pages/modplatform/technic/TechnicPage.h b/launcher/ui/pages/modplatform/technic/TechnicPage.h
index bf4baa58..f4a3b61d 100644
--- a/launcher/ui/pages/modplatform/technic/TechnicPage.h
+++ b/launcher/ui/pages/modplatform/technic/TechnicPage.h
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
- * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ * Copyright (c) 2021-2022 Jamie Mansfield <jmansfield@cadixdev.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -39,6 +39,7 @@
#include "ui/pages/BasePage.h"
#include <Application.h>
+#include "net/NetJob.h"
#include "tasks/Task.h"
#include "TechnicData.h"
@@ -86,14 +87,22 @@ public:
private:
void suggestCurrent();
void metadataLoaded();
+ void selectVersion();
private slots:
void triggerSearch();
void onSelectionChanged(QModelIndex first, QModelIndex second);
+ void onSolderLoaded();
+ void onVersionSelectionChanged(QString data);
private:
Ui::TechnicPage *ui = nullptr;
NewInstanceDialog* dialog = nullptr;
Technic::ListModel* model = nullptr;
+
Technic::Modpack current;
+ QString selectedVersion;
+
+ NetJob::Ptr jobPtr;
+ QByteArray response;
};
diff --git a/launcher/ui/pages/modplatform/technic/TechnicPage.ui b/launcher/ui/pages/modplatform/technic/TechnicPage.ui
index 62ab6154..ca6a9b7e 100644
--- a/launcher/ui/pages/modplatform/technic/TechnicPage.ui
+++ b/launcher/ui/pages/modplatform/technic/TechnicPage.ui
@@ -10,86 +10,76 @@
<height>405</height>
</rect>
</property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QWidget" name="widget" native="true">
- <layout class="QHBoxLayout" name="horizontalLayout">
- <property name="leftMargin">
- <number>0</number>
- </property>
- <property name="topMargin">
- <number>0</number>
- </property>
- <property name="rightMargin">
- <number>0</number>
- </property>
- <property name="bottomMargin">
- <number>0</number>
- </property>
- <item>
- <widget class="QLineEdit" name="searchEdit">
- <property name="placeholderText">
- <string>Search and filter...</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="searchButton">
- <property name="text">
- <string>Search</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="3" column="0" colspan="2">
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="2">
+ <widget class="QComboBox" name="versionSelectionBox"/>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Version selected:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Preferred</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>1</width>
+ <height>1</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
</item>
- <item>
- <widget class="QListView" name="packView">
- <property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
- </property>
- <property name="alternatingRowColors">
- <bool>true</bool>
- </property>
- <property name="iconSize">
- <size>
- <width>48</width>
- <height>48</height>
- </size>
+ <item row="2" column="0" colspan="2">
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <widget class="QListView" name="packView">
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>48</width>
+ <height>48</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QTextBrowser" name="packDescription"/>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLineEdit" name="searchEdit">
+ <property name="placeholderText">
+ <string>Search and filter...</string>
</property>
</widget>
</item>
- <item>
- <widget class="MCModInfoFrame" name="frame">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="frameShape">
- <enum>QFrame::StyledPanel</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Raised</enum>
+ <item row="1" column="1">
+ <widget class="QPushButton" name="searchButton">
+ <property name="text">
+ <string>Search</string>
</property>
</widget>
</item>
</layout>
</widget>
- <customwidgets>
- <customwidget>
- <class>MCModInfoFrame</class>
- <extends>QFrame</extends>
- <header>ui/widgets/MCModInfoFrame.h</header>
- <container>1</container>
- </customwidget>
- </customwidgets>
- <tabstops>
- <tabstop>searchEdit</tabstop>
- <tabstop>searchButton</tabstop>
- <tabstop>packView</tabstop>
- </tabstops>
<resources/>
<connections/>
</ui>
diff --git a/launcher/ui/widgets/CustomCommands.ui b/launcher/ui/widgets/CustomCommands.ui
index dbd54431..650a9cc1 100644
--- a/launcher/ui/widgets/CustomCommands.ui
+++ b/launcher/ui/widgets/CustomCommands.ui
@@ -74,7 +74,7 @@
<item>
<widget class="QLabel" name="labelCustomCmdsDescription">
<property name="text">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Pre-launch command runs before the instance launches and post-exit command runs after it exits.&lt;/p&gt;&lt;p&gt;Both will be run in the launcher's working folder with extra environment variables:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;$INST_NAME - Name of the instance&lt;/li&gt;&lt;li&gt;$INST_ID - ID of the instance (its folder name)&lt;/li&gt;&lt;li&gt;$INST_DIR - absolute path of the instance&lt;/li&gt;&lt;li&gt;$INST_MC_DIR - absolute path of Minecraft&lt;/li&gt;&lt;li&gt;$INST_JAVA - Java binary used for launch&lt;/li&gt;&lt;li&gt;$INST_JAVA_ARGS - command-line parameters used for launch&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Wrapper command allows launching using an extra wrapper program (like 'optirun' on Linux)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Pre-launch command runs before the instance launches and post-exit command runs after it exits.&lt;/p&gt;&lt;p&gt;Both will be run in the launcher's working folder with extra environment variables:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;$INST_NAME - Name of the instance&lt;/li&gt;&lt;li&gt;$INST_ID - ID of the instance (its folder name)&lt;/li&gt;&lt;li&gt;$INST_DIR - absolute path of the instance&lt;/li&gt;&lt;li&gt;$INST_MC_DIR - absolute path of Minecraft&lt;/li&gt;&lt;li&gt;$INST_JAVA - Java binary used for launch&lt;/li&gt;&lt;li&gt;$INST_JAVA_ARGS - command-line parameters used for launch (warning: will not work correctly if arguments contain spaces)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Wrapper command allows launching using an extra wrapper program (like 'optirun' on Linux)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>