diff options
Diffstat (limited to 'launcher/minecraft')
38 files changed, 624 insertions, 155 deletions
diff --git a/launcher/minecraft/ComponentUpdateTask.cpp b/launcher/minecraft/ComponentUpdateTask.cpp index ff7ed0af..6db21622 100644 --- a/launcher/minecraft/ComponentUpdateTask.cpp +++ b/launcher/minecraft/ComponentUpdateTask.cpp @@ -197,6 +197,10 @@ void ComponentUpdateTask::loadComponents() { remoteLoadFailed(taskIndex, error); }); + connect(indexLoadTask.get(), &Task::aborted, [=]() + { + remoteLoadFailed(taskIndex, tr("Aborted")); + }); taskIndex++; } } @@ -243,6 +247,10 @@ void ComponentUpdateTask::loadComponents() { remoteLoadFailed(taskIndex, error); }); + connect(loadTask.get(), &Task::aborted, [=]() + { + remoteLoadFailed(taskIndex, tr("Aborted")); + }); RemoteLoadStatus status; status.type = loadType; status.PackProfileIndex = componentIndex; diff --git a/launcher/minecraft/GradleSpecifier.h b/launcher/minecraft/GradleSpecifier.h index d9bb0207..27514ab9 100644 --- a/launcher/minecraft/GradleSpecifier.h +++ b/launcher/minecraft/GradleSpecifier.h @@ -1,7 +1,43 @@ +// 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 <QStringList> +#include <QRegularExpression> #include "DefaultVariable.h" struct GradleSpecifier @@ -25,20 +61,21 @@ struct GradleSpecifier 4 "jdk15" 5 "jar" */ - QRegExp matcher("([^:@]+):([^:@]+):([^:@]+)" "(?::([^:@]+))?" "(?:@([^:@]+))?"); - m_valid = matcher.exactMatch(value); + QRegularExpression matcher(QRegularExpression::anchoredPattern("([^:@]+):([^:@]+):([^:@]+)" "(?::([^:@]+))?" "(?:@([^:@]+))?")); + QRegularExpressionMatch match = matcher.match(value); + m_valid = match.hasMatch(); if(!m_valid) { m_invalidValue = value; return *this; } - auto elements = matcher.capturedTexts(); - m_groupId = elements[1]; - m_artifactId = elements[2]; - m_version = elements[3]; - m_classifier = elements[4]; - if(!elements[5].isEmpty()) + auto elements = match.captured(); + m_groupId = match.captured(1); + m_artifactId = match.captured(2); + m_version = match.captured(3); + m_classifier = match.captured(4); + if(match.lastCapturedIndex() >= 5) { - m_extension = elements[5]; + m_extension = match.captured(5); } return *this; } diff --git a/launcher/minecraft/GradleSpecifier_test.cpp b/launcher/minecraft/GradleSpecifier_test.cpp index 0900c9d8..a062dfac 100644 --- a/launcher/minecraft/GradleSpecifier_test.cpp +++ b/launcher/minecraft/GradleSpecifier_test.cpp @@ -1,5 +1,4 @@ #include <QTest> -#include "TestUtil.h" #include "minecraft/GradleSpecifier.h" diff --git a/launcher/minecraft/Library_test.cpp b/launcher/minecraft/Library_test.cpp index 47531ad6..834dd558 100644 --- a/launcher/minecraft/Library_test.cpp +++ b/launcher/minecraft/Library_test.cpp @@ -1,5 +1,4 @@ #include <QTest> -#include "TestUtil.h" #include "minecraft/MojangVersionFormat.h" #include "minecraft/OneSixVersionFormat.h" @@ -11,15 +10,14 @@ class LibraryTest : public QObject { Q_OBJECT private: - LibraryPtr readMojangJson(const char *file) + LibraryPtr readMojangJson(const QString path) { - auto path = QFINDTESTDATA(file); QFile jsonFile(path); jsonFile.open(QIODevice::ReadOnly); auto data = jsonFile.readAll(); jsonFile.close(); ProblemContainer problems; - return MojangVersionFormat::libraryFromJson(problems, QJsonDocument::fromJson(data).object(), file); + return MojangVersionFormat::libraryFromJson(problems, QJsonDocument::fromJson(data).object(), path); } // get absolute path to expected storage, assuming default cache prefix QStringList getStorage(QString relative) @@ -32,7 +30,7 @@ slots: { cache.reset(new HttpMetaCache()); cache->addBase("libraries", QDir("libraries").absolutePath()); - dataDir = QDir("data").absolutePath(); + dataDir = QDir(QFINDTESTDATA("testdata")).absolutePath(); } void test_legacy() { @@ -74,14 +72,14 @@ slots: QCOMPARE(test.isNative(), false); QStringList failedFiles; test.setHint("local"); - auto downloads = test.getDownloads(currentSystem, cache.get(), failedFiles, QString("data")); + auto downloads = test.getDownloads(currentSystem, cache.get(), failedFiles, QFINDTESTDATA("testdata")); QCOMPARE(downloads.size(), 0); qDebug() << failedFiles; QCOMPARE(failedFiles.size(), 0); QStringList jar, native, native32, native64; - test.getApplicableFiles(currentSystem, jar, native, native32, native64, QString("data")); - QCOMPARE(jar, {QFileInfo("data/codecwav-20101023.jar").absoluteFilePath()}); + test.getApplicableFiles(currentSystem, jar, native, native32, native64, QFINDTESTDATA("testdata")); + QCOMPARE(jar, {QFileInfo(QFINDTESTDATA("testdata/codecwav-20101023.jar")).absoluteFilePath()}); QCOMPARE(native, {}); QCOMPARE(native32, {}); QCOMPARE(native64, {}); @@ -167,20 +165,20 @@ slots: test.setRepositoryURL("file://foo/bar"); { QStringList jar, native, native32, native64; - test.getApplicableFiles(Os_Linux, jar, native, native32, native64, QString("data")); + test.getApplicableFiles(Os_Linux, jar, native, native32, native64, QFINDTESTDATA("testdata")); QCOMPARE(jar, {}); QCOMPARE(native, {}); - QCOMPARE(native32, {QFileInfo("data/testname-testversion-linux-32.jar").absoluteFilePath()}); - QCOMPARE(native64, {QFileInfo("data/testname-testversion-linux-64.jar").absoluteFilePath()}); + QCOMPARE(native32, {QFileInfo(QFINDTESTDATA("testdata/testname-testversion-linux-32.jar")).absoluteFilePath()}); + QCOMPARE(native64, {QFileInfo(QFINDTESTDATA("testdata") + "/testname-testversion-linux-64.jar").absoluteFilePath()}); QStringList failedFiles; - auto dls = test.getDownloads(Os_Linux, cache.get(), failedFiles, QString("data")); + auto dls = test.getDownloads(Os_Linux, cache.get(), failedFiles, QFINDTESTDATA("testdata")); QCOMPARE(dls.size(), 0); - QCOMPARE(failedFiles, {"data/testname-testversion-linux-64.jar"}); + QCOMPARE(failedFiles, {QFileInfo(QFINDTESTDATA("testdata") + "/testname-testversion-linux-64.jar").absoluteFilePath()}); } } void test_onenine() { - auto test = readMojangJson("data/lib-simple.json"); + auto test = readMojangJson(QFINDTESTDATA("testdata/lib-simple.json")); { QStringList jar, native, native32, native64; test->getApplicableFiles(Os_OSX, jar, native, native32, native64, QString()); @@ -199,41 +197,41 @@ slots: test->setHint("local"); { QStringList jar, native, native32, native64; - test->getApplicableFiles(Os_OSX, jar, native, native32, native64, QString("data")); - QCOMPARE(jar, {QFileInfo("data/codecwav-20101023.jar").absoluteFilePath()}); + test->getApplicableFiles(Os_OSX, jar, native, native32, native64, QFINDTESTDATA("testdata")); + QCOMPARE(jar, {QFileInfo(QFINDTESTDATA("testdata/codecwav-20101023.jar")).absoluteFilePath()}); QCOMPARE(native, {}); QCOMPARE(native32, {}); QCOMPARE(native64, {}); } { QStringList failedFiles; - auto dls = test->getDownloads(Os_Linux, cache.get(), failedFiles, QString("data")); + auto dls = test->getDownloads(Os_Linux, cache.get(), failedFiles, QFINDTESTDATA("testdata")); QCOMPARE(dls.size(), 0); QCOMPARE(failedFiles, {}); } } void test_onenine_local_override() { - auto test = readMojangJson("data/lib-simple.json"); + auto test = readMojangJson(QFINDTESTDATA("testdata/lib-simple.json")); test->setHint("local"); { QStringList jar, native, native32, native64; - test->getApplicableFiles(Os_OSX, jar, native, native32, native64, QString("data")); - QCOMPARE(jar, {QFileInfo("data/codecwav-20101023.jar").absoluteFilePath()}); + test->getApplicableFiles(Os_OSX, jar, native, native32, native64, QFINDTESTDATA("testdata")); + QCOMPARE(jar, {QFileInfo(QFINDTESTDATA("testdata/codecwav-20101023.jar")).absoluteFilePath()}); QCOMPARE(native, {}); QCOMPARE(native32, {}); QCOMPARE(native64, {}); } { QStringList failedFiles; - auto dls = test->getDownloads(Os_Linux, cache.get(), failedFiles, QString("data")); + auto dls = test->getDownloads(Os_Linux, cache.get(), failedFiles, QFINDTESTDATA("testdata")); QCOMPARE(dls.size(), 0); QCOMPARE(failedFiles, {}); } } void test_onenine_native() { - auto test = readMojangJson("data/lib-native.json"); + auto test = readMojangJson(QFINDTESTDATA("testdata/lib-native.json")); QStringList jar, native, native32, native64; test->getApplicableFiles(Os_OSX, jar, native, native32, native64, QString()); QCOMPARE(jar, QStringList()); @@ -248,7 +246,7 @@ slots: } void test_onenine_native_arch() { - auto test = readMojangJson("data/lib-native-arch.json"); + auto test = readMojangJson(QFINDTESTDATA("testdata/lib-native-arch.json")); QStringList jar, native, native32, native64; test->getApplicableFiles(Os_Windows, jar, native, native32, native64, QString()); QCOMPARE(jar, {}); diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 7e72601f..abc022b6 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -154,6 +154,12 @@ MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsO m_settings->registerOverride(globalSettings->getSetting("UseNativeOpenAL"), nativeLibraryWorkaroundsOverride); m_settings->registerOverride(globalSettings->getSetting("UseNativeGLFW"), nativeLibraryWorkaroundsOverride); + // Peformance related options + auto performanceOverride = m_settings->registerSetting("OverridePerformance", false); + m_settings->registerOverride(globalSettings->getSetting("EnableFeralGamemode"), performanceOverride); + m_settings->registerOverride(globalSettings->getSetting("EnableMangoHud"), performanceOverride); + m_settings->registerOverride(globalSettings->getSetting("UseDiscreteGpu"), performanceOverride); + // Game time auto gameTimeOverride = m_settings->registerSetting("OverrideGameTime", false); m_settings->registerOverride(globalSettings->getSetting("ShowGameTime"), gameTimeOverride); @@ -435,27 +441,57 @@ QProcessEnvironment MinecraftInstance::createEnvironment() return env; } +QProcessEnvironment MinecraftInstance::createLaunchEnvironment() +{ + // prepare the process environment + QProcessEnvironment env = createEnvironment(); + +#ifdef Q_OS_LINUX + if (settings()->get("EnableMangoHud").toBool()) + { + auto preload = env.value("LD_PRELOAD", "") + ":libMangoHud_dlsym.so:libMangoHud.so"; + auto lib_path = env.value("LD_LIBRARY_PATH", "") + ":/usr/local/$LIB/mangohud/:/usr/$LIB/mangohud/"; + + env.insert("LD_PRELOAD", preload); + env.insert("LD_LIBRARY_PATH", lib_path); + env.insert("MANGOHUD", "1"); + } + + if (settings()->get("UseDiscreteGpu").toBool()) + { + // Open Source Drivers + env.insert("DRI_PRIME", "1"); + // Proprietary Nvidia Drivers + env.insert("__NV_PRIME_RENDER_OFFLOAD", "1"); + env.insert("__VK_LAYER_NV_optimus", "NVIDIA_only"); + env.insert("__GLX_VENDOR_LIBRARY_NAME", "nvidia"); + } +#endif + + return env; +} + static QString replaceTokensIn(QString text, QMap<QString, QString> with) { + // TODO: does this still work?? QString result; - QRegExp token_regexp("\\$\\{(.+)\\}"); - token_regexp.setMinimal(true); + QRegularExpression token_regexp("\\$\\{(.+)\\}", QRegularExpression::InvertedGreedinessOption); QStringList list; - int tail = 0; - int head = 0; - while ((head = token_regexp.indexIn(text, head)) != -1) + QRegularExpressionMatchIterator i = token_regexp.globalMatch(text); + int lastCapturedEnd = 0; + while (i.hasNext()) { - result.append(text.mid(tail, head - tail)); - QString key = token_regexp.cap(1); + QRegularExpressionMatch match = i.next(); + result.append(text.mid(lastCapturedEnd, match.capturedStart())); + QString key = match.captured(1); auto iter = with.find(key); if (iter != with.end()) { result.append(*iter); } - head += token_regexp.matchedLength(); - tail = head; + lastCapturedEnd = match.capturedEnd(); } - result.append(text.mid(tail)); + result.append(text.mid(lastCapturedEnd)); return result; } @@ -504,7 +540,11 @@ QStringList MinecraftInstance::processMinecraftArgs( token_mapping["assets_root"] = absAssetsDir; token_mapping["assets_index_name"] = assets->id; +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) + QStringList parts = args_pattern.split(' ', Qt::SkipEmptyParts); +#else QStringList parts = args_pattern.split(' ', QString::SkipEmptyParts); +#endif for (int i = 0; i < parts.length(); i++) { parts[i] = replaceTokensIn(parts[i], token_mapping); @@ -747,7 +787,9 @@ QMap<QString, QString> MinecraftInstance::createCensorFilterFromSession(AuthSess { addToFilter(sessionRef.session, tr("<SESSION ID>")); } - addToFilter(sessionRef.access_token, tr("<ACCESS TOKEN>")); + if (sessionRef.access_token != "offline") { + addToFilter(sessionRef.access_token, tr("<ACCESS TOKEN>")); + } if(sessionRef.client_token.size()) { addToFilter(sessionRef.client_token, tr("<CLIENT TOKEN>")); } @@ -826,8 +868,16 @@ QString MinecraftInstance::getStatusbarDescription() traits.append(tr("broken")); } + QString mcVersion = m_components->getComponentVersion("net.minecraft"); + if (mcVersion.isEmpty()) + { + // Load component info if needed + m_components->reload(Net::Mode::Offline); + mcVersion = m_components->getComponentVersion("net.minecraft"); + } + QString description; - description.append(tr("Minecraft %1 (%2)").arg(m_components->getComponentVersion("net.minecraft")).arg(typeName())); + description.append(tr("Minecraft %1").arg(mcVersion)); if(m_settings->get("ShowGameTime").toBool()) { if (lastTimePlayed() > 0) { diff --git a/launcher/minecraft/MinecraftInstance.h b/launcher/minecraft/MinecraftInstance.h index fda58aa7..05450d41 100644 --- a/launcher/minecraft/MinecraftInstance.h +++ b/launcher/minecraft/MinecraftInstance.h @@ -91,6 +91,7 @@ public: /// create an environment for launching processes QProcessEnvironment createEnvironment() override; + QProcessEnvironment createLaunchEnvironment() override; /// guess log level from a line of minecraft log MessageLevel::Enum guessLevel(const QString &line, MessageLevel::Enum level) override; diff --git a/launcher/minecraft/MinecraftLoadAndCheck.cpp b/launcher/minecraft/MinecraftLoadAndCheck.cpp index 79b0c484..d72bc7be 100644 --- a/launcher/minecraft/MinecraftLoadAndCheck.cpp +++ b/launcher/minecraft/MinecraftLoadAndCheck.cpp @@ -20,6 +20,7 @@ void MinecraftLoadAndCheck::executeTask() } connect(m_task.get(), &Task::succeeded, this, &MinecraftLoadAndCheck::subtaskSucceeded); connect(m_task.get(), &Task::failed, this, &MinecraftLoadAndCheck::subtaskFailed); + connect(m_task.get(), &Task::aborted, this, [this]{ subtaskFailed(tr("Aborted")); }); connect(m_task.get(), &Task::progress, this, &MinecraftLoadAndCheck::progress); connect(m_task.get(), &Task::status, this, &MinecraftLoadAndCheck::setStatus); } diff --git a/launcher/minecraft/MinecraftUpdate.cpp b/launcher/minecraft/MinecraftUpdate.cpp index 32e9cbb6..0ce0c347 100644 --- a/launcher/minecraft/MinecraftUpdate.cpp +++ b/launcher/minecraft/MinecraftUpdate.cpp @@ -98,6 +98,7 @@ void MinecraftUpdate::next() auto task = m_tasks[m_currentTask - 1]; disconnect(task.get(), &Task::succeeded, this, &MinecraftUpdate::subtaskSucceeded); disconnect(task.get(), &Task::failed, this, &MinecraftUpdate::subtaskFailed); + disconnect(task.get(), &Task::aborted, this, &Task::abort); disconnect(task.get(), &Task::progress, this, &MinecraftUpdate::progress); disconnect(task.get(), &Task::status, this, &MinecraftUpdate::setStatus); } @@ -115,6 +116,7 @@ void MinecraftUpdate::next() } connect(task.get(), &Task::succeeded, this, &MinecraftUpdate::subtaskSucceeded); connect(task.get(), &Task::failed, this, &MinecraftUpdate::subtaskFailed); + connect(task.get(), &Task::aborted, this, &Task::abort); connect(task.get(), &Task::progress, this, &MinecraftUpdate::progress); connect(task.get(), &Task::status, this, &MinecraftUpdate::setStatus); // if the task is already running, do not start it again diff --git a/launcher/minecraft/MinecraftUpdate.h b/launcher/minecraft/MinecraftUpdate.h index 9ebef656..acf2eb86 100644 --- a/launcher/minecraft/MinecraftUpdate.h +++ b/launcher/minecraft/MinecraftUpdate.h @@ -27,6 +27,8 @@ class MinecraftVersion; class MinecraftInstance; +// FIXME: This looks very similar to a SequentialTask. Maybe we can reduce code duplications? :^) + class MinecraftUpdate : public Task { Q_OBJECT diff --git a/launcher/minecraft/MojangVersionFormat_test.cpp b/launcher/minecraft/MojangVersionFormat_test.cpp index 9d095340..71df784b 100644 --- a/launcher/minecraft/MojangVersionFormat_test.cpp +++ b/launcher/minecraft/MojangVersionFormat_test.cpp @@ -1,6 +1,5 @@ #include <QTest> #include <QDebug> -#include "TestUtil.h" #include "minecraft/MojangVersionFormat.h" @@ -8,9 +7,8 @@ class MojangVersionFormatTest : public QObject { Q_OBJECT - static QJsonDocument readJson(const char *file) + static QJsonDocument readJson(const QString path) { - auto path = QFINDTESTDATA(file); QFile jsonFile(path); jsonFile.open(QIODevice::ReadOnly); auto data = jsonFile.readAll(); @@ -31,7 +29,7 @@ private slots: void test_Through_Simple() { - QJsonDocument doc = readJson("data/1.9-simple.json"); + QJsonDocument doc = readJson(QFINDTESTDATA("testdata/1.9-simple.json")); auto vfile = MojangVersionFormat::versionFileFromJson(doc, "1.9-simple.json"); auto doc2 = MojangVersionFormat::versionFileToJson(vfile); writeJson("1.9-simple-passthorugh.json", doc2); @@ -41,7 +39,7 @@ slots: void test_Through() { - QJsonDocument doc = readJson("data/1.9.json"); + QJsonDocument doc = readJson(QFINDTESTDATA("testdata/1.9.json")); auto vfile = MojangVersionFormat::versionFileFromJson(doc, "1.9.json"); auto doc2 = MojangVersionFormat::versionFileToJson(vfile); writeJson("1.9-passthorugh.json", doc2); diff --git a/launcher/minecraft/OneSixVersionFormat.cpp b/launcher/minecraft/OneSixVersionFormat.cpp index 879f18c1..cec4a55b 100644 --- a/launcher/minecraft/OneSixVersionFormat.cpp +++ b/launcher/minecraft/OneSixVersionFormat.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 "OneSixVersionFormat.h" #include <Json.h> #include "minecraft/Agent.h" @@ -296,7 +331,7 @@ QJsonDocument OneSixVersionFormat::versionFileToJson(const VersionFilePtr &patch } writeString(root, "appletClass", patch->appletClass); writeStringList(root, "+tweakers", patch->addTweakers); - writeStringList(root, "+traits", patch->traits.toList()); + writeStringList(root, "+traits", patch->traits.values()); if (!patch->libraries.isEmpty()) { QJsonArray array; diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp index 125048f0..5e76b892 100644 --- a/launcher/minecraft/PackProfile.cpp +++ b/launcher/minecraft/PackProfile.cpp @@ -1,16 +1,36 @@ -/* Copyright 2013-2021 MultiMC Contributors +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * - * 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 <QFile> @@ -346,6 +366,7 @@ void PackProfile::resolve(Net::Mode netmode) d->m_updateTask.reset(updateTask); connect(updateTask, &ComponentUpdateTask::succeeded, this, &PackProfile::updateSucceeded); connect(updateTask, &ComponentUpdateTask::failed, this, &PackProfile::updateFailed); + connect(updateTask, &ComponentUpdateTask::aborted, this, [this]{ updateFailed(tr("Aborted")); }); d->m_updateTask->start(); } @@ -687,7 +708,11 @@ void PackProfile::move(const int index, const MoveDirection direction) return; } beginMoveRows(QModelIndex(), index, index, QModelIndex(), togap); +#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) + d->components.swapItemsAt(index, theirIndex); +#else d->components.swap(index, theirIndex); +#endif endMoveRows(); invalidateLaunchProfile(); scheduleSave(); diff --git a/launcher/minecraft/ParseUtils_test.cpp b/launcher/minecraft/ParseUtils_test.cpp index fcc137e5..7721a46d 100644 --- a/launcher/minecraft/ParseUtils_test.cpp +++ b/launcher/minecraft/ParseUtils_test.cpp @@ -1,5 +1,4 @@ #include <QTest> -#include "TestUtil.h" #include "minecraft/ParseUtils.h" @@ -42,4 +41,3 @@ slots: QTEST_GUILESS_MAIN(ParseUtilsTest) #include "ParseUtils_test.moc" - diff --git a/launcher/minecraft/ProfileUtils.cpp b/launcher/minecraft/ProfileUtils.cpp index 8ca24cc8..03f8c198 100644 --- a/launcher/minecraft/ProfileUtils.cpp +++ b/launcher/minecraft/ProfileUtils.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 "ProfileUtils.h" #include "minecraft/VersionFilterData.h" #include "minecraft/OneSixVersionFormat.h" @@ -141,24 +176,6 @@ bool saveJsonFile(const QJsonDocument doc, const QString & filename) return true; } -VersionFilePtr parseBinaryJsonFile(const QFileInfo &fileInfo) -{ - QFile file(fileInfo.absoluteFilePath()); - if (!file.open(QFile::ReadOnly)) - { - auto errorStr = QObject::tr("Unable to open the version file %1: %2.").arg(fileInfo.fileName(), file.errorString()); - return createErrorVersionFile(fileInfo.completeBaseName(), fileInfo.absoluteFilePath(), errorStr); - } - QJsonDocument doc = QJsonDocument::fromBinaryData(file.readAll()); - file.close(); - if (doc.isNull()) - { - file.remove(); - throw JSONValidationError(QObject::tr("Unable to process the version file %1.").arg(fileInfo.fileName())); - } - return guardedParseJson(doc, fileInfo.completeBaseName(), fileInfo.absoluteFilePath(), false); -} - void removeLwjglFromPatch(VersionFilePtr patch) { auto filter = [](QList<LibraryPtr>& libs) diff --git a/launcher/minecraft/ProfileUtils.h b/launcher/minecraft/ProfileUtils.h index 351c36cb..5b938784 100644 --- a/launcher/minecraft/ProfileUtils.h +++ b/launcher/minecraft/ProfileUtils.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 "Library.h" #include "VersionFile.h" @@ -19,9 +54,6 @@ VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder) /// Save a JSON file (in any format) bool saveJsonFile(const QJsonDocument doc, const QString & filename); -/// Parse a version file in binary JSON format -VersionFilePtr parseBinaryJsonFile(const QFileInfo &fileInfo); - /// Remove LWJGL from a patch file. This is applied to all Mojang-like profile files. void removeLwjglFromPatch(VersionFilePtr patch); diff --git a/launcher/minecraft/VersionFile.cpp b/launcher/minecraft/VersionFile.cpp index f242fbe7..a9a0f7f4 100644 --- a/launcher/minecraft/VersionFile.cpp +++ b/launcher/minecraft/VersionFile.cpp @@ -89,14 +89,3 @@ void VersionFile::applyTo(LaunchProfile *profile) } profile->applyProblemSeverity(getProblemSeverity()); } - -/* - auto theirVersion = profile->getMinecraftVersion(); - if (!theirVersion.isNull() && !dependsOnMinecraftVersion.isNull()) - { - if (QRegExp(dependsOnMinecraftVersion, Qt::CaseInsensitive, QRegExp::Wildcard).indexIn(theirVersion) == -1) - { - throw MinecraftVersionMismatch(uid, dependsOnMinecraftVersion, theirVersion); - } - } -*/ diff --git a/launcher/minecraft/World.cpp b/launcher/minecraft/World.cpp index dc756e06..dfcb43d8 100644 --- a/launcher/minecraft/World.cpp +++ b/launcher/minecraft/World.cpp @@ -1,16 +1,36 @@ -/* Copyright 2015-2021 MultiMC Contributors +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * - * 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 <QDir> @@ -321,7 +341,8 @@ bool World::install(const QString &to, const QString &name) if(ok && !name.isEmpty() && m_actualName != name) { - World newWorld(finalPath); + QFileInfo finalPathInfo(finalPath); + World newWorld(finalPathInfo); if(newWorld.isValid()) { newWorld.rename(name); diff --git a/launcher/minecraft/WorldList.cpp b/launcher/minecraft/WorldList.cpp index 955609bf..aee7be35 100644 --- a/launcher/minecraft/WorldList.cpp +++ b/launcher/minecraft/WorldList.cpp @@ -1,16 +1,36 @@ -/* Copyright 2015-2021 MultiMC Contributors +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * - * 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 "WorldList.h" @@ -195,7 +215,7 @@ QVariant WorldList::data(const QModelIndex &index, int role) const switch (column) { case SizeColumn: - return qVariantFromValue<qlonglong>(world.bytes()); + return QVariant::fromValue<qlonglong>(world.bytes()); default: return data(index, Qt::DisplayRole); @@ -215,7 +235,7 @@ QVariant WorldList::data(const QModelIndex &index, int role) const } case SeedRole: { - return qVariantFromValue<qlonglong>(world.seed()); + return QVariant::fromValue<qlonglong>(world.seed()); } case NameRole: { @@ -227,7 +247,7 @@ QVariant WorldList::data(const QModelIndex &index, int role) const } case SizeRole: { - return qVariantFromValue<qlonglong>(world.bytes()); + return QVariant::fromValue<qlonglong>(world.bytes()); } case IconFileRole: { @@ -301,7 +321,11 @@ public: } protected: +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + QVariant retrieveData(const QString &mimetype, QMetaType type) const +#else QVariant retrieveData(const QString &mimetype, QVariant::Type type) const +#endif { QList<QUrl> urls; for(auto &world: m_worlds) diff --git a/launcher/minecraft/auth/AccountData.cpp b/launcher/minecraft/auth/AccountData.cpp index dd9c3f8f..44f7e256 100644 --- a/launcher/minecraft/auth/AccountData.cpp +++ b/launcher/minecraft/auth/AccountData.cpp @@ -39,6 +39,7 @@ #include <QJsonArray> #include <QDebug> #include <QUuid> +#include <QRegularExpression> namespace { void tokenToJSONV3(QJsonObject &parent, Katabasis::Token t, const char * tokenName) { @@ -451,7 +452,7 @@ void AccountData::invalidateClientToken() { if(type != AccountType::Mojang) { return; } - yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegExp("[{-}]")); + yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegularExpression("[{-}]")); } QString AccountData::profileId() const { @@ -473,7 +474,7 @@ QString AccountData::accountDisplayString() const { return userName(); } case AccountType::Offline: { - return userName(); + return QObject::tr("<Offline>"); } case AccountType::MSA: { if(xboxApiToken.extra.contains("gtg")) { diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp index 3422df7c..2b851e18 100644 --- a/launcher/minecraft/auth/AccountList.cpp +++ b/launcher/minecraft/auth/AccountList.cpp @@ -282,6 +282,10 @@ QVariant AccountList::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { + case ProfileNameColumn: { + return account->profileName(); + } + case NameColumn: return account->accountDisplayString(); @@ -300,7 +304,7 @@ QVariant AccountList::data(const QModelIndex &index, int role) const return tr("Offline", "Account status"); } case AccountState::Online: { - return tr("Online", "Account status"); + return tr("Ready", "Account status"); } case AccountState::Working: { return tr("Working", "Account status"); @@ -320,10 +324,6 @@ QVariant AccountList::data(const QModelIndex &index, int role) const } } - case ProfileNameColumn: { - return account->profileName(); - } - case MigrationColumn: { if(account->isMSA() || account->isOffline()) { return tr("N/A", "Can Migrate?"); @@ -349,7 +349,7 @@ QVariant AccountList::data(const QModelIndex &index, int role) const case Qt::CheckStateRole: switch (index.column()) { - case NameColumn: + case ProfileNameColumn: return account == m_defaultAccount ? Qt::Checked : Qt::Unchecked; } @@ -365,6 +365,8 @@ QVariant AccountList::headerData(int section, Qt::Orientation orientation, int r case Qt::DisplayRole: switch (section) { + case ProfileNameColumn: + return tr("Username"); case NameColumn: return tr("Account"); case TypeColumn: @@ -373,8 +375,6 @@ QVariant AccountList::headerData(int section, Qt::Orientation orientation, int r return tr("Status"); case MigrationColumn: return tr("Can Migrate?"); - case ProfileNameColumn: - return tr("Profile"); default: return QVariant(); } @@ -382,6 +382,8 @@ QVariant AccountList::headerData(int section, Qt::Orientation orientation, int r case Qt::ToolTipRole: switch (section) { + case ProfileNameColumn: + return tr("Minecraft username associated with the account."); case NameColumn: return tr("User name of the account."); case TypeColumn: @@ -389,9 +391,7 @@ QVariant AccountList::headerData(int section, Qt::Orientation orientation, int r case StatusColumn: return tr("Current status of the account."); case MigrationColumn: - return tr("Can this account migrate to Microsoft account?"); - case ProfileNameColumn: - return tr("Name of the Minecraft profile associated with the account."); + return tr("Can this account migrate to a Microsoft account?"); default: return QVariant(); } diff --git a/launcher/minecraft/auth/AccountList.h b/launcher/minecraft/auth/AccountList.h index baaf7414..8136a92e 100644 --- a/launcher/minecraft/auth/AccountList.h +++ b/launcher/minecraft/auth/AccountList.h @@ -58,8 +58,8 @@ public: enum VListColumns { // TODO: Add icon column. - NameColumn = 0, - ProfileNameColumn, + ProfileNameColumn = 0, + NameColumn, MigrationColumn, TypeColumn, StatusColumn, diff --git a/launcher/minecraft/auth/AccountTask.cpp b/launcher/minecraft/auth/AccountTask.cpp index 49b6e46f..4118c3c5 100644 --- a/launcher/minecraft/auth/AccountTask.cpp +++ b/launcher/minecraft/auth/AccountTask.cpp @@ -79,6 +79,8 @@ QString AccountTask::getStateMessage() const bool AccountTask::changeState(AccountTaskState newState, QString reason) { m_taskState = newState; + // FIXME: virtual method invoked in constructor. + // We want that behavior, but maybe make it less weird? setStatus(getStateMessage()); switch(newState) { case AccountTaskState::STATE_CREATED: { diff --git a/launcher/minecraft/auth/AuthRequest.cpp b/launcher/minecraft/auth/AuthRequest.cpp index feface80..bb82e1e2 100644 --- a/launcher/minecraft/auth/AuthRequest.cpp +++ b/launcher/minecraft/auth/AuthRequest.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 <cassert> #include <QDebug> @@ -20,7 +55,11 @@ void AuthRequest::get(const QNetworkRequest &req, int timeout/* = 60*1000*/) { reply_ = APPLICATION->network()->get(request_); status_ = Requesting; timedReplies_.add(new Katabasis::Reply(reply_, timeout)); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError))); +#else connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError))); +#endif connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished())); connect(reply_, &QNetworkReply::sslErrors, this, &AuthRequest::onSslErrors); } @@ -31,7 +70,11 @@ void AuthRequest::post(const QNetworkRequest &req, const QByteArray &data, int t status_ = Requesting; reply_ = APPLICATION->network()->post(request_, data_); timedReplies_.add(new Katabasis::Reply(reply_, timeout)); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError))); +#else connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError))); +#endif connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished())); connect(reply_, &QNetworkReply::sslErrors, this, &AuthRequest::onSslErrors); connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64))); diff --git a/launcher/minecraft/auth/MinecraftAccount.cpp b/launcher/minecraft/auth/MinecraftAccount.cpp index ec86fa5c..a5c6f542 100644 --- a/launcher/minecraft/auth/MinecraftAccount.cpp +++ b/launcher/minecraft/auth/MinecraftAccount.cpp @@ -40,7 +40,7 @@ #include <QUuid> #include <QJsonObject> #include <QJsonArray> -#include <QRegExp> +#include <QRegularExpression> #include <QStringList> #include <QJsonDocument> @@ -53,7 +53,7 @@ #include "flows/Offline.h" MinecraftAccount::MinecraftAccount(QObject* parent) : QObject(parent) { - data.internalId = QUuid::createUuid().toString().remove(QRegExp("[{}-]")); + data.internalId = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]")); } @@ -78,7 +78,7 @@ MinecraftAccountPtr MinecraftAccount::createFromUsername(const QString &username MinecraftAccountPtr account = new MinecraftAccount(); account->data.type = AccountType::Mojang; account->data.yggdrasilToken.extra["userName"] = username; - account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegExp("[{}-]")); + account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]")); return account; } @@ -97,10 +97,10 @@ MinecraftAccountPtr MinecraftAccount::createOffline(const QString &username) account->data.yggdrasilToken.validity = Katabasis::Validity::Certain; account->data.yggdrasilToken.issueInstant = QDateTime::currentDateTimeUtc(); account->data.yggdrasilToken.extra["userName"] = username; - account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegExp("[{}-]")); + account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]")); account->data.minecraftEntitlement.ownsMinecraft = true; account->data.minecraftEntitlement.canPlayMinecraft = true; - account->data.minecraftProfile.id = QUuid::createUuid().toString().remove(QRegExp("[{}-]")); + account->data.minecraftProfile.id = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]")); account->data.minecraftProfile.name = username; account->data.minecraftProfile.validity = Katabasis::Validity::Certain; return account; @@ -135,6 +135,7 @@ shared_qobject_ptr<AccountTask> MinecraftAccount::login(QString password) { m_currentTask.reset(new MojangLogin(&data, password)); connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded())); connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString))); + connect(m_currentTask.get(), &Task::aborted, this, [this]{ authFailed(tr("Aborted")); }); emit activityChanged(true); return m_currentTask; } @@ -145,6 +146,7 @@ shared_qobject_ptr<AccountTask> MinecraftAccount::loginMSA() { m_currentTask.reset(new MSAInteractive(&data)); connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded())); connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString))); + connect(m_currentTask.get(), &Task::aborted, this, [this]{ authFailed(tr("Aborted")); }); emit activityChanged(true); return m_currentTask; } @@ -155,6 +157,7 @@ shared_qobject_ptr<AccountTask> MinecraftAccount::loginOffline() { m_currentTask.reset(new OfflineLogin(&data)); connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded())); connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString))); + connect(m_currentTask.get(), &Task::aborted, this, [this]{ authFailed(tr("Aborted")); }); emit activityChanged(true); return m_currentTask; } @@ -176,6 +179,7 @@ shared_qobject_ptr<AccountTask> MinecraftAccount::refresh() { connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded())); connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString))); + connect(m_currentTask.get(), &Task::aborted, this, [this]{ authFailed(tr("Aborted")); }); emit activityChanged(true); return m_currentTask; } diff --git a/launcher/minecraft/auth/steps/YggdrasilStep.cpp b/launcher/minecraft/auth/steps/YggdrasilStep.cpp index 4c6b1624..e1d33172 100644 --- a/launcher/minecraft/auth/steps/YggdrasilStep.cpp +++ b/launcher/minecraft/auth/steps/YggdrasilStep.cpp @@ -9,6 +9,7 @@ YggdrasilStep::YggdrasilStep(AccountData* data, QString password) : AuthStep(dat connect(m_yggdrasil, &Task::failed, this, &YggdrasilStep::onAuthFailed); connect(m_yggdrasil, &Task::succeeded, this, &YggdrasilStep::onAuthSucceeded); + connect(m_yggdrasil, &Task::aborted, this, &YggdrasilStep::onAuthFailed); } YggdrasilStep::~YggdrasilStep() noexcept = default; diff --git a/launcher/minecraft/launch/DirectJavaLaunch.cpp b/launcher/minecraft/launch/DirectJavaLaunch.cpp index 742170fa..152485b3 100644 --- a/launcher/minecraft/launch/DirectJavaLaunch.cpp +++ b/launcher/minecraft/launch/DirectJavaLaunch.cpp @@ -12,13 +12,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include "DirectJavaLaunch.h" + +#include <QStandardPaths> + #include <launch/LaunchTask.h> #include <minecraft/MinecraftInstance.h> #include <FileSystem.h> #include <Commandline.h> -#include <QStandardPaths> + +#ifdef Q_OS_LINUX +#include "gamemode_client.h" +#endif DirectJavaLaunch::DirectJavaLaunch(LaunchTask *parent) : LaunchStep(parent) { @@ -50,7 +55,7 @@ void DirectJavaLaunch::executeTask() auto javaPath = FS::ResolveExecutable(instance->settings()->get("JavaPath").toString()); - m_process.setProcessEnvironment(instance->createEnvironment()); + m_process.setProcessEnvironment(instance->createLaunchEnvironment()); // make detachable - this will keep the process running even if the object is destroyed m_process.setDetachable(true); @@ -79,6 +84,17 @@ void DirectJavaLaunch::executeTask() { m_process.start(javaPath, args); } + +#ifdef Q_OS_LINUX + if (instance->settings()->get("EnableFeralGamemode").toBool()) + { + auto pid = m_process.processId(); + if (pid) + { + gamemode_request_start_for(pid); + } + } +#endif } void DirectJavaLaunch::on_state(LoggedProcess::State state) diff --git a/launcher/minecraft/launch/LauncherPartLaunch.cpp b/launcher/minecraft/launch/LauncherPartLaunch.cpp index 427bc32b..63e4d90f 100644 --- a/launcher/minecraft/launch/LauncherPartLaunch.cpp +++ b/launcher/minecraft/launch/LauncherPartLaunch.cpp @@ -36,7 +36,6 @@ #include "LauncherPartLaunch.h" #include <QStandardPaths> -#include <QRegularExpression> #include "launch/LaunchTask.h" #include "minecraft/MinecraftInstance.h" @@ -44,6 +43,10 @@ #include "Commandline.h" #include "Application.h" +#ifdef Q_OS_LINUX +#include "gamemode_client.h" +#endif + LauncherPartLaunch::LauncherPartLaunch(LaunchTask *parent) : LaunchStep(parent) { auto instance = parent->instance(); @@ -92,6 +95,15 @@ bool fitsInLocal8bit(const QString & string) void LauncherPartLaunch::executeTask() { + QString jarPath = APPLICATION->getJarPath("NewLaunch.jar"); + if (jarPath.isEmpty()) + { + const char *reason = QT_TR_NOOP("Launcher library could not be found. Please check your installation."); + emit logLine(tr(reason), MessageLevel::Fatal); + emitFailed(tr(reason)); + return; + } + auto instance = m_parent->instance(); std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance); @@ -102,13 +114,13 @@ void LauncherPartLaunch::executeTask() auto javaPath = FS::ResolveExecutable(instance->settings()->get("JavaPath").toString()); - m_process.setProcessEnvironment(instance->createEnvironment()); + m_process.setProcessEnvironment(instance->createLaunchEnvironment()); // make detachable - this will keep the process running even if the object is destroyed m_process.setDetachable(true); auto classPath = minecraftInstance->getClassPath(); - classPath.prepend(FS::PathCombine(APPLICATION->getJarsPath(), "NewLaunch.jar")); + classPath.prepend(jarPath); auto natPath = minecraftInstance->getNativePath(); #ifdef Q_OS_WIN @@ -142,7 +154,7 @@ void LauncherPartLaunch::executeTask() #else args << classPath.join(':'); #endif - args << "org.multimc.EntryPoint"; + args << "org.polymc.EntryPoint"; qDebug() << args.join(' '); @@ -167,6 +179,17 @@ void LauncherPartLaunch::executeTask() { m_process.start(javaPath, args); } + +#ifdef Q_OS_LINUX + if (instance->settings()->get("EnableFeralGamemode").toBool()) + { + auto pid = m_process.processId(); + if (pid) + { + gamemode_request_start_for(pid); + } + } +#endif } void LauncherPartLaunch::on_state(LoggedProcess::State state) diff --git a/launcher/minecraft/mod/ModFolderModel.cpp b/launcher/minecraft/mod/ModFolderModel.cpp index ded2d3a2..5ee08cbf 100644 --- a/launcher/minecraft/mod/ModFolderModel.cpp +++ b/launcher/minecraft/mod/ModFolderModel.cpp @@ -116,9 +116,17 @@ bool ModFolderModel::update() void ModFolderModel::finishUpdate() { +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) + auto currentList = modsIndex.keys(); + QSet<QString> currentSet(currentList.begin(), currentList.end()); + auto & newMods = m_update->mods; + auto newList = newMods.keys(); + QSet<QString> newSet(newList.begin(), newList.end()); +#else QSet<QString> currentSet = modsIndex.keys().toSet(); auto & newMods = m_update->mods; QSet<QString> newSet = newMods.keys().toSet(); +#endif // see if the kept mods changed in some way { @@ -167,12 +175,16 @@ void ModFolderModel::finishUpdate() { QSet<QString> added = newSet; added.subtract(currentSet); - beginInsertRows(QModelIndex(), mods.size(), mods.size() + added.size() - 1); - for(auto & addedMod: added) { - mods.append(newMods[addedMod]); - resolveMod(mods.last()); + + // When you have a Qt build with assertions turned on, proceeding here will abort the application + if (added.size() > 0) { + beginInsertRows(QModelIndex(), mods.size(), mods.size() + added.size() - 1); + for (auto& addedMod : added) { + mods.append(newMods[addedMod]); + resolveMod(mods.last()); + } + endInsertRows(); } - endInsertRows(); } // update index @@ -305,7 +317,8 @@ bool ModFolderModel::installMod(const QString &filename) return false; } FS::updateTimestamp(newpath); - installedMod.repath(newpath); + QFileInfo newpathInfo(newpath); + installedMod.repath(newpathInfo); update(); return true; } @@ -323,7 +336,8 @@ bool ModFolderModel::installMod(const QString &filename) qWarning() << "Copy of folder from" << originalPath << "to" << newpath << "has (potentially partially) failed."; return false; } - installedMod.repath(newpath); + QFileInfo newpathInfo(newpath); + installedMod.repath(newpathInfo); update(); return true; } diff --git a/launcher/minecraft/mod/ModFolderModel_test.cpp b/launcher/minecraft/mod/ModFolderModel_test.cpp index 34a3b83a..b4d37ce5 100644 --- a/launcher/minecraft/mod/ModFolderModel_test.cpp +++ b/launcher/minecraft/mod/ModFolderModel_test.cpp @@ -35,7 +35,6 @@ #include <QTest> #include <QTemporaryDir> -#include "TestUtil.h" #include "FileSystem.h" #include "minecraft/mod/ModFolderModel.h" @@ -50,7 +49,7 @@ slots: void test_1178() { // source - QString source = QFINDTESTDATA("data/test_folder"); + QString source = QFINDTESTDATA("testdata/test_folder"); // sanity check QVERIFY(!source.endsWith('/')); diff --git a/launcher/minecraft/mod/testdata/test_folder/assets/minecraft/textures/blah.txt b/launcher/minecraft/mod/testdata/test_folder/assets/minecraft/textures/blah.txt new file mode 100644 index 00000000..8d1c8b69 --- /dev/null +++ b/launcher/minecraft/mod/testdata/test_folder/assets/minecraft/textures/blah.txt @@ -0,0 +1 @@ + diff --git a/launcher/minecraft/mod/testdata/test_folder/pack.mcmeta b/launcher/minecraft/mod/testdata/test_folder/pack.mcmeta new file mode 100644 index 00000000..67ee0434 --- /dev/null +++ b/launcher/minecraft/mod/testdata/test_folder/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "pack_format": 1, + "description": "Some resource pack maybe" + } +} diff --git a/launcher/minecraft/mod/testdata/test_folder/pack.nfo b/launcher/minecraft/mod/testdata/test_folder/pack.nfo new file mode 100644 index 00000000..8d1c8b69 --- /dev/null +++ b/launcher/minecraft/mod/testdata/test_folder/pack.nfo @@ -0,0 +1 @@ + diff --git a/launcher/minecraft/services/CapeChange.cpp b/launcher/minecraft/services/CapeChange.cpp index e49c166a..c73a11b6 100644 --- a/launcher/minecraft/services/CapeChange.cpp +++ b/launcher/minecraft/services/CapeChange.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 "CapeChange.h" #include <QNetworkRequest> @@ -34,7 +69,11 @@ void CapeChange::clearCape() { m_reply = shared_qobject_ptr<QNetworkReply>(rep); connect(rep, &QNetworkReply::uploadProgress, this, &Task::setProgress); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + connect(rep, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError))); +#else connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError))); +#endif connect(rep, SIGNAL(finished()), this, SLOT(downloadFinished())); } diff --git a/launcher/minecraft/services/SkinDelete.cpp b/launcher/minecraft/services/SkinDelete.cpp index cce8364e..921bd094 100644 --- a/launcher/minecraft/services/SkinDelete.cpp +++ b/launcher/minecraft/services/SkinDelete.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 "SkinDelete.h" #include <QNetworkRequest> @@ -19,7 +54,11 @@ void SkinDelete::executeTask() setStatus(tr("Deleting skin")); connect(rep, &QNetworkReply::uploadProgress, this, &Task::setProgress); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + connect(rep, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError))); +#else connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError))); +#endif connect(rep, SIGNAL(finished()), this, SLOT(downloadFinished())); } diff --git a/launcher/minecraft/services/SkinUpload.cpp b/launcher/minecraft/services/SkinUpload.cpp index 7c2e8337..c7987875 100644 --- a/launcher/minecraft/services/SkinUpload.cpp +++ b/launcher/minecraft/services/SkinUpload.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 "SkinUpload.h" #include <QNetworkRequest> @@ -44,7 +79,11 @@ void SkinUpload::executeTask() setStatus(tr("Uploading skin")); connect(rep, &QNetworkReply::uploadProgress, this, &Task::setProgress); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + connect(rep, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError))); +#else connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError))); +#endif connect(rep, SIGNAL(finished()), this, SLOT(downloadFinished())); } diff --git a/launcher/minecraft/update/AssetUpdateTask.cpp b/launcher/minecraft/update/AssetUpdateTask.cpp index c4bddb08..dd246665 100644 --- a/launcher/minecraft/update/AssetUpdateTask.cpp +++ b/launcher/minecraft/update/AssetUpdateTask.cpp @@ -43,6 +43,7 @@ void AssetUpdateTask::executeTask() connect(downloadJob.get(), &NetJob::succeeded, this, &AssetUpdateTask::assetIndexFinished); connect(downloadJob.get(), &NetJob::failed, this, &AssetUpdateTask::assetIndexFailed); + connect(downloadJob.get(), &NetJob::aborted, this, [this]{ emitFailed(tr("Aborted")); }); connect(downloadJob.get(), &NetJob::progress, this, &AssetUpdateTask::progress); qDebug() << m_inst->name() << ": Starting asset index download"; @@ -80,6 +81,7 @@ void AssetUpdateTask::assetIndexFinished() downloadJob = job; connect(downloadJob.get(), &NetJob::succeeded, this, &AssetUpdateTask::emitSucceeded); connect(downloadJob.get(), &NetJob::failed, this, &AssetUpdateTask::assetsFailed); + connect(downloadJob.get(), &NetJob::aborted, this, [this]{ emitFailed(tr("Aborted")); }); connect(downloadJob.get(), &NetJob::progress, this, &AssetUpdateTask::progress); downloadJob->start(); return; diff --git a/launcher/minecraft/update/FMLLibrariesTask.cpp b/launcher/minecraft/update/FMLLibrariesTask.cpp index 58141991..b6238ce9 100644 --- a/launcher/minecraft/update/FMLLibrariesTask.cpp +++ b/launcher/minecraft/update/FMLLibrariesTask.cpp @@ -72,6 +72,7 @@ void FMLLibrariesTask::executeTask() connect(dljob, &NetJob::succeeded, this, &FMLLibrariesTask::fmllibsFinished); connect(dljob, &NetJob::failed, this, &FMLLibrariesTask::fmllibsFailed); + connect(dljob, &NetJob::aborted, this, [this]{ emitFailed(tr("Aborted")); }); connect(dljob, &NetJob::progress, this, &FMLLibrariesTask::progress); downloadJob.reset(dljob); downloadJob->start(); diff --git a/launcher/minecraft/update/LibrariesTask.cpp b/launcher/minecraft/update/LibrariesTask.cpp index 26679110..aa2bf407 100644 --- a/launcher/minecraft/update/LibrariesTask.cpp +++ b/launcher/minecraft/update/LibrariesTask.cpp @@ -68,6 +68,7 @@ void LibrariesTask::executeTask() connect(downloadJob.get(), &NetJob::succeeded, this, &LibrariesTask::emitSucceeded); connect(downloadJob.get(), &NetJob::failed, this, &LibrariesTask::jarlibFailed); + connect(downloadJob.get(), &NetJob::aborted, this, [this]{ emitFailed(tr("Aborted")); }); connect(downloadJob.get(), &NetJob::progress, this, &LibrariesTask::progress); downloadJob->start(); } |