aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yml7
-rw-r--r--CMakeLists.txt4
-rw-r--r--README.md20
-rw-r--r--buildconfig/BuildConfig.h6
-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
-rw-r--r--program_info/LICENSE57
51 files changed, 1329 insertions, 419 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b011a779..c2571e91 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -16,13 +16,8 @@ jobs:
include:
- os: ubuntu-20.04
- qt_version: 5.12.8
- qt_host: linux
- os: ubuntu-20.04
- name: Linux-Portable
- qt_version: 5.12.8
- qt_host: linux
portable: true
- os: ubuntu-20.04
@@ -33,12 +28,10 @@ jobs:
- os: windows-2022
name: "Windows-i686"
msystem: mingw32
- portable: false
- os: windows-2022
name: "Windows-x86_64"
msystem: mingw64
- portable: false
- os: windows-2022
name: "Windows-i686-portable"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b97635c1..d45d4975 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -80,7 +80,7 @@ set(Launcher_BUG_TRACKER_URL "https://github.com/PolyMC/PolyMC/issues" CACHE STR
set(Launcher_TRANSLATIONS_URL "https://hosted.weblate.org/projects/polymc/polymc/" CACHE STRING "URL for the translations platform.")
# Matrix Space
-set(Launcher_MATRIX_URL "https://matrix.to/#/#polymc:polymc.org" CACHE STRING "URL to the Matrix Space")
+set(Launcher_MATRIX_URL "https://matrix.to/#/#polymc:matrix.org" CACHE STRING "URL to the Matrix Space")
# Discord URL
set(Launcher_DISCORD_URL "https://discord.gg/Z52pwxWCHP" CACHE STRING "URL for the Discord guild.")
@@ -88,7 +88,7 @@ set(Launcher_DISCORD_URL "https://discord.gg/Z52pwxWCHP" CACHE STRING "URL for t
# Subreddit URL
-set(Launcher_SUBREDDIT_URL "" CACHE STRING "URL for the subreddit.")
+set(Launcher_SUBREDDIT_URL "https://www.reddit.com/r/PolyMCLauncher/" CACHE STRING "URL for the subreddit.")
# Builds
# TODO: Launcher_FORCE_BUNDLED_LIBS should be off in the future, but as of QuaZip 1.2, we can't do that yet.
diff --git a/README.md b/README.md
index a114869c..4c73c47e 100644
--- a/README.md
+++ b/README.md
@@ -33,14 +33,22 @@ Feel free to create an issue if you need help. However, you might find it easier
For people who don't want to use Discord, we have a Matrix Space which is bridged to the Discord server:
-[![PolyMC Space](https://img.shields.io/matrix/polymc:polymc.org?label=PolyMC%20Space&server_fqdn=matrix.polymc.org)](https://matrix.to/#/#polymc:polymc.org)
+[![PolyMC Space](https://img.shields.io/matrix/polymc:matrix.org?label=PolyMC%20space)](https://matrix.to/#/#polymc:matrix.org)
If there are any issues with the space or you are using a client that does not support the feature here are the individual rooms:
-[![Support](https://img.shields.io/matrix/support:polymc.org?label=%23support&server_fqdn=matrix.polymc.org)](https://matrix.to/#/#support:polymc.org)
-[![Discussion](https://img.shields.io/matrix/discussion:polymc.org?label=%23discussion&server_fqdn=matrix.polymc.org)](https://matrix.to/#/#discussion:polymc.org)
-[![Development](https://img.shields.io/matrix/development:polymc.org?label=%23development&server_fqdn=matrix.polymc.org)](https://matrix.to/#/#development:polymc.org)
-[![News](https://img.shields.io/matrix/news:polymc.org?label=%23news&server_fqdn=matrix.polymc.org)](https://matrix.to/#/#news:polymc.org)
+[![Development](https://img.shields.io/matrix/polymc-development:matrix.org?label=PolyMC%20Development)](https://matrix.to/#/#polymc-development:matrix.org)
+[![Discussion](https://img.shields.io/matrix/polymc-discussion:matrix.org?label=PolyMC%20Discussion)](https://matrix.to/#/#polymc-discussion:matrix.org)
+[![Github](https://img.shields.io/matrix/polymc-github:matrix.org?label=PolyMC%20Github)](https://matrix.to/#/#polymc-github:matrix.org)
+[![Maintainers](https://img.shields.io/matrix/polymc-maintainers:matrix.org?label=PolyMC%20Maintainers)](https://matrix.to/#/#polymc-maintainers:matrix.org)
+[![News](https://img.shields.io/matrix/polymc-news:matrix.org?label=PolyMC%20News)](https://matrix.to/#/#polymc-news:matrix.org)
+[![Offtopic](https://img.shields.io/matrix/polymc-offtopic:matrix.org?label=PolyMC%20Offtopic)](https://matrix.to/#/#polymc-offtopic:matrix.org)
+[![Support](https://img.shields.io/matrix/polymc-support:matrix.org?label=PolyMC%20Support)](https://matrix.to/#/#polymc-support:matrix.org)
+[![Voice](https://img.shields.io/matrix/polymc-voice:matrix.org?label=PolyMC%20Voice)](https://matrix.to/#/#polymc-voice:matrix.org)
+
+we also have a subreddit you can post your issues and suggestions on:
+
+[r/PolyMCLauncher](https://www.reddit.com/r/PolyMCLauncher/)
# Development
@@ -77,4 +85,4 @@ All launcher code is available under the GPL-3 license.
[Source for the website](https://github.com/PolyMC/polymc.github.io) is hosted under the AGPL-3 License.
-The logo and related assets are under the CC BY-NC-SA 4.0 license.
+The logo and related assets are under the CC BY-SA 4.0 license.
diff --git a/buildconfig/BuildConfig.h b/buildconfig/BuildConfig.h
index 2fb71f14..6304387c 100644
--- a/buildconfig/BuildConfig.h
+++ b/buildconfig/BuildConfig.h
@@ -140,6 +140,12 @@ public:
QString ATL_DOWNLOAD_SERVER_URL = "https://download.nodecdn.net/containers/atl/";
+ QString TECHNIC_API_BASE_URL = "https://api.technicpack.net/";
+ /**
+ * The build that is reported to the Technic API.
+ */
+ QString TECHNIC_API_BUILD = "multimc";
+
/**
* \brief Converts the Version to a string.
* \return The version number in string format (major.minor.revision.build).
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>
diff --git a/program_info/LICENSE b/program_info/LICENSE
index 40cc6059..c68207dc 100644
--- a/program_info/LICENSE
+++ b/program_info/LICENSE
@@ -1,4 +1,4 @@
-Attribution-NonCommercial-ShareAlike 4.0 International
+Attribution-ShareAlike 4.0 International
This license only applies to the logos and branding in this folder.
@@ -56,18 +56,18 @@ exhaustive, and do not form part of our licenses.
=======================================================================
-Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
-Public License
+Creative Commons Attribution-ShareAlike 4.0 International Public
+License
By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
-Attribution-NonCommercial-ShareAlike 4.0 International Public License
-("Public License"). To the extent this Public License may be
-interpreted as a contract, You are granted the Licensed Rights in
-consideration of Your acceptance of these terms and conditions, and the
-Licensor grants You such rights in consideration of benefits the
-Licensor receives from making the Licensed Material available under
-these terms and conditions.
+Attribution-ShareAlike 4.0 International Public License ("Public
+License"). To the extent this Public License may be interpreted as a
+contract, You are granted the Licensed Rights in consideration of Your
+acceptance of these terms and conditions, and the Licensor grants You
+such rights in consideration of benefits the Licensor receives from
+making the Licensed Material available under these terms and
+conditions.
Section 1 -- Definitions.
@@ -86,7 +86,7 @@ Section 1 -- Definitions.
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.
- c. BY-NC-SA Compatible License means a license listed at
+ c. BY-SA Compatible License means a license listed at
creativecommons.org/compatiblelicenses, approved by Creative
Commons as essentially the equivalent of this Public License.
@@ -110,7 +110,7 @@ Section 1 -- Definitions.
g. License Elements means the license attributes listed in the name
of a Creative Commons Public License. The License Elements of this
- Public License are Attribution, NonCommercial, and ShareAlike.
+ Public License are Attribution and ShareAlike.
h. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
@@ -124,15 +124,7 @@ Section 1 -- Definitions.
j. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.
- k. NonCommercial means not primarily intended for or directed towards
- commercial advantage or monetary compensation. For purposes of
- this Public License, the exchange of the Licensed Material for
- other material subject to Copyright and Similar Rights by digital
- file-sharing or similar means is NonCommercial provided there is
- no payment of monetary compensation in connection with the
- exchange.
-
- l. Share means to provide material to the public by any means or
+ k. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
@@ -140,13 +132,13 @@ Section 1 -- Definitions.
public may access the material from a place and at a time
individually chosen by them.
- m. Sui Generis Database Rights means rights other than copyright
+ l. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.
- n. You means the individual or entity exercising the Licensed Rights
+ m. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.
@@ -160,10 +152,9 @@ Section 2 -- Scope.
exercise the Licensed Rights in the Licensed Material to:
a. reproduce and Share the Licensed Material, in whole or
- in part, for NonCommercial purposes only; and
+ in part; and
- b. produce, reproduce, and Share Adapted Material for
- NonCommercial purposes only.
+ b. produce, reproduce, and Share Adapted Material.
2. Exceptions and Limitations. For the avoidance of doubt, where
Exceptions and Limitations apply to Your use, this Public
@@ -231,9 +222,7 @@ Section 2 -- Scope.
Rights, whether directly or through a collecting society
under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly
- reserves any right to collect such royalties, including when
- the Licensed Material is used other than for NonCommercial
- purposes.
+ reserves any right to collect such royalties.
Section 3 -- License Conditions.
@@ -278,6 +267,7 @@ following conditions.
reasonable to satisfy the conditions by providing a URI or
hyperlink to a resource that includes the required
information.
+
3. If requested by the Licensor, You must remove any of the
information required by Section 3(a)(1)(A) to the extent
reasonably practicable.
@@ -289,7 +279,7 @@ following conditions.
1. The Adapter's License You apply must be a Creative Commons
license with the same License Elements, this version or
- later, or a BY-NC-SA Compatible License.
+ later, or a BY-SA Compatible License.
2. You must include the text of, or the URI or hyperlink to, the
Adapter's License You apply. You may satisfy this condition
@@ -309,15 +299,14 @@ apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
to extract, reuse, reproduce, and Share all or a substantial
- portion of the contents of the database for NonCommercial purposes
- only;
+ portion of the contents of the database;
b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
Rights (but not its individual contents) is Adapted Material,
- including for purposes of Section 3(b); and
+ including for purposes of Section 3(b); and
c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.
@@ -417,6 +406,7 @@ Section 8 -- Interpretation.
that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.
+
=======================================================================
Creative Commons is not a party to its public
@@ -437,3 +427,4 @@ the avoidance of doubt, this paragraph does not form part of the
public licenses.
Creative Commons may be contacted at creativecommons.org.
+