Merge branch 'develop' into feature/sparkle-mac

# Conflicts:
#	.github/workflows/build.yml
This commit is contained in:
Sefa Eyeoglu
2022-07-10 19:38:30 +02:00
374 changed files with 12410 additions and 6477 deletions

View File

@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 Lenny McLennington <lenny@sneed.church>
*
* 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
@ -36,6 +37,7 @@
#include "Application.h"
#include "BuildConfig.h"
#include "net/PasteUpload.h"
#include "ui/MainWindow.h"
#include "ui/InstanceWindow.h"
@ -61,6 +63,7 @@
#include "ui/setupwizard/SetupWizard.h"
#include "ui/setupwizard/LanguageWizardPage.h"
#include "ui/setupwizard/JavaWizardPage.h"
#include "ui/setupwizard/PasteWizardPage.h"
#include "ui/dialogs/CustomMessageBox.h"
@ -81,6 +84,7 @@
#include <QDebug>
#include <QStyleFactory>
#include <QWindow>
#include <QIcon>
#include "InstanceList.h"
@ -96,7 +100,6 @@
#include "tools/JVisualVM.h"
#include "tools/MCEditTool.h"
#include <xdgicon.h>
#include "settings/INISettingsObject.h"
#include "settings/Setting.h"
@ -221,7 +224,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
setOrganizationName(BuildConfig.LAUNCHER_NAME);
setOrganizationDomain(BuildConfig.LAUNCHER_DOMAIN);
setApplicationName(BuildConfig.LAUNCHER_NAME);
setApplicationDisplayName(BuildConfig.LAUNCHER_DISPLAYNAME);
setApplicationDisplayName(QString("%1 %2").arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.printableVersionString()));
setApplicationVersion(BuildConfig.printableVersionString());
setDesktopFileName(BuildConfig.LAUNCHER_DESKTOPFILENAME);
startTime = QDateTime::currentDateTime();
@ -329,10 +332,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
// on macOS, touch the root to force Finder to reload the .app metadata (and fix any icon change issues)
FS::updateTimestamp(m_rootPath);
#endif
#ifdef LAUNCHER_JARS_LOCATION
m_jarsPath = TOSTRING(LAUNCHER_JARS_LOCATION);
#endif
}
QString adjustedBy;
@ -622,6 +621,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_settings->registerSetting("JavaPath", "");
m_settings->registerSetting("JavaTimestamp", 0);
m_settings->registerSetting("JavaArchitecture", "");
m_settings->registerSetting("JavaRealArchitecture", "");
m_settings->registerSetting("JavaVersion", "");
m_settings->registerSetting("JavaVendor", "");
m_settings->registerSetting("LastHostname", "");
@ -633,6 +633,11 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_settings->registerSetting("UseNativeOpenAL", false);
m_settings->registerSetting("UseNativeGLFW", false);
// Peformance related options
m_settings->registerSetting("EnableFeralGamemode", false);
m_settings->registerSetting("EnableMangoHud", false);
m_settings->registerSetting("UseDiscreteGpu", false);
// Game time
m_settings->registerSetting("ShowGameTime", true);
m_settings->registerSetting("ShowGlobalGameTime", true);
@ -641,6 +646,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
// Minecraft launch method
m_settings->registerSetting("MCLaunchMethod", "LauncherPart");
// Minecraft mods
m_settings->registerSetting("ModMetadataDisabled", false);
// Minecraft offline player name
m_settings->registerSetting("LastOfflinePlayerName", "");
@ -672,14 +680,41 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_settings->registerSetting("UpdateDialogGeometry", "");
// pastebin URL
m_settings->registerSetting("PastebinURL", "https://0x0.st");
// HACK: This code feels so stupid is there a less stupid way of doing this?
{
m_settings->registerSetting("PastebinURL", "");
m_settings->registerSetting("PastebinType", PasteUpload::PasteType::Mclogs);
m_settings->registerSetting("PastebinCustomAPIBase", "");
QString pastebinURL = m_settings->get("PastebinURL").toString();
bool userHadDefaultPastebin = pastebinURL == "https://0x0.st";
if (!pastebinURL.isEmpty() && !userHadDefaultPastebin)
{
m_settings->set("PastebinType", PasteUpload::PasteType::NullPointer);
m_settings->set("PastebinCustomAPIBase", pastebinURL);
m_settings->reset("PastebinURL");
}
bool ok;
int pasteType = m_settings->get("PastebinType").toInt(&ok);
// If PastebinType is invalid then reset the related settings.
if (!ok || !(PasteUpload::PasteType::First <= pasteType && pasteType <= PasteUpload::PasteType::Last))
{
m_settings->reset("PastebinType");
m_settings->reset("PastebinCustomAPIBase");
}
}
// meta URL
m_settings->registerSetting("MetaURLOverride", "");
m_settings->registerSetting("CloseAfterLaunch", false);
m_settings->registerSetting("QuitAfterGameStop", false);
// Custom MSA credentials
m_settings->registerSetting("MSAClientIDOverride", "");
m_settings->registerSetting("CFKeyOverride", "");
m_settings->registerSetting("UserAgentOverride", "");
// Init page provider
{
@ -843,6 +878,12 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_mcedit.reset(new MCEditTool(m_settings));
}
#ifdef Q_OS_MACOS
connect(this, &Application::clickedOnDock, [this]() {
this->showMainWindow();
});
#endif
connect(this, &Application::aboutToQuit, [this](){
if(m_instances)
{
@ -899,7 +940,8 @@ bool Application::createSetupWizard()
return true;
return false;
}();
bool wizardRequired = javaRequired || languageRequired;
bool pasteInterventionRequired = settings()->get("PastebinURL") != "";
bool wizardRequired = javaRequired || languageRequired || pasteInterventionRequired;
if(wizardRequired)
{
@ -913,6 +955,11 @@ bool Application::createSetupWizard()
{
m_setupWizard->addPage(new JavaWizardPage(m_setupWizard));
}
if (pasteInterventionRequired)
{
m_setupWizard->addPage(new PasteWizardPage(m_setupWizard));
}
connect(m_setupWizard, &QDialog::finished, this, &Application::setupWizardFinished);
m_setupWizard->show();
return true;
@ -920,6 +967,21 @@ bool Application::createSetupWizard()
return false;
}
bool Application::event(QEvent* event) {
#ifdef Q_OS_MACOS
if (event->type() == QEvent::ApplicationStateChange) {
auto ev = static_cast<QApplicationStateChangeEvent*>(event);
if (m_prevAppState == Qt::ApplicationActive
&& ev->applicationState() == Qt::ApplicationActive) {
emit clickedOnDock();
}
m_prevAppState = ev->applicationState();
}
#endif
return QApplication::event(event);
}
void Application::setupWizardFinished(int status)
{
qDebug() << "Wizard result =" << status;
@ -1121,7 +1183,7 @@ void Application::setApplicationTheme(const QString& name, bool initial)
void Application::setIconTheme(const QString& name)
{
XdgIcon::setThemeName(name);
QIcon::setThemeName(name);
}
QIcon Application::getThemedIcon(const QString& name)
@ -1129,7 +1191,7 @@ QIcon Application::getThemedIcon(const QString& name)
if(name == "logo") {
return QIcon(":/org.polymc.PolyMC.svg");
}
return XdgIcon::fromTheme(name);
return QIcon::fromTheme(name);
}
bool Application::openJsonEditor(const QString &filename)
@ -1491,13 +1553,22 @@ shared_qobject_ptr<Meta::Index> Application::metadataIndex()
return m_metadataIndex;
}
QString Application::getJarsPath()
QString Application::getJarPath(QString jarFile)
{
if(m_jarsPath.isEmpty())
QStringList potentialPaths = {
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
FS::PathCombine(m_rootPath, "share/jars"),
#endif
FS::PathCombine(m_rootPath, "jars"),
FS::PathCombine(applicationDirPath(), "jars")
};
for(QString p : potentialPaths)
{
return FS::PathCombine(QCoreApplication::applicationDirPath(), "jars");
QString jarPath = FS::PathCombine(p, jarFile);
if (QFileInfo(jarPath).isFile())
return jarPath;
}
return FS::PathCombine(m_rootPath, m_jarsPath);
return {};
}
QString Application::getMSAClientID()
@ -1509,3 +1580,34 @@ QString Application::getMSAClientID()
return BuildConfig.MSA_CLIENT_ID;
}
QString Application::getCurseKey()
{
QString keyOverride = m_settings->get("CFKeyOverride").toString();
if (!keyOverride.isEmpty()) {
return keyOverride;
}
return BuildConfig.CURSEFORGE_API_KEY;
}
QString Application::getUserAgent()
{
QString uaOverride = m_settings->get("UserAgentOverride").toString();
if (!uaOverride.isEmpty()) {
return uaOverride.replace("$LAUNCHER_VER", BuildConfig.printableVersionString());
}
return BuildConfig.USER_AGENT;
}
QString Application::getUserAgentUncached()
{
QString uaOverride = m_settings->get("UserAgentOverride").toString();
if (!uaOverride.isEmpty()) {
uaOverride += " (Uncached)";
return uaOverride.replace("$LAUNCHER_VER", BuildConfig.printableVersionString());
}
return BuildConfig.USER_AGENT_UNCACHED;
}

View File

@ -94,6 +94,8 @@ public:
Application(int &argc, char **argv);
virtual ~Application();
bool event(QEvent* event) override;
std::shared_ptr<SettingsObject> settings() const {
return m_settings;
}
@ -152,9 +154,16 @@ public:
shared_qobject_ptr<Meta::Index> metadataIndex();
QString getJarsPath();
/*!
* Finds and returns the full path to a jar file.
* Returns a null-string if it could not be found.
*/
QString getJarPath(QString jarFile);
QString getMSAClientID();
QString getCurseKey();
QString getUserAgent();
QString getUserAgentUncached();
/// this is the root of the 'installation'. Used for automatic updates
const QString &root() {
@ -180,6 +189,10 @@ signals:
void globalSettingsAboutToOpen();
void globalSettingsClosed();
#ifdef Q_OS_MACOS
void clickedOnDock();
#endif
public slots:
bool launch(
InstancePtr instance,
@ -229,7 +242,6 @@ private:
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
std::map<QString, std::unique_ptr<ITheme>> m_themes;
std::unique_ptr<MCEditTool> m_mcedit;
QString m_jarsPath;
QSet<QString> m_features;
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
@ -237,6 +249,10 @@ private:
QString m_rootPath;
Status m_status = Application::StartingUp;
#ifdef Q_OS_MACOS
Qt::ApplicationState m_prevAppState = Qt::ApplicationInactive;
#endif
#if defined Q_OS_WIN32
// used on Windows to attach the standard IO streams
bool consoleAttached = false;

View File

@ -1,11 +1,47 @@
// 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 "ApplicationMessage.h"
#include <QJsonDocument>
#include <QJsonObject>
#include "Json.h"
void ApplicationMessage::parse(const QByteArray & input) {
auto doc = QJsonDocument::fromBinaryData(input);
auto root = doc.object();
auto doc = Json::requireDocument(input, "ApplicationMessage");
auto root = Json::requireObject(doc, "ApplicationMessage");
command = root.value("command").toString();
args.clear();
@ -25,7 +61,5 @@ QByteArray ApplicationMessage::serialize() {
}
root.insert("args", outArgs);
QJsonDocument out;
out.setObject(root);
return out.toBinaryData();
return Json::toText(root);
}

View File

@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* 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
@ -38,6 +39,7 @@
#include <QFileInfo>
#include <QDir>
#include <QDebug>
#include <QRegularExpression>
#include "settings/INISettingsObject.h"
#include "settings/Setting.h"
@ -59,7 +61,11 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
m_settings->registerSetting("lastLaunchTime", 0);
m_settings->registerSetting("totalTimePlayed", 0);
m_settings->registerSetting("lastTimePlayed", 0);
m_settings->registerSetting("InstanceType", "OneSix");
// NOTE: Sometimees InstanceType is already registered, as it was used to identify the type of
// a locally stored instance
if (!m_settings->getSetting("InstanceType"))
m_settings->registerSetting("InstanceType", "");
// Custom Commands
auto commandSetting = m_settings->registerSetting({"OverrideCommands","OverrideLaunchCmd"}, false);
@ -76,6 +82,14 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
m_settings->registerPassthrough(globalSettings->getSetting("ConsoleMaxLines"), nullptr);
m_settings->registerPassthrough(globalSettings->getSetting("ConsoleOverflowStop"), nullptr);
// Managed Packs
m_settings->registerSetting("ManagedPack", false);
m_settings->registerSetting("ManagedPackType", "");
m_settings->registerSetting("ManagedPackID", "");
m_settings->registerSetting("ManagedPackName", "");
m_settings->registerSetting("ManagedPackVersionID", "");
m_settings->registerSetting("ManagedPackVersionName", "");
}
QString BaseInstance::getPreLaunchCommand()
@ -93,6 +107,46 @@ QString BaseInstance::getPostExitCommand()
return settings()->get("PostExitCommand").toString();
}
bool BaseInstance::isManagedPack()
{
return settings()->get("ManagedPack").toBool();
}
QString BaseInstance::getManagedPackType()
{
return settings()->get("ManagedPackType").toString();
}
QString BaseInstance::getManagedPackID()
{
return settings()->get("ManagedPackID").toString();
}
QString BaseInstance::getManagedPackName()
{
return settings()->get("ManagedPackName").toString();
}
QString BaseInstance::getManagedPackVersionID()
{
return settings()->get("ManagedPackVersionID").toString();
}
QString BaseInstance::getManagedPackVersionName()
{
return settings()->get("ManagedPackVersionName").toString();
}
void BaseInstance::setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version)
{
settings()->set("ManagedPack", true);
settings()->set("ManagedPackType", type);
settings()->set("ManagedPackID", id);
settings()->set("ManagedPackName", name);
settings()->set("ManagedPackVersionID", versionId);
settings()->set("ManagedPackVersionName", version);
}
int BaseInstance::getConsoleMaxLines() const
{
auto lineSetting = settings()->getSetting("ConsoleMaxLines");
@ -282,7 +336,7 @@ QString BaseInstance::name() const
QString BaseInstance::windowTitle() const
{
return BuildConfig.LAUNCHER_NAME + ": " + name().replace(QRegExp("[ \n\r\t]+"), " ");
return BuildConfig.LAUNCHER_NAME + ": " + name().replace(QRegularExpression("\\s+"), " ");
}
// FIXME: why is this here? move it to MinecraftInstance!!!

View File

@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* 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
@ -139,6 +140,14 @@ public:
QString getPostExitCommand();
QString getWrapperCommand();
bool isManagedPack();
QString getManagedPackType();
QString getManagedPackID();
QString getManagedPackName();
QString getManagedPackVersionID();
QString getManagedPackVersionName();
void setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version);
/// guess log level from a line of game log
virtual MessageLevel::Enum guessLevel(const QString &line, MessageLevel::Enum level)
{
@ -179,6 +188,7 @@ public:
* Create envrironment variables for running the instance
*/
virtual QProcessEnvironment createEnvironment() = 0;
virtual QProcessEnvironment createLaunchEnvironment() = 0;
/*!
* Returns a matcher that can maps relative paths within the instance to whether they are 'log files'

View File

@ -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 "BaseVersionList.h"
@ -51,7 +71,7 @@ QVariant BaseVersionList::data(const QModelIndex &index, int role) const
switch (role)
{
case VersionPointerRole:
return qVariantFromValue(version);
return QVariant::fromValue(version);
case VersionRole:
return version->name();

View File

@ -4,8 +4,6 @@ project(application)
######## Sources and headers ########
include (UnitTest)
set(CORE_SOURCES
# LOGIC - Base classes and infrastructure
BaseInstaller.h
@ -90,16 +88,11 @@ set(CORE_SOURCES
MMCTime.cpp
)
add_unit_test(FileSystem
SOURCES FileSystem_test.cpp
LIBS Launcher_logic
DATA testdata
)
ecm_add_test(FileSystem_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME FileSystem) # TODO: needs testdata
add_unit_test(GZip
SOURCES GZip_test.cpp
LIBS Launcher_logic
)
ecm_add_test(GZip_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME GZip)
set(PATHMATCHER_SOURCES
# Path matchers
@ -128,6 +121,8 @@ set(NET_SOURCES
net/PasteUpload.h
net/Sink.h
net/Validator.h
net/Upload.cpp
net/Upload.h
)
# Game launch logic
@ -170,18 +165,6 @@ set(MAC_UPDATE_SOURCES
updater/MacSparkleUpdater.mm
)
add_unit_test(UpdateChecker
SOURCES updater/UpdateChecker_test.cpp
LIBS Launcher_logic
DATA updater/testdata
)
add_unit_test(DownloadTask
SOURCES updater/DownloadTask_test.cpp
LIBS Launcher_logic
DATA updater/testdata
)
# Backend for the news bar... there's usually no news.
set(NEWS_SOURCES
# News System
@ -328,19 +311,22 @@ set(MINECRAFT_SOURCES
minecraft/WorldList.h
minecraft/WorldList.cpp
minecraft/mod/MetadataHandler.h
minecraft/mod/Mod.h
minecraft/mod/Mod.cpp
minecraft/mod/ModDetails.h
minecraft/mod/ModFolderModel.h
minecraft/mod/ModFolderModel.cpp
minecraft/mod/ModFolderLoadTask.h
minecraft/mod/ModFolderLoadTask.cpp
minecraft/mod/LocalModParseTask.h
minecraft/mod/LocalModParseTask.cpp
minecraft/mod/ResourcePackFolderModel.h
minecraft/mod/ResourcePackFolderModel.cpp
minecraft/mod/TexturePackFolderModel.h
minecraft/mod/TexturePackFolderModel.cpp
minecraft/mod/tasks/ModFolderLoadTask.h
minecraft/mod/tasks/ModFolderLoadTask.cpp
minecraft/mod/tasks/LocalModParseTask.h
minecraft/mod/tasks/LocalModParseTask.cpp
minecraft/mod/tasks/LocalModUpdateTask.h
minecraft/mod/tasks/LocalModUpdateTask.cpp
# Assets
minecraft/AssetsUtils.h
@ -358,10 +344,8 @@ set(MINECRAFT_SOURCES
mojang/PackageManifest.cpp
minecraft/Agent.h)
add_unit_test(GradleSpecifier
SOURCES minecraft/GradleSpecifier_test.cpp
LIBS Launcher_logic
)
ecm_add_test(minecraft/GradleSpecifier_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME GradleSpecifier)
if(BUILD_TESTING)
add_executable(PackageManifest
@ -369,7 +353,7 @@ if(BUILD_TESTING)
)
target_link_libraries(PackageManifest
Launcher_logic
Qt5::Test
Qt${QT_VERSION_MAJOR}::Test
)
target_include_directories(PackageManifest
PRIVATE ../cmake/UnitTest/
@ -381,28 +365,20 @@ if(BUILD_TESTING)
)
endif()
add_unit_test(MojangVersionFormat
SOURCES minecraft/MojangVersionFormat_test.cpp
LIBS Launcher_logic
DATA minecraft/testdata
)
# TODO: needs minecraft/testdata
ecm_add_test(minecraft/MojangVersionFormat_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME MojangVersionFormat)
add_unit_test(Library
SOURCES minecraft/Library_test.cpp
LIBS Launcher_logic
)
ecm_add_test(minecraft/Library_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME Library)
# FIXME: shares data with FileSystem test
add_unit_test(ModFolderModel
SOURCES minecraft/mod/ModFolderModel_test.cpp
DATA testdata
LIBS Launcher_logic
)
# TODO: needs testdata
ecm_add_test(minecraft/mod/ModFolderModel_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME ModFolderModel)
add_unit_test(ParseUtils
SOURCES minecraft/ParseUtils_test.cpp
LIBS Launcher_logic
)
ecm_add_test(minecraft/ParseUtils_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME ParseUtils)
# the screenshots feature
set(SCREENSHOTS_SOURCES
@ -417,14 +393,14 @@ set(TASKS_SOURCES
# Tasks
tasks/Task.h
tasks/Task.cpp
tasks/ConcurrentTask.h
tasks/ConcurrentTask.cpp
tasks/SequentialTask.h
tasks/SequentialTask.cpp
)
add_unit_test(Task
SOURCES tasks/Task_test.cpp
LIBS Launcher_logic
)
ecm_add_test(tasks/Task_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME Task)
set(SETTINGS_SOURCES
# Settings
@ -442,10 +418,8 @@ set(SETTINGS_SOURCES
settings/SettingsObject.h
)
add_unit_test(INIFile
SOURCES settings/INIFile_test.cpp
LIBS Launcher_logic
)
ecm_add_test(settings/INIFile_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME INIFile)
set(JAVA_SOURCES
java/JavaChecker.h
@ -462,10 +436,8 @@ set(JAVA_SOURCES
java/JavaVersion.cpp
)
add_unit_test(JavaVersion
SOURCES java/JavaVersion_test.cpp
LIBS Launcher_logic
)
ecm_add_test(java/JavaVersion_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME JavaVersion)
set(TRANSLATIONS_SOURCES
translations/TranslationsModel.h
@ -503,6 +475,9 @@ set(META_SOURCES
)
set(API_SOURCES
modplatform/ModIndex.h
modplatform/ModIndex.cpp
modplatform/ModAPI.h
modplatform/flame/FlameAPI.h
@ -549,6 +524,15 @@ set(MODPACKSCH_SOURCES
modplatform/modpacksch/FTBPackManifest.cpp
)
set(PACKWIZ_SOURCES
modplatform/packwiz/Packwiz.h
modplatform/packwiz/Packwiz.cpp
)
# TODO: needs modplatform/packwiz/testdata
ecm_add_test(modplatform/packwiz/Packwiz_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME Packwiz)
set(TECHNIC_SOURCES
modplatform/technic/SingleZipPackInstallTask.h
modplatform/technic/SingleZipPackInstallTask.cpp
@ -571,10 +555,8 @@ set(ATLAUNCHER_SOURCES
modplatform/atlauncher/ATLShareCode.h
)
add_unit_test(Index
SOURCES meta/Index_test.cpp
LIBS Launcher_logic
)
ecm_add_test(meta/Index_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME Index)
################################ COMPILE ################################
@ -602,6 +584,7 @@ set(LOGIC_SOURCES
${FLAME_SOURCES}
${MODRINTH_SOURCES}
${MODPACKSCH_SOURCES}
${PACKWIZ_SOURCES}
${TECHNIC_SOURCES}
${ATLAUNCHER_SOURCES}
)
@ -671,6 +654,8 @@ SET(LAUNCHER_SOURCES
ui/setupwizard/JavaWizardPage.h
ui/setupwizard/LanguageWizardPage.cpp
ui/setupwizard/LanguageWizardPage.h
ui/setupwizard/PasteWizardPage.cpp
ui/setupwizard/PasteWizardPage.h
# GUI - themes
ui/themes/FusionTheme.cpp
@ -703,6 +688,8 @@ SET(LAUNCHER_SOURCES
ui/pages/BasePageProvider.h
# GUI - instance pages
ui/pages/instance/ExternalResourcesPage.cpp
ui/pages/instance/ExternalResourcesPage.h
ui/pages/instance/GameOptionsPage.cpp
ui/pages/instance/GameOptionsPage.h
ui/pages/instance/VersionPage.cpp
@ -831,6 +818,8 @@ SET(LAUNCHER_SOURCES
ui/dialogs/NewComponentDialog.h
ui/dialogs/NewInstanceDialog.cpp
ui/dialogs/NewInstanceDialog.h
ui/dialogs/NewsDialog.cpp
ui/dialogs/NewsDialog.h
ui/pagedialog/PageDialog.cpp
ui/pagedialog/PageDialog.h
ui/dialogs/ProgressDialog.cpp
@ -845,6 +834,8 @@ SET(LAUNCHER_SOURCES
ui/dialogs/SkinUploadDialog.h
ui/dialogs/ModDownloadDialog.cpp
ui/dialogs/ModDownloadDialog.h
ui/dialogs/ScrollMessageBox.cpp
ui/dialogs/ScrollMessageBox.h
# GUI - widgets
ui/widgets/Common.cpp
@ -899,7 +890,8 @@ SET(LAUNCHER_SOURCES
ui/instanceview/VisualGroup.h
)
qt5_wrap_ui(LAUNCHER_UI
qt_wrap_ui(LAUNCHER_UI
ui/setupwizard/PasteWizardPage.ui
ui/pages/global/AccountListPage.ui
ui/pages/global/JavaPage.ui
ui/pages/global/LauncherPage.ui
@ -907,7 +899,7 @@ qt5_wrap_ui(LAUNCHER_UI
ui/pages/global/ProxyPage.ui
ui/pages/global/MinecraftPage.ui
ui/pages/global/ExternalToolsPage.ui
ui/pages/instance/ModFolderPage.ui
ui/pages/instance/ExternalResourcesPage.ui
ui/pages/instance/NotesPage.ui
ui/pages/instance/LogPage.ui
ui/pages/instance/ServersPage.ui
@ -937,6 +929,7 @@ qt5_wrap_ui(LAUNCHER_UI
ui/dialogs/NewInstanceDialog.ui
ui/dialogs/UpdateDialog.ui
ui/dialogs/NewComponentDialog.ui
ui/dialogs/NewsDialog.ui
ui/dialogs/ProfileSelectDialog.ui
ui/dialogs/SkinUploadDialog.ui
ui/dialogs/ExportInstanceDialog.ui
@ -947,9 +940,10 @@ qt5_wrap_ui(LAUNCHER_UI
ui/dialogs/LoginDialog.ui
ui/dialogs/EditAccountDialog.ui
ui/dialogs/ReviewMessageBox.ui
ui/dialogs/ScrollMessageBox.ui
)
qt5_add_resources(LAUNCHER_RESOURCES
qt_add_resources(LAUNCHER_RESOURCES
resources/backgrounds/backgrounds.qrc
resources/multimc/multimc.qrc
resources/pe_dark/pe_dark.qrc
@ -965,7 +959,7 @@ qt5_add_resources(LAUNCHER_RESOURCES
######## Windows resource files ########
if(WIN32)
set(LAUNCHER_RCS ../${Launcher_Branding_WindowsRC})
set(LAUNCHER_RCS ${CMAKE_CURRENT_BINARY_DIR}/../${Launcher_Branding_WindowsRC})
endif()
# Add executable
@ -979,16 +973,25 @@ target_link_libraries(Launcher_logic
tomlc99
BuildConfig
Katabasis
Qt${QT_VERSION_MAJOR}::Widgets
)
if (UNIX AND NOT CYGWIN AND NOT APPLE)
target_link_libraries(Launcher_logic
gamemode
)
endif()
target_link_libraries(Launcher_logic
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Xml
Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Concurrent
Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Widgets
${Launcher_QT_LIBS}
)
target_link_libraries(Launcher_logic
Qt5::Core
Qt5::Xml
Qt5::Network
Qt5::Concurrent
Qt5::Gui
)
target_link_libraries(Launcher_logic
Launcher_iconfix
QuaZip::QuaZip
hoedown
LocalPeer
@ -1082,6 +1085,14 @@ if(INSTALL_BUNDLE STREQUAL "full")
COMPONENT Runtime
)
endif()
# TLS plugins (Qt 6 only)
if(EXISTS "${QT_PLUGINS_DIR}/tls")
install(
DIRECTORY "${QT_PLUGINS_DIR}/tls"
DESTINATION ${PLUGIN_DEST_DIR}
COMPONENT Runtime
)
endif()
else()
# Image formats
install(
@ -1124,6 +1135,16 @@ if(INSTALL_BUNDLE STREQUAL "full")
REGEX "\\.dSYM" EXCLUDE
)
endif()
# TLS plugins (Qt 6 only)
if(EXISTS "${QT_PLUGINS_DIR}/tls")
install(
DIRECTORY "${QT_PLUGINS_DIR}/tls"
DESTINATION ${PLUGIN_DEST_DIR}
COMPONENT Runtime
REGEX "_debug\\." EXCLUDE
REGEX "\\.dSYM" EXCLUDE
)
endif()
endif()
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in"

View File

@ -1,18 +1,38 @@
/* Copyright 2013-2021 MultiMC Contributors
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
* 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.
*
* 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 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.
*
* http://www.apache.org/licenses/LICENSE-2.0
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* 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.
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
*
* 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 "Commandline.h"
@ -47,7 +67,7 @@ QStringList splitArgs(QString args)
if (cchar == '\\')
escape = true;
else if (cchar == inquotes)
inquotes = 0;
inquotes = QChar::Null;
else
current += cchar;
// otherwise
@ -480,4 +500,4 @@ void Parser::getPrefix(QString &opt, QString &flag)
ParsingError::ParsingError(const QString &what) : std::runtime_error(what.toStdString())
{
}
}
}

View File

@ -1,4 +1,37 @@
// Licensed under the Apache-2.0 license. See README.md for details.
// 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 "FileSystem.h"
@ -346,7 +379,7 @@ bool checkProblemticPathJava(QDir folder)
}
// Win32 crap
#if defined Q_OS_WIN
#ifdef Q_OS_WIN
bool called_coinit = false;
@ -366,7 +399,7 @@ HRESULT CreateLink(LPCSTR linkPath, LPCSTR targetPath, LPCSTR args)
}
}
IShellLink *link;
IShellLinkA *link;
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink,
(LPVOID *)&link);
@ -454,4 +487,47 @@ bool createShortCut(QString location, QString dest, QStringList args, QString na
return false;
#endif
}
QStringList listFolderPaths(QDir root)
{
auto createAbsPath = [](QFileInfo const& entry) { return FS::PathCombine(entry.path(), entry.fileName()); };
QStringList entries;
root.refresh();
for (auto entry : root.entryInfoList(QDir::Filter::Files)) {
entries.append(createAbsPath(entry));
}
for (auto entry : root.entryInfoList(QDir::Filter::AllDirs | QDir::Filter::NoDotAndDotDot)) {
entries.append(listFolderPaths(createAbsPath(entry)));
}
return entries;
}
bool overrideFolder(QString overwritten_path, QString override_path)
{
if (!FS::ensureFolderPathExists(overwritten_path))
return false;
QStringList paths_to_override;
QDir root_override (override_path);
for (auto file : listFolderPaths(root_override)) {
QString destination = file;
destination.replace(override_path, overwritten_path);
qDebug() << QString("Applying override %1 in %2").arg(file, destination);
if (QFile::exists(destination))
QFile::remove(destination);
if (!QFile::rename(file, destination)) {
qCritical() << QString("Failed to apply override from %1 to %2").arg(file, destination);
return false;
}
}
return true;
}
}

View File

@ -1,4 +1,37 @@
// Licensed under the Apache-2.0 license. See README.md for details.
// 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
@ -49,8 +82,8 @@ class copy
public:
copy(const QString & src, const QString & dst)
{
m_src = src;
m_dst = dst;
m_src.setPath(src);
m_dst.setPath(dst);
}
copy & followSymlinks(const bool follow)
{
@ -120,8 +153,7 @@ bool checkProblemticPathJava(QDir folder);
// Get the Directory representing the User's Desktop
QString getDesktopDir();
// Create a shortcut at *location*, pointing to *dest* called with the arguments *args*
// call it *name* and assign it the icon *icon*
// return true if operation succeeded
bool createShortCut(QString location, QString dest, QStringList args, QString name, QString iconLocation);
// Overrides one folder with the contents of another, preserving items exclusive to the first folder
// Equivalent to doing QDir::rename, but allowing for overrides
bool overrideFolder(QString overwritten_path, QString override_path);
}

View File

@ -1,7 +1,6 @@
#include <QTest>
#include <QTemporaryDir>
#include <QStandardPaths>
#include "TestUtil.h"
#include "FileSystem.h"
@ -81,7 +80,7 @@ slots:
void test_copy()
{
QString folder = QFINDTESTDATA("data/test_folder");
QString folder = QFINDTESTDATA("testdata/test_folder");
auto f = [&folder]()
{
QTemporaryDir tempDir;
@ -116,47 +115,6 @@ slots:
{
QCOMPARE(FS::getDesktopDir(), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
}
// this is only valid on linux
// FIXME: implement on windows, OSX, then test.
#if defined(Q_OS_LINUX)
void test_createShortcut_data()
{
QTest::addColumn<QString>("location");
QTest::addColumn<QString>("dest");
QTest::addColumn<QStringList>("args");
QTest::addColumn<QString>("name");
QTest::addColumn<QString>("iconLocation");
QTest::addColumn<QByteArray>("result");
QTest::newRow("unix") << QDir::currentPath()
<< "asdfDest"
<< (QStringList() << "arg1" << "arg2")
<< "asdf"
<< QString()
#if defined(Q_OS_LINUX)
<< GET_TEST_FILE("data/FileSystem-test_createShortcut-unix")
#elif defined(Q_OS_WIN)
<< QByteArray()
#endif
;
}
void test_createShortcut()
{
QFETCH(QString, location);
QFETCH(QString, dest);
QFETCH(QStringList, args);
QFETCH(QString, name);
QFETCH(QString, iconLocation);
QFETCH(QByteArray, result);
QVERIFY(FS::createShortCut(location, dest, args, name, iconLocation));
QCOMPARE(QString::fromLocal8Bit(TestsInternal::readFile(location + QDir::separator() + name + ".desktop")), QString::fromLocal8Bit(result));
//QDir().remove(location);
}
#endif
};
QTEST_GUILESS_MAIN(FileSystemTest)

View File

@ -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 "GZip.h"
#include <zlib.h>
#include <QByteArray>
@ -67,7 +102,7 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes)
return true;
}
unsigned compLength = std::min(uncompressedBytes.size(), 16);
unsigned compLength = qMin(uncompressedBytes.size(), 16);
compressedBytes.clear();
compressedBytes.resize(compLength);
@ -112,4 +147,4 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes)
return false;
}
return true;
}
}

View File

@ -1,5 +1,4 @@
#include <QTest>
#include "TestUtil.h"
#include "GZip.h"
#include <random>

View File

@ -41,6 +41,7 @@
#include "FileSystem.h"
#include "MMCZip.h"
#include "NullInstance.h"
#include "icons/IconList.h"
#include "icons/IconUtils.h"
#include "settings/INISettingsObject.h"
@ -59,9 +60,9 @@
#include "net/ChecksumValidator.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/dialogs/ScrollMessageBox.h"
#include <algorithm>
#include <iterator>
InstanceImportTask::InstanceImportTask(const QUrl sourceUrl, QWidget* parent)
{
@ -71,7 +72,8 @@ InstanceImportTask::InstanceImportTask(const QUrl sourceUrl, QWidget* parent)
bool InstanceImportTask::abort()
{
m_filesNetJob->abort();
if (m_filesNetJob)
m_filesNetJob->abort();
m_extractFuture.cancel();
return false;
@ -134,18 +136,20 @@ void InstanceImportTask::processZipPack()
return;
}
QStringList blacklist = {"instance.cfg", "manifest.json"};
QString mmcFound = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg");
bool technicFound = QuaZipDir(m_packZip.get()).exists("/bin/modpack.jar") || QuaZipDir(m_packZip.get()).exists("/bin/version.json");
QString flameFound = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json");
QString modrinthFound = MMCZip::findFolderOfFileInZip(m_packZip.get(), "modrinth.index.json");
QuaZipDir packZipDir(m_packZip.get());
// https://docs.modrinth.com/docs/modpacks/format_definition/#storage
bool modrinthFound = packZipDir.exists("/modrinth.index.json");
bool technicFound = packZipDir.exists("/bin/modpack.jar") || packZipDir.exists("/bin/version.json");
QString root;
if(!mmcFound.isNull())
// NOTE: Prioritize modpack platforms that aren't searched for recursively.
// Especially Flame has a very common filename for its manifest, which may appear inside overrides for example
if(modrinthFound)
{
// process as MultiMC instance/pack
qDebug() << "MultiMC:" << mmcFound;
root = mmcFound;
m_modpackType = ModpackType::MultiMC;
// process as Modrinth pack
qDebug() << "Modrinth:" << modrinthFound;
m_modpackType = ModpackType::Modrinth;
}
else if (technicFound)
{
@ -155,19 +159,25 @@ void InstanceImportTask::processZipPack()
extractDir.cd(".minecraft");
m_modpackType = ModpackType::Technic;
}
else if(!flameFound.isNull())
else
{
// process as Flame pack
qDebug() << "Flame:" << flameFound;
root = flameFound;
m_modpackType = ModpackType::Flame;
}
else if(!modrinthFound.isNull())
{
// process as Modrinth pack
qDebug() << "Modrinth:" << modrinthFound;
root = modrinthFound;
m_modpackType = ModpackType::Modrinth;
QString mmcRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg");
QString flameRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json");
if (!mmcRoot.isNull())
{
// process as MultiMC instance/pack
qDebug() << "MultiMC:" << mmcRoot;
root = mmcRoot;
m_modpackType = ModpackType::MultiMC;
}
else if(!flameRoot.isNull())
{
// process as Flame pack
qDebug() << "Flame:" << flameRoot;
root = flameRoot;
m_modpackType = ModpackType::Flame;
}
}
if(m_modpackType == ModpackType::Unknown)
{
@ -315,7 +325,7 @@ void InstanceImportTask::processFlame()
// Hack to correct some 'special sauce'...
if(mcVersion.endsWith('.'))
{
mcVersion.remove(QRegExp("[.]+$"));
mcVersion.remove(QRegularExpression("[.]+$"));
logWarning(tr("Mysterious trailing dots removed from Minecraft version while importing pack."));
}
auto components = instance.getPackProfile();
@ -384,61 +394,135 @@ void InstanceImportTask::processFlame()
connect(m_modIdResolver.get(), &Flame::FileResolvingTask::succeeded, [&]()
{
auto results = m_modIdResolver->getResults();
m_filesNetJob = new NetJob(tr("Mod download"), APPLICATION->network());
for(auto result: results.files)
{
QString filename = result.fileName;
if(!result.required)
{
filename += ".disabled";
}
auto relpath = FS::PathCombine("minecraft", result.targetFolder, filename);
auto path = FS::PathCombine(m_stagingPath , relpath);
switch(result.type)
{
case Flame::File::Type::Folder:
{
logWarning(tr("This 'Folder' may need extracting: %1").arg(relpath));
// fall-through intentional, we treat these as plain old mods and dump them wherever.
}
case Flame::File::Type::SingleFile:
case Flame::File::Type::Mod:
{
qDebug() << "Will download" << result.url << "to" << path;
auto dl = Net::Download::makeFile(result.url, path);
m_filesNetJob->addNetAction(dl);
break;
}
case Flame::File::Type::Modpack:
logWarning(tr("Nesting modpacks in modpacks is not implemented, nothing was downloaded: %1").arg(relpath));
break;
case Flame::File::Type::Cmod2:
case Flame::File::Type::Ctoc:
case Flame::File::Type::Unknown:
logWarning(tr("Unrecognized/unhandled PackageType for: %1").arg(relpath));
break;
//first check for blocked mods
QString text;
auto anyBlocked = false;
for(const auto& result: results.files.values()) {
if (!result.resolved || result.url.isEmpty()) {
text += QString("%1: <a href='%2'>%2</a><br/>").arg(result.fileName, result.websiteUrl);
anyBlocked = true;
}
}
m_modIdResolver.reset();
connect(m_filesNetJob.get(), &NetJob::succeeded, this, [&]()
{
m_filesNetJob.reset();
emitSucceeded();
if(anyBlocked) {
qWarning() << "Blocked mods found, displaying mod list";
auto message_dialog = new ScrollMessageBox(m_parent,
tr("Blocked mods found"),
tr("The following mods were blocked on third party launchers.<br/>"
"You will need to manually download them and add them to the modpack"),
text);
message_dialog->setModal(true);
if (message_dialog->exec()) {
m_filesNetJob = new NetJob(tr("Mod download"), APPLICATION->network());
for (const auto &result: m_modIdResolver->getResults().files) {
QString filename = result.fileName;
if (!result.required) {
filename += ".disabled";
}
auto relpath = FS::PathCombine("minecraft", result.targetFolder, filename);
auto path = FS::PathCombine(m_stagingPath, relpath);
switch (result.type) {
case Flame::File::Type::Folder: {
logWarning(tr("This 'Folder' may need extracting: %1").arg(relpath));
// fall-through intentional, we treat these as plain old mods and dump them wherever.
}
case Flame::File::Type::SingleFile:
case Flame::File::Type::Mod: {
if (!result.url.isEmpty()) {
qDebug() << "Will download" << result.url << "to" << path;
auto dl = Net::Download::makeFile(result.url, path);
m_filesNetJob->addNetAction(dl);
}
break;
}
case Flame::File::Type::Modpack:
logWarning(
tr("Nesting modpacks in modpacks is not implemented, nothing was downloaded: %1").arg(
relpath));
break;
case Flame::File::Type::Cmod2:
case Flame::File::Type::Ctoc:
case Flame::File::Type::Unknown:
logWarning(tr("Unrecognized/unhandled PackageType for: %1").arg(relpath));
break;
}
}
m_modIdResolver.reset();
connect(m_filesNetJob.get(), &NetJob::succeeded, this, [&]() {
m_filesNetJob.reset();
emitSucceeded();
}
);
connect(m_filesNetJob.get(), &NetJob::failed, [&](QString reason) {
m_filesNetJob.reset();
emitFailed(reason);
});
connect(m_filesNetJob.get(), &NetJob::progress, [&](qint64 current, qint64 total) {
setProgress(current, total);
});
setStatus(tr("Downloading mods..."));
m_filesNetJob->start();
} else {
m_modIdResolver.reset();
emitFailed("Canceled");
}
} else {
//TODO extract to function ?
m_filesNetJob = new NetJob(tr("Mod download"), APPLICATION->network());
for (const auto &result: m_modIdResolver->getResults().files) {
QString filename = result.fileName;
if (!result.required) {
filename += ".disabled";
}
auto relpath = FS::PathCombine("minecraft", result.targetFolder, filename);
auto path = FS::PathCombine(m_stagingPath, relpath);
switch (result.type) {
case Flame::File::Type::Folder: {
logWarning(tr("This 'Folder' may need extracting: %1").arg(relpath));
// fall-through intentional, we treat these as plain old mods and dump them wherever.
}
case Flame::File::Type::SingleFile:
case Flame::File::Type::Mod: {
if (!result.url.isEmpty()) {
qDebug() << "Will download" << result.url << "to" << path;
auto dl = Net::Download::makeFile(result.url, path);
m_filesNetJob->addNetAction(dl);
}
break;
}
case Flame::File::Type::Modpack:
logWarning(
tr("Nesting modpacks in modpacks is not implemented, nothing was downloaded: %1").arg(
relpath));
break;
case Flame::File::Type::Cmod2:
case Flame::File::Type::Ctoc:
case Flame::File::Type::Unknown:
logWarning(tr("Unrecognized/unhandled PackageType for: %1").arg(relpath));
break;
}
}
m_modIdResolver.reset();
connect(m_filesNetJob.get(), &NetJob::succeeded, this, [&]() {
m_filesNetJob.reset();
emitSucceeded();
}
);
connect(m_filesNetJob.get(), &NetJob::failed, [&](QString reason) {
m_filesNetJob.reset();
emitFailed(reason);
});
connect(m_filesNetJob.get(), &NetJob::progress, [&](qint64 current, qint64 total) {
setProgress(current, total);
});
setStatus(tr("Downloading mods..."));
m_filesNetJob->start();
}
);
connect(m_filesNetJob.get(), &NetJob::failed, [&](QString reason)
{
m_filesNetJob.reset();
emitFailed(reason);
});
connect(m_filesNetJob.get(), &NetJob::progress, [&](qint64 current, qint64 total)
{
setProgress(current, total);
});
setStatus(tr("Downloading mods..."));
m_filesNetJob->start();
}
);
connect(m_modIdResolver.get(), &Flame::FileResolvingTask::failed, [&](QString reason)
@ -497,6 +581,7 @@ void InstanceImportTask::processMultiMC()
emitSucceeded();
}
// https://docs.modrinth.com/docs/modpacks/format_definition/
void InstanceImportTask::processModrinth()
{
std::vector<Modrinth::File> files;
@ -514,29 +599,33 @@ void InstanceImportTask::processModrinth()
auto jsonFiles = Json::requireIsArrayOf<QJsonObject>(obj, "files", "modrinth.index.json");
bool had_optional = false;
for (auto& obj : jsonFiles) {
for (auto modInfo : jsonFiles) {
Modrinth::File file;
file.path = Json::requireString(obj, "path");
file.path = Json::requireString(modInfo, "path");
auto env = Json::ensureObject(obj, "env");
QString support = Json::ensureString(env, "client", "unsupported");
if (support == "unsupported") {
continue;
} else if (support == "optional") {
// TODO: Make a review dialog for choosing which ones the user wants!
if (!had_optional) {
had_optional = true;
auto info = CustomMessageBox::selectable(
m_parent, tr("Optional mod detected!"),
tr("One or more mods from this modpack are optional. They will be downloaded, but disabled by default!"), QMessageBox::Information);
info->exec();
auto env = Json::ensureObject(modInfo, "env");
// 'env' field is optional
if (!env.isEmpty()) {
QString support = Json::ensureString(env, "client", "unsupported");
if (support == "unsupported") {
continue;
} else if (support == "optional") {
// TODO: Make a review dialog for choosing which ones the user wants!
if (!had_optional) {
had_optional = true;
auto info = CustomMessageBox::selectable(
m_parent, tr("Optional mod detected!"),
tr("One or more mods from this modpack are optional. They will be downloaded, but disabled by default!"),
QMessageBox::Information);
info->exec();
}
if (file.path.endsWith(".jar"))
file.path += ".disabled";
}
if (file.path.endsWith(".jar"))
file.path += ".disabled";
}
QJsonObject hashes = Json::requireObject(obj, "hashes");
QJsonObject hashes = Json::requireObject(modInfo, "hashes");
QString hash;
QCryptographicHash::Algorithm hashAlgorithm;
hash = Json::ensureString(hashes, "sha1");
@ -554,12 +643,28 @@ void InstanceImportTask::processModrinth()
}
file.hash = QByteArray::fromHex(hash.toLatin1());
file.hashAlgorithm = hashAlgorithm;
// Do not use requireUrl, which uses StrictMode, instead use QUrl's default TolerantMode
// (as Modrinth seems to incorrectly handle spaces)
file.download = Json::requireString(Json::ensureArray(obj, "downloads").first(), "Download URL for " + file.path);
if (!file.download.isValid() || !Modrinth::validateDownloadUrl(file.download)) {
throw JSONValidationError("Download URL for " + file.path + " is not a correctly formatted URL");
auto download_arr = Json::ensureArray(modInfo, "downloads");
for(auto download : download_arr) {
qWarning() << download.toString();
bool is_last = download.toString() == download_arr.last().toString();
auto download_url = QUrl(download.toString());
if (!download_url.isValid()) {
qDebug() << QString("Download URL (%1) for %2 is not a correctly formatted URL")
.arg(download_url.toString(), file.path);
if(is_last && file.downloads.isEmpty())
throw JSONValidationError(tr("Download URL for %1 is not a correctly formatted URL").arg(file.path));
}
else {
file.downloads.push_back(download_url);
}
}
files.push_back(file);
}
@ -590,16 +695,26 @@ void InstanceImportTask::processModrinth()
emitFailed(tr("Could not understand pack index:\n") + e.cause());
return;
}
auto mcPath = FS::PathCombine(m_stagingPath, ".minecraft");
QString overridePath = FS::PathCombine(m_stagingPath, "overrides");
if (QFile::exists(overridePath)) {
QString mcPath = FS::PathCombine(m_stagingPath, ".minecraft");
if (!QFile::rename(overridePath, mcPath)) {
auto override_path = FS::PathCombine(m_stagingPath, "overrides");
if (QFile::exists(override_path)) {
if (!QFile::rename(override_path, mcPath)) {
emitFailed(tr("Could not rename the overrides folder:\n") + "overrides");
return;
}
}
// Do client overrides
auto client_override_path = FS::PathCombine(m_stagingPath, "client-overrides");
if (QFile::exists(client_override_path)) {
if (!FS::overrideFolder(mcPath, client_override_path)) {
emitFailed(tr("Could not rename the client overrides folder:\n") + "client overrides");
return;
}
}
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
@ -607,11 +722,11 @@ void InstanceImportTask::processModrinth()
components->buildingFromScratch();
components->setComponentVersion("net.minecraft", minecraftVersion, true);
if (!fabricVersion.isEmpty())
components->setComponentVersion("net.fabricmc.fabric-loader", fabricVersion, true);
components->setComponentVersion("net.fabricmc.fabric-loader", fabricVersion);
if (!quiltVersion.isEmpty())
components->setComponentVersion("org.quiltmc.quilt-loader", quiltVersion, true);
components->setComponentVersion("org.quiltmc.quilt-loader", quiltVersion);
if (!forgeVersion.isEmpty())
components->setComponentVersion("net.minecraftforge", forgeVersion, true);
components->setComponentVersion("net.minecraftforge", forgeVersion);
if (m_instIcon != "default")
{
instance.setIconKey(m_instIcon);
@ -624,13 +739,24 @@ void InstanceImportTask::processModrinth()
instance.saveNow();
m_filesNetJob = new NetJob(tr("Mod download"), APPLICATION->network());
for (auto &file : files)
for (auto file : files)
{
auto path = FS::PathCombine(m_stagingPath, ".minecraft", file.path);
qDebug() << "Will download" << file.download << "to" << path;
auto dl = Net::Download::makeFile(file.download, path);
qDebug() << "Will try to download" << file.downloads.front() << "to" << path;
auto dl = Net::Download::makeFile(file.downloads.dequeue(), path);
dl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash));
m_filesNetJob->addNetAction(dl);
if (file.downloads.size() > 0) {
// FIXME: This really needs to be put into a ConcurrentTask of
// MultipleOptionsTask's , once those exist :)
connect(dl.get(), &NetAction::failed, [this, &file, path, dl]{
auto dl = Net::Download::makeFile(file.downloads.dequeue(), path);
dl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash));
m_filesNetJob->addNetAction(dl);
dl->succeeded();
});
}
}
connect(m_filesNetJob.get(), &NetJob::succeeded, this, [&]()
{

View File

@ -42,6 +42,7 @@
#include <QFutureWatcher>
#include "settings/SettingsObject.h"
#include "QObjectPtr.h"
#include "modplatform/flame/PackManifest.h"
#include <nonstd/optional>
@ -59,6 +60,10 @@ public:
bool canAbort() const override { return true; }
bool abort() override;
const QVector<Flame::File> &getBlockedFiles() const
{
return m_blockedMods;
}
protected:
//! Entry point for tasks.
@ -87,6 +92,7 @@ private: /* data */
std::unique_ptr<QuaZip> m_packZip;
QFuture<nonstd::optional<QStringList>> m_extractFuture;
QFutureWatcher<nonstd::optional<QStringList>> m_extractFutureWatcher;
QVector<Flame::File> m_blockedMods;
enum class ModpackType{
Unknown,
MultiMC,

View File

@ -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 <QDir>
@ -136,7 +156,7 @@ QVariant InstanceList::data(const QModelIndex &index, int role) const
{
case InstancePointerRole:
{
QVariant v = qVariantFromValue((void *)pdata);
QVariant v = QVariant::fromValue((void *)pdata);
return v;
}
case InstanceIDRole:
@ -252,7 +272,7 @@ void InstanceList::setInstanceGroup(const InstanceId& id, const GroupId& name)
QStringList InstanceList::getGroups()
{
return m_groupNameCache.toList();
return m_groupNameCache.values();
}
void InstanceList::deleteGroup(const QString& name)
@ -353,7 +373,11 @@ QList< InstanceId > InstanceList::discoverInstances()
out.append(id);
qDebug() << "Found instance ID" << id;
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
instanceSet = QSet<QString>(out.begin(), out.end());
#else
instanceSet = out.toSet();
#endif
m_instancesProbed = true;
return out;
}
@ -547,8 +571,20 @@ InstancePtr InstanceList::loadInstance(const InstanceId& id)
auto instanceRoot = FS::PathCombine(m_instDir, id);
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(instanceRoot, "instance.cfg"));
InstancePtr inst;
// TODO: Handle incompatible instances
inst.reset(new MinecraftInstance(m_globalSettings, instanceSettings, instanceRoot));
instanceSettings->registerSetting("InstanceType", "");
QString inst_type = instanceSettings->get("InstanceType").toString();
// NOTE: Some PolyMC versions didn't save the InstanceType properly. We will just bank on the probability that this is probably a OneSix instance
if (inst_type == "OneSix" || inst_type.isEmpty())
{
inst.reset(new MinecraftInstance(m_globalSettings, instanceSettings, instanceRoot));
}
else
{
inst.reset(new NullInstance(m_globalSettings, instanceSettings, instanceRoot));
}
qDebug() << "Loaded instance " << inst->name() << " from " << inst->instanceRoot();
return inst;
}

View File

@ -33,10 +33,10 @@ public:
values.append(new LogPage(inst));
std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
values.append(new VersionPage(onesix.get()));
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList(), "mods", "loadermods", tr("Mods"), "Loader-mods");
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList());
modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
values.append(modsPage);
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList(), "coremods", "coremods", tr("Core mods"), "Core-mods"));
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList()));
values.append(new ResourcePackPage(onesix.get()));
values.append(new TexturePackPage(onesix.get()));
values.append(new ShaderPackPage(onesix.get()));

View File

@ -1,10 +1,47 @@
// 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 "JavaCommon.h"
#include "java/JavaUtils.h"
#include "ui/dialogs/CustomMessageBox.h"
#include <MMCStrings.h>
#include <QRegularExpression>
bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
{
if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegExp("-Xm[sx]"))
if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegularExpression("-Xm[sx]"))
|| jvmargs.contains("-XX-MaxHeapSize") || jvmargs.contains("-XX:InitialHeapSize"))
{
auto warnStr = QObject::tr(
@ -18,7 +55,7 @@ bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
return false;
}
// block lunacy with passing required version to the JVM
if (jvmargs.contains(QRegExp("-version:.*"))) {
if (jvmargs.contains(QRegularExpression("-version:.*"))) {
auto warnStr = QObject::tr(
"You tried to pass required Java version argument to the JVM (using \"-version:xxx\"). This is not safe and will not be allowed.\n"
"This message will be displayed until you remove this from the JVM arguments.");
@ -65,6 +102,13 @@ void JavaCommon::javaBinaryWasBad(QWidget *parent, JavaCheckResult result)
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
}
void JavaCommon::javaCheckNotFound(QWidget *parent)
{
QString text;
text += QObject::tr("Java checker library could not be found. Please check your installation");
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
}
void JavaCommon::TestCheck::run()
{
if (!JavaCommon::checkJVMArgs(m_args, m_parent))
@ -72,6 +116,11 @@ void JavaCommon::TestCheck::run()
emit finished();
return;
}
if (JavaUtils::getJavaCheckPath().isEmpty()) {
javaCheckNotFound(m_parent);
emit finished();
return;
}
checker.reset(new JavaChecker());
connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
SLOT(checkFinished(JavaCheckResult)));

View File

@ -10,12 +10,14 @@ namespace JavaCommon
{
bool checkJVMArgs(QString args, QWidget *parent);
// Show a dialog saying that the Java binary was not usable
void javaBinaryWasBad(QWidget *parent, JavaCheckResult result);
// Show a dialog saying that the Java binary was not usable because of bad options
void javaArgsWereBad(QWidget *parent, JavaCheckResult result);
// Show a dialog saying that the Java binary was usable
void javaWasOk(QWidget *parent, JavaCheckResult result);
// Show a dialog saying that the Java binary was not usable because of bad options
void javaArgsWereBad(QWidget *parent, JavaCheckResult result);
// Show a dialog saying that the Java binary was not usable
void javaBinaryWasBad(QWidget *parent, JavaCheckResult result);
// Show a dialog if we couldn't find Java Checker
void javaCheckNotFound(QWidget *parent);
class TestCheck : public QObject
{

View File

@ -1,4 +1,37 @@
// Licensed under the Apache-2.0 license. See README.md for details.
// 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 "Json.h"
@ -22,14 +55,6 @@ void write(const QJsonArray &array, const QString &filename)
write(QJsonDocument(array), filename);
}
QByteArray toBinary(const QJsonObject &obj)
{
return QJsonDocument(obj).toBinaryData();
}
QByteArray toBinary(const QJsonArray &array)
{
return QJsonDocument(array).toBinaryData();
}
QByteArray toText(const QJsonObject &obj)
{
return QJsonDocument(obj).toJson(QJsonDocument::Compact);
@ -48,12 +73,8 @@ QJsonDocument requireDocument(const QByteArray &data, const QString &what)
{
if (isBinaryJson(data))
{
QJsonDocument doc = QJsonDocument::fromBinaryData(data);
if (doc.isNull())
{
throw JsonException(what + ": Invalid JSON (binary JSON detected)");
}
return doc;
// FIXME: Is this needed?
throw JsonException(what + ": Invalid JSON. Binary JSON unsupported");
}
else
{

View File

@ -1,4 +1,37 @@
// Licensed under the Apache-2.0 license. See README.md for details.
// 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
@ -29,8 +62,6 @@ void write(const QJsonObject &object, const QString &filename);
/// @throw FileSystemException
void write(const QJsonArray &array, const QString &filename);
QByteArray toBinary(const QJsonObject &obj);
QByteArray toBinary(const QJsonArray &array);
QByteArray toText(const QJsonObject &obj);
QByteArray toText(const QJsonArray &array);

View File

@ -105,6 +105,11 @@ void LaunchController::decideAccount()
// Open the account manager.
APPLICATION->ShowGlobalSettings(m_parentWidget, "accounts");
}
else if (reply == QMessageBox::No)
{
// Do not open "profile select" dialog.
return;
}
}
m_accountToUse = accounts->defaultAccount();

View File

@ -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 "LoggedProcess.h"
#include "MessageLevel.h"
#include <QDebug>
@ -8,7 +43,11 @@ LoggedProcess::LoggedProcess(QObject *parent) : QProcess(parent)
connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut);
connect(this, &QProcess::readyReadStandardError, this, &LoggedProcess::on_stdErr);
connect(this, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(on_exit(int,QProcess::ExitStatus)));
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
connect(this, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(on_error(QProcess::ProcessError)));
#else
connect(this, SIGNAL(error(QProcess::ProcessError)), this, SLOT(on_error(QProcess::ProcessError)));
#endif
connect(this, &QProcess::stateChanged, this, &LoggedProcess::on_stateChange);
}
@ -157,19 +196,6 @@ void LoggedProcess::on_stateChange(QProcess::ProcessState state)
}
}
#if defined Q_OS_WIN32
#include <windows.h>
#endif
qint64 LoggedProcess::processId() const
{
#ifdef Q_OS_WIN
return pid() ? pid()->dwProcessId : 0;
#else
return pid();
#endif
}
void LoggedProcess::setDetachable(bool detachable)
{
m_is_detachable = detachable;

View File

@ -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.
*/
#pragma once
@ -43,7 +63,6 @@ public:
State state() const;
int exitCode() const;
qint64 processId() const;
void setDetachable(bool detachable);

View File

@ -151,23 +151,23 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
continue;
if (mod.type() == Mod::MOD_ZIPFILE)
{
if (!mergeZipFiles(&zipOut, mod.filename(), addedFiles))
if (!mergeZipFiles(&zipOut, mod.fileinfo(), addedFiles))
{
zipOut.close();
QFile::remove(targetJarPath);
qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar.";
qCritical() << "Failed to add" << mod.fileinfo().fileName() << "to the jar.";
return false;
}
}
else if (mod.type() == Mod::MOD_SINGLEFILE)
{
// FIXME: buggy - does not work with addedFiles
auto filename = mod.filename();
auto filename = mod.fileinfo();
if (!JlCompress::compressFile(&zipOut, filename.absoluteFilePath(), filename.fileName()))
{
zipOut.close();
QFile::remove(targetJarPath);
qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar.";
qCritical() << "Failed to add" << mod.fileinfo().fileName() << "to the jar.";
return false;
}
addedFiles.insert(filename.fileName());
@ -176,7 +176,7 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
{
// untested, but seems to be unused / not possible to reach
// FIXME: buggy - does not work with addedFiles
auto filename = mod.filename();
auto filename = mod.fileinfo();
QString what_to_zip = filename.absoluteFilePath();
QDir dir(what_to_zip);
dir.cdUp();
@ -193,7 +193,7 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
{
zipOut.close();
QFile::remove(targetJarPath);
qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar.";
qCritical() << "Failed to add" << mod.fileinfo().fileName() << "to the jar.";
return false;
}
qDebug() << "Adding folder " << filename.fileName() << " from "
@ -204,7 +204,7 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
// Make sure we do not continue launching when something is missing or undefined...
zipOut.close();
QFile::remove(targetJarPath);
qCritical() << "Failed to add unknown mod type" << mod.filename().fileName() << "to the jar.";
qCritical() << "Failed to add unknown mod type" << mod.fileinfo().fileName() << "to the jar.";
return false;
}
}
@ -305,7 +305,7 @@ nonstd::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString &
QString path;
if(name.contains('/') && !name.endsWith('/')){
path = name.section('/', 0, -2) + "/";
FS::ensureFolderPathExists(path);
FS::ensureFolderPathExists(FS::PathCombine(target, path));
name = name.split('/').last();
}
@ -421,7 +421,7 @@ bool MMCZip::collectFileListRecursively(const QString& rootDir, const QString& s
continue;
}
files->append(e.filePath()); // we want the original paths for MMCZip::compressDirFiles
files->append(e); // we want the original paths for MMCZip::compressDirFiles
}
return true;
}

View File

@ -1,24 +1,50 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
* 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/>.
*/
#include "ModDownloadTask.h"
#include "Application.h"
#include "minecraft/mod/ModFolderModel.h"
ModDownloadTask::ModDownloadTask(const QUrl sourceUrl,const QString filename, const std::shared_ptr<ModFolderModel> mods)
: m_sourceUrl(sourceUrl), mods(mods), filename(filename) {
}
ModDownloadTask::ModDownloadTask(ModPlatform::IndexedPack mod, ModPlatform::IndexedVersion version, const std::shared_ptr<ModFolderModel> mods, bool is_indexed)
: m_mod(mod), m_mod_version(version), mods(mods)
{
if (is_indexed) {
m_update_task.reset(new LocalModUpdateTask(mods->indexDir(), m_mod, m_mod_version));
void ModDownloadTask::executeTask() {
setStatus(tr("Downloading mod:\n%1").arg(m_sourceUrl.toString()));
addTask(m_update_task);
}
m_filesNetJob.reset(new NetJob(tr("Mod download"), APPLICATION->network()));
m_filesNetJob->addNetAction(Net::Download::makeFile(m_sourceUrl, mods->dir().absoluteFilePath(filename)));
m_filesNetJob->setStatus(tr("Downloading mod:\n%1").arg(m_mod_version.downloadUrl));
m_filesNetJob->addNetAction(Net::Download::makeFile(m_mod_version.downloadUrl, mods->dir().absoluteFilePath(getFilename())));
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &ModDownloadTask::downloadSucceeded);
connect(m_filesNetJob.get(), &NetJob::progress, this, &ModDownloadTask::downloadProgressChanged);
connect(m_filesNetJob.get(), &NetJob::failed, this, &ModDownloadTask::downloadFailed);
m_filesNetJob->start();
addTask(m_filesNetJob);
}
void ModDownloadTask::downloadSucceeded()
{
emitSucceeded();
m_filesNetJob.reset();
}
@ -32,8 +58,3 @@ void ModDownloadTask::downloadProgressChanged(qint64 current, qint64 total)
{
emit progress(current, total);
}
bool ModDownloadTask::abort() {
return m_filesNetJob->abort();
}

View File

@ -1,28 +1,45 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
* 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/>.
*/
#pragma once
#include "QObjectPtr.h"
#include "tasks/Task.h"
#include "minecraft/mod/ModFolderModel.h"
#include "net/NetJob.h"
#include <QUrl>
#include "tasks/SequentialTask.h"
#include "modplatform/ModIndex.h"
#include "minecraft/mod/tasks/LocalModUpdateTask.h"
class ModDownloadTask : public Task {
class ModFolderModel;
class ModDownloadTask : public SequentialTask {
Q_OBJECT
public:
explicit ModDownloadTask(const QUrl sourceUrl, const QString filename, const std::shared_ptr<ModFolderModel> mods);
const QString& getFilename() const { return filename; }
public slots:
bool abort() override;
protected:
//! Entry point for tasks.
void executeTask() override;
explicit ModDownloadTask(ModPlatform::IndexedPack mod, ModPlatform::IndexedVersion version, const std::shared_ptr<ModFolderModel> mods, bool is_indexed);
const QString& getFilename() const { return m_mod_version.fileName; }
private:
QUrl m_sourceUrl;
NetJob::Ptr m_filesNetJob;
ModPlatform::IndexedPack m_mod;
ModPlatform::IndexedVersion m_mod_version;
const std::shared_ptr<ModFolderModel> mods;
const QString filename;
NetJob::Ptr m_filesNetJob;
LocalModUpdateTask::Ptr m_update_task;
void downloadProgressChanged(qint64 current, qint64 total);

View File

@ -39,6 +39,10 @@ public:
{
return QProcessEnvironment();
}
QProcessEnvironment createLaunchEnvironment() override
{
return QProcessEnvironment();
}
QMap<QString, QString> getVariables() const override
{
return QMap<QString, QString>();

View File

@ -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 <QStringView>
#include <QList>
class QUrl;
@ -39,13 +75,21 @@ private:
break;
}
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto numPart = QStringView{m_fullString}.left(cutoff);
#else
auto numPart = m_fullString.leftRef(cutoff);
#endif
if(numPart.size())
{
numValid = true;
m_numPart = numPart.toInt();
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto stringPart = QStringView{m_fullString}.mid(cutoff);
#else
auto stringPart = m_fullString.midRef(cutoff);
#endif
if(stringPart.size())
{
m_stringPart = stringPart.toString();

View File

@ -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 "VersionProxyModel.h"
#include "Application.h"
#include <QSortFilterProxyModel>
@ -208,7 +243,8 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const
{
return APPLICATION->getThemedIcon("bug");
}
auto pixmap = QPixmapCache::find("placeholder");
QPixmap pixmap;
QPixmapCache::find("placeholder", &pixmap);
if(!pixmap)
{
QPixmap px(16,16);
@ -216,7 +252,7 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const
QPixmapCache::insert("placeholder", px);
return px;
}
return *pixmap;
return pixmap;
}
}
default:

View File

@ -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 "IconList.h"
@ -56,6 +76,15 @@ IconList::IconList(const QStringList &builtinPaths, QString path, QObject *paren
emit iconUpdated({});
}
void IconList::sortIconList()
{
qDebug() << "Sorting icon list...";
std::sort(icons.begin(), icons.end(), [](const MMCIcon& a, const MMCIcon& b) {
return a.m_key.localeAwareCompare(b.m_key) < 0;
});
reindex();
}
void IconList::directoryChanged(const QString &path)
{
QDir new_dir (path);
@ -77,7 +106,11 @@ void IconList::directoryChanged(const QString &path)
QString &foo = (*it);
foo = m_dir.filePath(foo);
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QSet<QString> new_set(new_list.begin(), new_list.end());
#else
auto new_set = new_list.toSet();
#endif
QList<QString> current_list;
for (auto &it : icons)
{
@ -85,7 +118,11 @@ void IconList::directoryChanged(const QString &path)
continue;
current_list.push_back(it.m_images[IconType::FileBased].filename);
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QSet<QString> current_set(current_list.begin(), current_list.end());
#else
QSet<QString> current_set = current_list.toSet();
#endif
QSet<QString> to_remove = current_set;
to_remove -= new_set;
@ -141,6 +178,8 @@ void IconList::directoryChanged(const QString &path)
emit iconUpdated(key);
}
}
sortIconList();
}
void IconList::fileChanged(const QString &path)
@ -273,7 +312,7 @@ void IconList::installIcons(const QStringList &iconFiles)
QFileInfo fileinfo(file);
if (!fileinfo.isReadable() || !fileinfo.isFile())
continue;
QString target = FS::PathCombine(m_dir.dirName(), fileinfo.fileName());
QString target = FS::PathCombine(getDirectory(), fileinfo.fileName());
QString suffix = fileinfo.suffix();
if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif")
@ -290,7 +329,7 @@ void IconList::installIcon(const QString &file, const QString &name)
if(!fileinfo.isReadable() || !fileinfo.isFile())
return;
QString target = FS::PathCombine(m_dir.dirName(), name);
QString target = FS::PathCombine(getDirectory(), name);
QFile::copy(file, target);
}

View File

@ -71,6 +71,7 @@ private:
// hide assign op
IconList &operator=(const IconList &) = delete;
void reindex();
void sortIconList();
public slots:
void directoryChanged(const QString &path);

View File

@ -1,21 +1,41 @@
/* 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 "MMCIcon.h"
#include <QFileInfo>
#include <xdgicon.h>
#include <QIcon>
IconType operator--(IconType &t, int)
{
@ -63,7 +83,7 @@ QIcon MMCIcon::icon() const
if(!icon.isNull())
return icon;
// FIXME: inject this.
return XdgIcon::fromTheme(m_images[m_current_type].key);
return QIcon::fromTheme(m_images[m_current_type].key);
}
void MMCIcon::remove(IconType rm_type)

View File

@ -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 "JavaChecker.h"
#include <QFile>
@ -16,7 +51,13 @@ JavaChecker::JavaChecker(QObject *parent) : QObject(parent)
void JavaChecker::performCheck()
{
QString checkerJar = FS::PathCombine(APPLICATION->getJarsPath(), "JavaCheck.jar");
QString checkerJar = JavaUtils::getJavaCheckPath();
if (checkerJar.isEmpty())
{
qDebug() << "Java checker library could not be found. Please check your installation.";
return;
}
QStringList args;
@ -47,7 +88,11 @@ void JavaChecker::performCheck()
qDebug() << "Running java checker: " + m_path + args.join(" ");;
connect(process.get(), SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(finished(int, QProcess::ExitStatus)));
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
connect(process.get(), SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)));
#else
connect(process.get(), SIGNAL(error(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)));
#endif
connect(process.get(), SIGNAL(readyReadStandardOutput()), this, SLOT(stdoutReady()));
connect(process.get(), SIGNAL(readyReadStandardError()), this, SLOT(stderrReady()));
connect(&killTimer, SIGNAL(timeout()), SLOT(timeout()));
@ -99,7 +144,12 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
bool success = true;
QMap<QString, QString> results;
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QStringList lines = m_stdout.split("\n", Qt::SkipEmptyParts);
#else
QStringList lines = m_stdout.split("\n", QString::SkipEmptyParts);
#endif
for(QString line : lines)
{
line = line.trimmed();
@ -108,7 +158,11 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
continue;
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
auto parts = line.split('=', Qt::SkipEmptyParts);
#else
auto parts = line.split('=', QString::SkipEmptyParts);
#endif
if(parts.size() != 2 || parts[0].isEmpty() || parts[1].isEmpty())
{
continue;

View File

@ -1,21 +1,40 @@
/* 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 <QtNetwork>
#include <QtXml>
#include <QRegExp>
#include <QDebug>
@ -81,7 +100,7 @@ QVariant JavaInstallList::data(const QModelIndex &index, int role) const
switch (role)
{
case VersionPointerRole:
return qVariantFromValue(m_vlist[index.row()]);
return QVariant::fromValue(m_vlist[index.row()]);
case VersionIdRole:
return version->descriptor();
case VersionRole:

View File

@ -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 <QStringList>
@ -24,6 +44,7 @@
#include "java/JavaUtils.h"
#include "java/JavaInstallList.h"
#include "FileSystem.h"
#include "Application.h"
#define IBUS "@im=ibus"
@ -176,25 +197,25 @@ QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString
archType = "32";
HKEY jreKey;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyName.toStdString().c_str(), 0,
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyName.toStdWString().c_str(), 0,
KEY_READ | keyType | KEY_ENUMERATE_SUB_KEYS, &jreKey) == ERROR_SUCCESS)
{
// Read the current type version from the registry.
// This will be used to find any key that contains the JavaHome value.
char *value = new char[0];
DWORD valueSz = 0;
if (RegQueryValueExA(jreKey, "CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz) ==
if (RegQueryValueExW(jreKey, L"CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz) ==
ERROR_MORE_DATA)
{
value = new char[valueSz];
RegQueryValueExA(jreKey, "CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz);
RegQueryValueExW(jreKey, L"CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz);
}
TCHAR subKeyName[255];
DWORD subKeyNameSize, numSubKeys, retCode;
// Get the number of subkeys
RegQueryInfoKey(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL,
RegQueryInfoKeyW(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL,
NULL, NULL);
// Iterate until RegEnumKeyEx fails
@ -203,31 +224,32 @@ QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString
for (DWORD i = 0; i < numSubKeys; i++)
{
subKeyNameSize = 255;
retCode = RegEnumKeyEx(jreKey, i, subKeyName, &subKeyNameSize, NULL, NULL, NULL,
NULL);
retCode = RegEnumKeyExW(jreKey, i, subKeyName, &subKeyNameSize, NULL, NULL, NULL,
NULL);
QString newSubkeyName = QString::fromWCharArray(subKeyName);
if (retCode == ERROR_SUCCESS)
{
// Now open the registry key for the version that we just got.
QString newKeyName = keyName + "\\" + subKeyName + subkeySuffix;
QString newKeyName = keyName + "\\" + newSubkeyName + subkeySuffix;
HKEY newKey;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, newKeyName.toStdString().c_str(), 0,
KEY_READ | KEY_WOW64_64KEY, &newKey) == ERROR_SUCCESS)
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, newKeyName.toStdWString().c_str(), 0,
KEY_READ | KEY_WOW64_64KEY, &newKey) == ERROR_SUCCESS)
{
// Read the JavaHome value to find where Java is installed.
value = new char[0];
valueSz = 0;
if (RegQueryValueEx(newKey, keyJavaDir.toStdString().c_str(), NULL, NULL, (BYTE *)value,
&valueSz) == ERROR_MORE_DATA)
if (RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, (BYTE *)value,
&valueSz) == ERROR_MORE_DATA)
{
value = new char[valueSz];
RegQueryValueEx(newKey, keyJavaDir.toStdString().c_str(), NULL, NULL, (BYTE *)value,
&valueSz);
RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, (BYTE *)value,
&valueSz);
// Now, we construct the version object and add it to the list.
JavaInstallPtr javaVersion(new JavaInstall());
javaVersion->id = subKeyName;
javaVersion->id = newSubkeyName;
javaVersion->arch = archType;
javaVersion->path =
QDir(FS::PathCombine(value, "bin")).absoluteFilePath("javaw.exe");
@ -437,3 +459,8 @@ QList<QString> JavaUtils::FindJavaPaths()
return addJavasFromEnv(javas);
}
#endif
QString JavaUtils::getJavaCheckPath()
{
return APPLICATION->getJarPath("JavaCheck.jar");
}

View File

@ -39,4 +39,6 @@ public:
#ifdef Q_OS_WIN
QList<JavaInstallPtr> FindJavaFromRegistryKey(DWORD keyType, QString keyName, QString keyJavaDir, QString subkeySuffix = "");
#endif
static QString getJavaCheckPath();
};

View File

@ -1,5 +1,4 @@
#include <QTest>
#include "TestUtil.h"
#include "java/JavaVersion.h"

View File

@ -282,6 +282,23 @@ void LaunchTask::emitFailed(QString reason)
Task::emitFailed(reason);
}
void LaunchTask::substituteVariables(const QStringList &args) const
{
auto variables = m_instance->getVariables();
auto envVariables = QProcessEnvironment::systemEnvironment();
for (auto arg : args) {
for (auto key : variables)
{
arg.replace("$" + key, variables.value(key));
}
for (auto env : envVariables.keys())
{
arg.replace("$" + env, envVariables.value(env));
}
}
}
QString LaunchTask::substituteVariables(const QString &cmd) const
{
QString out = cmd;

View File

@ -1,18 +1,38 @@
/* Copyright 2013-2021 MultiMC Contributors
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
* 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.
*
* 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 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.
*
* http://www.apache.org/licenses/LICENSE-2.0
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* 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.
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
*
* 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
@ -85,6 +105,7 @@ public: /* methods */
shared_qobject_ptr<LogModel> getLogModel();
public:
void substituteVariables(const QStringList &args) const;
QString substituteVariables(const QString &cmd) const;
QString censorPrivateInfo(QString in);

View File

@ -34,6 +34,7 @@
*/
#include "CheckJava.h"
#include "java/JavaUtils.h"
#include <launch/LaunchTask.h>
#include <FileSystem.h>
#include <QStandardPaths>
@ -71,15 +72,26 @@ void CheckJava::executeTask()
emit logLine("Java path is:\n" + m_javaPath + "\n\n", MessageLevel::Launcher);
}
if (JavaUtils::getJavaCheckPath().isEmpty())
{
const char *reason = QT_TR_NOOP("Java checker library could not be found. Please check your installation.");
emit logLine(tr(reason), MessageLevel::Fatal);
emitFailed(tr(reason));
return;
}
QFileInfo javaInfo(realJavaPath);
qlonglong javaUnixTime = javaInfo.lastModified().toMSecsSinceEpoch();
auto storedUnixTime = settings->get("JavaTimestamp").toLongLong();
auto storedArchitecture = settings->get("JavaArchitecture").toString();
auto storedRealArchitecture = settings->get("JavaRealArchitecture").toString();
auto storedVersion = settings->get("JavaVersion").toString();
auto storedVendor = settings->get("JavaVendor").toString();
m_javaUnixTime = javaUnixTime;
// if timestamps are not the same, or something is missing, check!
if (javaUnixTime != storedUnixTime || storedVersion.size() == 0 || storedArchitecture.size() == 0 || storedVendor.size() == 0)
if (javaUnixTime != storedUnixTime || storedVersion.size() == 0
|| storedArchitecture.size() == 0 || storedRealArchitecture.size() == 0
|| storedVendor.size() == 0)
{
m_JavaChecker = new JavaChecker();
emit logLine(QString("Checking Java version..."), MessageLevel::Launcher);
@ -92,8 +104,9 @@ void CheckJava::executeTask()
{
auto verString = instance->settings()->get("JavaVersion").toString();
auto archString = instance->settings()->get("JavaArchitecture").toString();
auto realArchString = settings->get("JavaRealArchitecture").toString();
auto vendorString = instance->settings()->get("JavaVendor").toString();
printJavaInfo(verString, archString, vendorString);
printJavaInfo(verString, archString, realArchString, vendorString);
}
emitSucceeded();
}
@ -124,10 +137,11 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
case JavaCheckResult::Validity::Valid:
{
auto instance = m_parent->instance();
printJavaInfo(result.javaVersion.toString(), result.realPlatform, result.javaVendor);
printJavaInfo(result.javaVersion.toString(), result.mojangPlatform, 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("JavaRealArchitecture", result.realPlatform);
instance->settings()->set("JavaVendor", result.javaVendor);
instance->settings()->set("JavaTimestamp", m_javaUnixTime);
emitSucceeded();
@ -136,9 +150,10 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
}
}
void CheckJava::printJavaInfo(const QString& version, const QString& architecture, const QString & vendor)
void CheckJava::printJavaInfo(const QString& version, const QString& architecture, const QString& realArchitecture, const QString & vendor)
{
emit logLine(QString("Java is version %1, using %2 architecture, from %3.\n\n").arg(version, architecture, vendor), MessageLevel::Launcher);
emit logLine(QString("Java is version %1, using %2 (%3) architecture, from %4.\n\n")
.arg(version, architecture, realArchitecture, vendor), MessageLevel::Launcher);
}
void CheckJava::printSystemInfo(bool javaIsKnown, bool javaIs64bit)

View File

@ -35,7 +35,7 @@ private slots:
void checkJavaFinished(JavaCheckResult result);
private:
void printJavaInfo(const QString & version, const QString & architecture, const QString & vendor);
void printJavaInfo(const QString & version, const QString & architecture, const QString & realArchitecture, const QString & vendor);
void printSystemInfo(bool javaIsKnown, bool javaIs64bit);
private:

View File

@ -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 "PostLaunchCommand.h"
@ -27,9 +47,19 @@ PostLaunchCommand::PostLaunchCommand(LaunchTask *parent) : LaunchStep(parent)
void PostLaunchCommand::executeTask()
{
//FIXME: where to put this?
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
auto args = QProcess::splitCommand(m_command);
m_parent->substituteVariables(args);
emit logLine(tr("Running Post-Launch command: %1").arg(args.join(' ')), MessageLevel::Launcher);
const QString program = args.takeFirst();
m_process.start(program, args);
#else
QString postlaunch_cmd = m_parent->substituteVariables(m_command);
emit logLine(tr("Running Post-Launch command: %1").arg(postlaunch_cmd), MessageLevel::Launcher);
m_process.start(postlaunch_cmd);
#endif
}
void PostLaunchCommand::on_state(LoggedProcess::State state)

View File

@ -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 "PreLaunchCommand.h"
@ -28,9 +48,18 @@ PreLaunchCommand::PreLaunchCommand(LaunchTask *parent) : LaunchStep(parent)
void PreLaunchCommand::executeTask()
{
//FIXME: where to put this?
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
auto args = QProcess::splitCommand(m_command);
m_parent->substituteVariables(args);
emit logLine(tr("Running Pre-Launch command: %1").arg(args.join(' ')), MessageLevel::Launcher);
const QString program = args.takeFirst();
m_process.start(program, args);
#else
QString prelaunch_cmd = m_parent->substituteVariables(m_command);
emit logLine(tr("Running Pre-Launch command: %1").arg(prelaunch_cmd), MessageLevel::Launcher);
m_process.start(prelaunch_cmd);
#endif
}
void PreLaunchCommand::on_state(LoggedProcess::State state)

View File

@ -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 "Application.h"
// #define BREAK_INFINITE_LOOP
@ -24,11 +59,9 @@ int main(int argc, char *argv[])
return 42;
#endif
#if QT_VERSION <= QT_VERSION_CHECK(6, 0, 0)
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif
// initialize Qt

View File

@ -75,7 +75,16 @@ Meta::BaseEntity::~BaseEntity()
QUrl Meta::BaseEntity::url() const
{
return QUrl(BuildConfig.META_URL).resolved(localFilename());
auto s = APPLICATION->settings();
QString metaOverride = s->get("MetaURLOverride").toString();
if(metaOverride.isEmpty())
{
return QUrl(BuildConfig.META_URL).resolved(localFilename());
}
else
{
return QUrl(metaOverride).resolved(localFilename());
}
}
bool Meta::BaseEntity::loadLocalFile()

View File

@ -1,5 +1,4 @@
#include <QTest>
#include "TestUtil.h"
#include "meta/Index.h"
#include "meta/VersionList.h"

View File

@ -1,16 +1,36 @@
/* Copyright 2013-2021 MultiMC Contributors
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
*
* 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 <QFileInfo>
@ -297,7 +317,7 @@ NetAction::Ptr AssetObject::getDownloadAction()
auto rawHash = QByteArray::fromHex(hash.toLatin1());
objectDL->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawHash));
}
objectDL->m_total_progress = size;
objectDL->setProgress(objectDL->getProgress(), size);
return objectDL;
}
return nullptr;

View File

@ -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;

View File

@ -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;
}

View File

@ -1,5 +1,4 @@
#include <QTest>
#include "TestUtil.h"
#include "minecraft/GradleSpecifier.h"

View File

@ -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, {});

View File

@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* 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
@ -153,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);
@ -167,6 +174,8 @@ MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsO
m_settings->registerOverride(globalSettings->getSetting("CloseAfterLaunch"), miscellaneousOverride);
m_settings->registerOverride(globalSettings->getSetting("QuitAfterGameStop"), miscellaneousOverride);
m_settings->set("InstanceType", "OneSix");
m_components.reset(new PackProfile(this));
}
@ -432,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;
}
@ -487,9 +526,8 @@ QStringList MinecraftInstance::processMinecraftArgs(
}
}
// blatant self-promotion.
token_mapping["profile_name"] = token_mapping["version_name"] = BuildConfig.LAUNCHER_NAME;
token_mapping["profile_name"] = name();
token_mapping["version_name"] = profile->getMinecraftVersion();
token_mapping["version_type"] = profile->getMinecraftVersionType();
QString absRootDir = QDir(gameRoot()).absolutePath();
@ -502,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);
@ -659,23 +701,23 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr
out << QString("%1:").arg(label);
auto modList = model.allMods();
std::sort(modList.begin(), modList.end(), [](Mod &a, Mod &b) {
auto aName = a.filename().completeBaseName();
auto bName = b.filename().completeBaseName();
auto aName = a.fileinfo().completeBaseName();
auto bName = b.fileinfo().completeBaseName();
return aName.localeAwareCompare(bName) < 0;
});
for(auto & mod: modList)
{
if(mod.type() == Mod::MOD_FOLDER)
{
out << u8" [📁] " + mod.filename().completeBaseName() + " (folder)";
out << u8" [📁] " + mod.fileinfo().completeBaseName() + " (folder)";
continue;
}
if(mod.enabled()) {
out << u8" [✔️] " + mod.filename().completeBaseName();
out << u8" [✔️] " + mod.fileinfo().completeBaseName();
}
else {
out << u8" [❌] " + mod.filename().completeBaseName() + " (disabled)";
out << u8" [❌] " + mod.fileinfo().completeBaseName() + " (disabled)";
}
}
@ -745,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>"));
}
@ -824,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) {
@ -1013,7 +1065,8 @@ std::shared_ptr<ModFolderModel> MinecraftInstance::loaderModList() const
{
if (!m_loader_mod_list)
{
m_loader_mod_list.reset(new ModFolderModel(modsRoot()));
bool is_indexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
m_loader_mod_list.reset(new ModFolderModel(modsRoot(), is_indexed));
m_loader_mod_list->disableInteraction(isRunning());
connect(this, &BaseInstance::runningStatusChanged, m_loader_mod_list.get(), &ModFolderModel::disableInteraction);
}
@ -1024,7 +1077,8 @@ std::shared_ptr<ModFolderModel> MinecraftInstance::coreModList() const
{
if (!m_core_mod_list)
{
m_core_mod_list.reset(new ModFolderModel(coreModsDir()));
bool is_indexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
m_core_mod_list.reset(new ModFolderModel(coreModsDir(), is_indexed));
m_core_mod_list->disableInteraction(isRunning());
connect(this, &BaseInstance::runningStatusChanged, m_core_mod_list.get(), &ModFolderModel::disableInteraction);
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -65,7 +65,7 @@ struct MojangAssetIndexInfo : public MojangDownloadInfo
// https://www.theregister.co.uk/2017/02/28/aws_is_awol_as_s3_goes_haywire/
if(id == "legacy")
{
url = "https://launchermeta.mojang.com/mc/assets/legacy/c0fd82e8ce9fbc93119e40d96d5a4e62cfa3f729/legacy.json";
url = "https://piston-meta.mojang.com/mc/assets/legacy/c0fd82e8ce9fbc93119e40d96d5a4e62cfa3f729/legacy.json";
}
// HACK
else

View File

@ -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);

View File

@ -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;

View File

@ -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>
@ -36,6 +56,13 @@
#include "ComponentUpdateTask.h"
#include "Application.h"
#include "modplatform/ModAPI.h"
static const QMap<QString, ModAPI::ModLoaderType> modloaderMapping{
{"net.minecraftforge", ModAPI::Forge},
{"net.fabricmc.fabric-loader", ModAPI::Fabric},
{"org.quiltmc.quilt-loader", ModAPI::Quilt}
};
PackProfile::PackProfile(MinecraftInstance * instance)
: QAbstractListModel()
@ -339,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();
}
@ -680,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();
@ -971,19 +1003,19 @@ void PackProfile::disableInteraction(bool disable)
}
}
ModAPI::ModLoaderType PackProfile::getModLoader()
ModAPI::ModLoaderTypes PackProfile::getModLoaders()
{
if (!getComponentVersion("net.minecraftforge").isEmpty())
ModAPI::ModLoaderTypes result = ModAPI::Unspecified;
QMapIterator<QString, ModAPI::ModLoaderType> i(modloaderMapping);
while (i.hasNext())
{
return ModAPI::Forge;
i.next();
Component* c = getComponent(i.key());
if (c != nullptr && c->isEnabled()) {
result |= i.value();
}
}
else if (!getComponentVersion("net.fabricmc.fabric-loader").isEmpty())
{
return ModAPI::Fabric;
}
else if (!getComponentVersion("org.quiltmc.quilt-loader").isEmpty())
{
return ModAPI::Quilt;
}
return ModAPI::Unspecified;
return result;
}

View File

@ -118,7 +118,7 @@ public:
// todo(merged): is this the best approach
void appendComponent(ComponentPtr component);
ModAPI::ModLoaderType getModLoader();
ModAPI::ModLoaderTypes getModLoaders();
private:
void scheduleSave();

View File

@ -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"

View File

@ -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)

View File

@ -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);

View File

@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* 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
@ -55,7 +56,7 @@ void VersionFile::applyTo(LaunchProfile *profile)
// Only real Minecraft can set those. Don't let anything override them.
if (isMinecraftVersion(uid))
{
profile->applyMinecraftVersion(minecraftVersion);
profile->applyMinecraftVersion(version);
profile->applyMinecraftVersionType(type);
// HACK: ignore assets from other version files than Minecraft
// workaround for stupid assets issue caused by amazon:
@ -88,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);
}
}
*/

View File

@ -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);

View File

@ -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)

View File

@ -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")) {

View File

@ -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();
}

View File

@ -58,8 +58,8 @@ public:
enum VListColumns
{
// TODO: Add icon column.
NameColumn = 0,
ProfileNameColumn,
ProfileNameColumn = 0,
NameColumn,
MigrationColumn,
TypeColumn,
StatusColumn,

View File

@ -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: {

View File

@ -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)));

View File

@ -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;
}

View File

@ -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;

View File

@ -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)

View File

@ -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 "LauncherPartLaunch.h"
@ -23,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();
@ -71,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);
@ -81,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
@ -121,7 +154,7 @@ void LauncherPartLaunch::executeTask()
#else
args << classPath.join(':');
#endif
args << "org.multimc.EntryPoint";
args << "org.polymc.EntryPoint";
qDebug() << args.join(' ');
@ -146,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)

View File

@ -0,0 +1,59 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
*
* 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 <memory>
#include "modplatform/packwiz/Packwiz.h"
// launcher/minecraft/mod/Mod.h
class Mod;
/* Abstraction file for easily changing the way metadata is stored / handled
* Needs to be a class because of -Wunused-function and no C++17 [[maybe_unused]]
* */
class Metadata {
public:
using ModStruct = Packwiz::V1::Mod;
static auto create(QDir& index_dir, ModPlatform::IndexedPack& mod_pack, ModPlatform::IndexedVersion& mod_version) -> ModStruct
{
return Packwiz::V1::createModFormat(index_dir, mod_pack, mod_version);
}
static auto create(QDir& index_dir, Mod& internal_mod) -> ModStruct
{
return Packwiz::V1::createModFormat(index_dir, internal_mod);
}
static void update(QDir& index_dir, ModStruct& mod)
{
Packwiz::V1::updateModIndex(index_dir, mod);
}
static void remove(QDir& index_dir, QString& mod_name)
{
Packwiz::V1::deleteModIndex(index_dir, mod_name);
}
static auto get(QDir& index_dir, QString& mod_name) -> ModStruct
{
return Packwiz::V1::getIndexForMod(index_dir, mod_name);
}
};

View File

@ -1,24 +1,49 @@
/* 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.
*/
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
* 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 "Mod.h"
#include <QDir>
#include <QString>
#include "Mod.h"
#include <QDebug>
#include <FileSystem.h>
#include <QDebug>
#include "Application.h"
#include "MetadataHandler.h"
namespace {
@ -26,57 +51,67 @@ ModDetails invalidDetails;
}
Mod::Mod(const QFileInfo &file)
Mod::Mod(const QFileInfo& file)
{
repath(file);
m_changedDateTime = file.lastModified();
}
void Mod::repath(const QFileInfo &file)
Mod::Mod(const QDir& mods_dir, const Metadata::ModStruct& metadata)
: m_file(mods_dir.absoluteFilePath(metadata.filename))
, m_internal_id(metadata.filename)
, m_name(metadata.name)
{
if (m_file.isDir()) {
m_type = MOD_FOLDER;
} else {
if (metadata.filename.endsWith(".zip") || metadata.filename.endsWith(".jar"))
m_type = MOD_ZIPFILE;
else if (metadata.filename.endsWith(".litemod"))
m_type = MOD_LITEMOD;
else
m_type = MOD_SINGLEFILE;
}
m_enabled = true;
m_changedDateTime = m_file.lastModified();
m_temp_metadata = std::make_shared<Metadata::ModStruct>(std::move(metadata));
}
void Mod::repath(const QFileInfo& file)
{
m_file = file;
QString name_base = file.fileName();
m_type = Mod::MOD_UNKNOWN;
m_mmc_id = name_base;
m_internal_id = name_base;
if (m_file.isDir())
{
if (m_file.isDir()) {
m_type = MOD_FOLDER;
m_name = name_base;
}
else if (m_file.isFile())
{
if (name_base.endsWith(".disabled"))
{
} else if (m_file.isFile()) {
if (name_base.endsWith(".disabled")) {
m_enabled = false;
name_base.chop(9);
}
else
{
} else {
m_enabled = true;
}
if (name_base.endsWith(".zip") || name_base.endsWith(".jar"))
{
if (name_base.endsWith(".zip") || name_base.endsWith(".jar")) {
m_type = MOD_ZIPFILE;
name_base.chop(4);
}
else if (name_base.endsWith(".litemod"))
{
} else if (name_base.endsWith(".litemod")) {
m_type = MOD_LITEMOD;
name_base.chop(8);
}
else
{
} else {
m_type = MOD_SINGLEFILE;
}
m_name = name_base;
}
}
bool Mod::enable(bool value)
auto Mod::enable(bool value) -> bool
{
if (m_type == Mod::MOD_UNKNOWN || m_type == Mod::MOD_FOLDER)
return false;
@ -85,67 +120,126 @@ bool Mod::enable(bool value)
return false;
QString path = m_file.absoluteFilePath();
if (value)
{
QFile foo(path);
QFile file(path);
if (value) {
if (!path.endsWith(".disabled"))
return false;
path.chop(9);
if (!foo.rename(path))
if (!file.rename(path))
return false;
}
else
{
QFile foo(path);
} else {
path += ".disabled";
if (!foo.rename(path))
if (!file.rename(path))
return false;
}
repath(QFileInfo(path));
if (status() == ModStatus::NoMetadata)
repath(QFileInfo(path));
m_enabled = value;
return true;
}
bool Mod::destroy()
void Mod::setStatus(ModStatus status)
{
if (m_localDetails) {
m_localDetails->status = status;
} else {
m_temp_status = status;
}
}
void Mod::setMetadata(Metadata::ModStruct* metadata)
{
if (status() == ModStatus::NoMetadata)
setStatus(ModStatus::Installed);
if (m_localDetails) {
m_localDetails->metadata.reset(metadata);
} else {
m_temp_metadata.reset(metadata);
}
}
auto Mod::destroy(QDir& index_dir) -> bool
{
auto n = name();
// FIXME: This can fail to remove the metadata if the
// "ModMetadataDisabled" setting is on, since there could
// be a name mismatch!
Metadata::remove(index_dir, n);
m_type = MOD_UNKNOWN;
return FS::deletePath(m_file.filePath());
}
const ModDetails & Mod::details() const
auto Mod::details() const -> const ModDetails&
{
if(!m_localDetails)
return invalidDetails;
return *m_localDetails;
return m_localDetails ? *m_localDetails : invalidDetails;
}
QString Mod::version() const
auto Mod::name() const -> QString
{
return details().version;
}
QString Mod::name() const
{
auto & d = details();
if(!d.name.isEmpty()) {
return d.name;
auto d_name = details().name;
if (!d_name.isEmpty()) {
return d_name;
}
return m_name;
}
QString Mod::homeurl() const
auto Mod::version() const -> QString
{
return details().version;
}
auto Mod::homeurl() const -> QString
{
return details().homeurl;
}
QString Mod::description() const
auto Mod::description() const -> QString
{
return details().description;
}
QStringList Mod::authors() const
auto Mod::authors() const -> QStringList
{
return details().authors;
}
auto Mod::status() const -> ModStatus
{
if (!m_localDetails)
return m_temp_status;
return details().status;
}
auto Mod::metadata() -> std::shared_ptr<Metadata::ModStruct>
{
if (m_localDetails)
return m_localDetails->metadata;
return m_temp_metadata;
}
auto Mod::metadata() const -> const std::shared_ptr<Metadata::ModStruct>
{
if (m_localDetails)
return m_localDetails->metadata;
return m_temp_metadata;
}
void Mod::finishResolvingWithDetails(std::shared_ptr<ModDetails> details)
{
m_resolving = false;
m_resolved = true;
m_localDetails = details;
if (m_localDetails && m_temp_metadata && m_temp_metadata->isValid()) {
m_localDetails->metadata = m_temp_metadata;
if (status() == ModStatus::NoMetadata)
setStatus(ModStatus::Installed);
}
setStatus(m_temp_status);
}

View File

@ -1,28 +1,46 @@
/* 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.
*/
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
*
* 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 <QFileInfo>
#include <QDateTime>
#include <QFileInfo>
#include <QList>
#include <memory>
#include "ModDetails.h"
class Mod
{
public:
@ -32,84 +50,73 @@ public:
MOD_ZIPFILE, //!< The mod is a zip file containing the mod's class files.
MOD_SINGLEFILE, //!< The mod is a single file (not a zip file).
MOD_FOLDER, //!< The mod is in a folder on the filesystem.
MOD_LITEMOD, //!< The mod is a litemod
MOD_LITEMOD, //!< The mod is a litemod
};
Mod() = default;
Mod(const QFileInfo &file);
explicit Mod(const QDir& mods_dir, const Metadata::ModStruct& metadata);
QFileInfo filename() const
{
return m_file;
}
QString mmc_id() const
{
return m_mmc_id;
}
ModType type() const
{
return m_type;
}
bool valid()
{
return m_type != MOD_UNKNOWN;
}
auto fileinfo() const -> QFileInfo { return m_file; }
auto dateTimeChanged() const -> QDateTime { return m_changedDateTime; }
auto internal_id() const -> QString { return m_internal_id; }
auto type() const -> ModType { return m_type; }
auto enabled() const -> bool { return m_enabled; }
QDateTime dateTimeChanged() const
{
return m_changedDateTime;
}
auto valid() const -> bool { return m_type != MOD_UNKNOWN; }
bool enabled() const
{
return m_enabled;
}
auto details() const -> const ModDetails&;
auto name() const -> QString;
auto version() const -> QString;
auto homeurl() const -> QString;
auto description() const -> QString;
auto authors() const -> QStringList;
auto status() const -> ModStatus;
const ModDetails &details() const;
auto metadata() -> std::shared_ptr<Metadata::ModStruct>;
auto metadata() const -> const std::shared_ptr<Metadata::ModStruct>;
QString name() const;
QString version() const;
QString homeurl() const;
QString description() const;
QStringList authors() const;
void setStatus(ModStatus status);
void setMetadata(Metadata::ModStruct* metadata);
bool enable(bool value);
auto enable(bool value) -> bool;
// delete all the files of this mod
bool destroy();
auto destroy(QDir& index_dir) -> bool;
// change the mod's filesystem path (used by mod lists for *MAGIC* purposes)
void repath(const QFileInfo &file);
bool shouldResolve() {
return !m_resolving && !m_resolved;
}
bool isResolving() {
return m_resolving;
}
int resolutionTicket()
{
return m_resolutionTicket;
}
auto shouldResolve() const -> bool { return !m_resolving && !m_resolved; }
auto isResolving() const -> bool { return m_resolving; }
auto resolutionTicket() const -> int { return m_resolutionTicket; }
void setResolving(bool resolving, int resolutionTicket) {
m_resolving = resolving;
m_resolutionTicket = resolutionTicket;
}
void finishResolvingWithDetails(std::shared_ptr<ModDetails> details){
m_resolving = false;
m_resolved = true;
m_localDetails = details;
}
void finishResolvingWithDetails(std::shared_ptr<ModDetails> details);
protected:
QFileInfo m_file;
QDateTime m_changedDateTime;
QString m_mmc_id;
QString m_internal_id;
/* Name as reported via the file name */
QString m_name;
ModType m_type = MOD_UNKNOWN;
/* If the mod has metadata, this will be filled in the constructor, and passed to
* the ModDetails when calling finishResolvingWithDetails */
std::shared_ptr<Metadata::ModStruct> m_temp_metadata;
/* Set the mod status while it doesn't have local details just yet */
ModStatus m_temp_status = ModStatus::NotInstalled;
std::shared_ptr<ModDetails> m_localDetails;
bool m_enabled = true;
bool m_resolving = false;
bool m_resolved = false;
int m_resolutionTicket = 0;
ModType m_type = MOD_UNKNOWN;
std::shared_ptr<ModDetails> m_localDetails;
};

View File

@ -1,17 +1,79 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
*
* 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 <memory>
#include <QString>
#include <QStringList>
#include "minecraft/mod/MetadataHandler.h"
enum class ModStatus {
Installed, // Both JAR and Metadata are present
NotInstalled, // Only the Metadata is present
NoMetadata, // Only the JAR is present
};
struct ModDetails
{
/* Mod ID as defined in the ModLoader-specific metadata */
QString mod_id;
/* Human-readable name */
QString name;
/* Human-readable mod version */
QString version;
/* Human-readable minecraft version */
QString mcversion;
/* URL for mod's home page */
QString homeurl;
QString updateurl;
/* Human-readable description */
QString description;
/* List of the author's names */
QStringList authors;
QString credits;
/* Installation status of the mod */
ModStatus status;
/* Metadata information, if any */
std::shared_ptr<Metadata::ModStruct> metadata;
};

View File

@ -1,18 +0,0 @@
#include "ModFolderLoadTask.h"
#include <QDebug>
ModFolderLoadTask::ModFolderLoadTask(QDir dir) :
m_dir(dir), m_result(new Result())
{
}
void ModFolderLoadTask::run()
{
m_dir.refresh();
for (auto entry : m_dir.entryInfoList())
{
Mod m(entry);
m_result->mods[m.mmc_id()] = m;
}
emit succeeded();
}

View File

@ -1,29 +0,0 @@
#pragma once
#include <QRunnable>
#include <QObject>
#include <QDir>
#include <QMap>
#include "Mod.h"
#include <memory>
class ModFolderLoadTask : public QObject, public QRunnable
{
Q_OBJECT
public:
struct Result {
QMap<QString, Mod> mods;
};
using ResultPtr = std::shared_ptr<Result>;
ResultPtr result() const {
return m_result;
}
public:
ModFolderLoadTask(QDir dir);
void run();
signals:
void succeeded();
private:
QDir m_dir;
ResultPtr m_result;
};

View File

@ -1,32 +1,55 @@
/* 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.
*/
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
* 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 "ModFolderModel.h"
#include <FileSystem.h>
#include <QDebug>
#include <QFileSystemWatcher>
#include <QMimeData>
#include <QString>
#include <QThreadPool>
#include <QUrl>
#include <QUuid>
#include <QString>
#include <QFileSystemWatcher>
#include <QDebug>
#include "ModFolderLoadTask.h"
#include <QThreadPool>
#include <algorithm>
#include "LocalModParseTask.h"
ModFolderModel::ModFolderModel(const QString &dir) : QAbstractListModel(), m_dir(dir)
#include "minecraft/mod/tasks/LocalModParseTask.h"
#include "minecraft/mod/tasks/ModFolderLoadTask.h"
ModFolderModel::ModFolderModel(const QString &dir, bool is_indexed) : QAbstractListModel(), m_dir(dir), m_is_indexed(is_indexed)
{
FS::ensureFolderPathExists(m_dir.absolutePath());
m_dir.setFilter(QDir::Readable | QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
@ -79,19 +102,31 @@ bool ModFolderModel::update()
return true;
}
auto task = new ModFolderLoadTask(m_dir);
auto index_dir = indexDir();
auto task = new ModFolderLoadTask(dir(), index_dir, m_is_indexed);
m_update = task->result();
QThreadPool *threadPool = QThreadPool::globalInstance();
connect(task, &ModFolderLoadTask::succeeded, this, &ModFolderModel::finishUpdate);
threadPool->start(task);
return true;
}
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
{
@ -140,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
@ -153,7 +192,7 @@ void ModFolderModel::finishUpdate()
modsIndex.clear();
int idx = 0;
for(auto & mod: mods) {
modsIndex[mod.mmc_id()] = idx;
modsIndex[mod.internal_id()] = idx;
idx++;
}
}
@ -174,9 +213,9 @@ void ModFolderModel::resolveMod(Mod& m)
return;
}
auto task = new LocalModParseTask(nextResolutionTicket, m.type(), m.filename());
auto task = new LocalModParseTask(nextResolutionTicket, m.type(), m.fileinfo());
auto result = task->result();
result->id = m.mmc_id();
result->id = m.internal_id();
activeTickets.insert(nextResolutionTicket, result);
m.setResolving(true, nextResolutionTicket);
nextResolutionTicket++;
@ -278,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;
}
@ -296,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;
}
@ -333,8 +374,12 @@ bool ModFolderModel::deleteMods(const QModelIndexList& indexes)
for (auto i: indexes)
{
if(i.column() != 0) {
continue;
}
Mod &m = mods[i.row()];
m.destroy();
auto index_dir = indexDir();
m.destroy(index_dir);
}
return true;
}
@ -381,7 +426,7 @@ QVariant ModFolderModel::data(const QModelIndex &index, int role) const
}
case Qt::ToolTipRole:
return mods[row].mmc_id();
return mods[row].internal_id();
case Qt::CheckStateRole:
switch (column)
@ -436,11 +481,11 @@ bool ModFolderModel::setModStatus(int row, ModFolderModel::ModStatusAction actio
}
// preserve the row, but change its ID
auto oldId = mod.mmc_id();
auto oldId = mod.internal_id();
if(!mod.enable(!mod.enabled())) {
return false;
}
auto newId = mod.mmc_id();
auto newId = mod.internal_id();
if(modsIndex.contains(newId)) {
// NOTE: this could handle a corner case, where we are overwriting a file, because the same 'mod' exists both enabled and disabled
// But is it necessary?

View File

@ -1,17 +1,38 @@
/* 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.
*/
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
* 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
@ -24,8 +45,8 @@
#include "Mod.h"
#include "ModFolderLoadTask.h"
#include "LocalModParseTask.h"
#include "minecraft/mod/tasks/ModFolderLoadTask.h"
#include "minecraft/mod/tasks/LocalModParseTask.h"
class LegacyInstance;
class BaseInstance;
@ -52,7 +73,7 @@ public:
Enable,
Toggle
};
ModFolderModel(const QString &dir);
ModFolderModel(const QString &dir, bool is_indexed = false);
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
@ -108,11 +129,16 @@ public:
bool isValid();
QDir dir()
QDir& dir()
{
return m_dir;
}
QDir indexDir()
{
return { QString("%1/.index").arg(dir().absolutePath()) };
}
const QList<Mod> & allMods()
{
return mods;
@ -141,6 +167,7 @@ protected:
bool scheduled_update = false;
bool interaction_disabled = false;
QDir m_dir;
bool m_is_indexed;
QMap<QString, int> modsIndex;
QMap<int, LocalModParseTask::ResultPtr> activeTickets;
int nextResolutionTicket = 0;

View File

@ -1,7 +1,40 @@
// 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 <QTest>
#include <QTemporaryDir>
#include "TestUtil.h"
#include "FileSystem.h"
#include "minecraft/mod/ModFolderModel.h"
@ -16,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('/'));
@ -32,8 +65,11 @@ slots:
{
QString folder = source;
QTemporaryDir tempDir;
ModFolderModel m(tempDir.path());
QEventLoop loop;
ModFolderModel m(tempDir.path(), true);
connect(&m, &ModFolderModel::updateFinished, &loop, &QEventLoop::quit);
m.installMod(folder);
loop.exec();
verify(tempDir.path());
}
@ -41,8 +77,11 @@ slots:
{
QString folder = source + '/';
QTemporaryDir tempDir;
ModFolderModel m(tempDir.path());
QEventLoop loop;
ModFolderModel m(tempDir.path(), true);
connect(&m, &ModFolderModel::updateFinished, &loop, &QEventLoop::quit);
m.installMod(folder);
loop.exec();
verify(tempDir.path());
}
}

View File

@ -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 "ResourcePackFolderModel.h"
ResourcePackFolderModel::ResourcePackFolderModel(const QString &dir) : ModFolderModel(dir) {

View File

@ -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 "TexturePackFolderModel.h"
TexturePackFolderModel::TexturePackFolderModel(const QString &dir) : ModFolderModel(dir) {

View File

@ -35,7 +35,6 @@ std::shared_ptr<ModDetails> ReadMCModInfo(QByteArray contents)
details->name = name;
}
details->version = firstObj.value("version").toString();
details->updateurl = firstObj.value("updateUrl").toString();
auto homeurl = firstObj.value("url").toString().trimmed();
if(!homeurl.isEmpty())
{
@ -57,7 +56,6 @@ std::shared_ptr<ModDetails> ReadMCModInfo(QByteArray contents)
{
details->authors.append(author.toString());
}
details->credits = firstObj.value("credits").toString();
return details;
};
QJsonParseError jsonError;
@ -168,27 +166,9 @@ std::shared_ptr<ModDetails> ReadMCModTOML(QByteArray contents)
}
if(!authors.isEmpty())
{
// author information is stored as a string now, not a list
details->authors.append(authors);
}
// is credits even used anywhere? including this for completion/parity with old data version
toml_datum_t creditsDatum = toml_string_in(tomlData, "credits");
QString credits = "";
if(creditsDatum.ok)
{
authors = creditsDatum.u.s;
free(creditsDatum.u.s);
}
else
{
creditsDatum = toml_string_in(tomlModsTable0, "credits");
if(creditsDatum.ok)
{
credits = creditsDatum.u.s;
free(creditsDatum.u.s);
}
}
details->credits = credits;
toml_datum_t homeurlDatum = toml_string_in(tomlData, "displayURL");
QString homeurl = "";
if(homeurlDatum.ok)

View File

@ -1,9 +1,11 @@
#pragma once
#include <QRunnable>
#include <QDebug>
#include <QObject>
#include "Mod.h"
#include "ModDetails.h"
#include <QRunnable>
#include "minecraft/mod/Mod.h"
#include "minecraft/mod/ModDetails.h"
class LocalModParseTask : public QObject, public QRunnable
{

View File

@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
* 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/>.
*/
#include "LocalModUpdateTask.h"
#include "Application.h"
#include "FileSystem.h"
#include "minecraft/mod/MetadataHandler.h"
#ifdef Q_OS_WIN32
#include <windows.h>
#endif
LocalModUpdateTask::LocalModUpdateTask(QDir index_dir, ModPlatform::IndexedPack& mod, ModPlatform::IndexedVersion& mod_version)
: m_index_dir(index_dir), m_mod(mod), m_mod_version(mod_version)
{
// Ensure a '.index' folder exists in the mods folder, and create it if it does not
if (!FS::ensureFolderPathExists(index_dir.path())) {
emitFailed(QString("Unable to create index for mod %1!").arg(m_mod.name));
}
#ifdef Q_OS_WIN32
SetFileAttributesA(index_dir.path().toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
#endif
}
void LocalModUpdateTask::executeTask()
{
setStatus(tr("Updating index for mod:\n%1").arg(m_mod.name));
auto pw_mod = Metadata::create(m_index_dir, m_mod, m_mod_version);
Metadata::update(m_index_dir, pw_mod);
emitSucceeded();
}
auto LocalModUpdateTask::abort() -> bool
{
emitAborted();
return true;
}

View File

@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
*
* 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 <QDir>
#include "modplatform/ModIndex.h"
#include "tasks/Task.h"
class LocalModUpdateTask : public Task {
Q_OBJECT
public:
using Ptr = shared_qobject_ptr<LocalModUpdateTask>;
explicit LocalModUpdateTask(QDir index_dir, ModPlatform::IndexedPack& mod, ModPlatform::IndexedVersion& mod_version);
auto canAbort() const -> bool override { return true; }
auto abort() -> bool override;
protected slots:
//! Entry point for tasks.
void executeTask() override;
private:
QDir m_index_dir;
ModPlatform::IndexedPack& m_mod;
ModPlatform::IndexedVersion& m_mod_version;
};

View File

@ -0,0 +1,104 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
* 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 "ModFolderLoadTask.h"
#include "Application.h"
#include "minecraft/mod/MetadataHandler.h"
ModFolderLoadTask::ModFolderLoadTask(QDir& mods_dir, QDir& index_dir, bool is_indexed)
: m_mods_dir(mods_dir), m_index_dir(index_dir), m_is_indexed(is_indexed), m_result(new Result())
{}
void ModFolderLoadTask::run()
{
if (m_is_indexed) {
// Read metadata first
getFromMetadata();
}
// Read JAR files that don't have metadata
m_mods_dir.refresh();
for (auto entry : m_mods_dir.entryInfoList()) {
Mod mod(entry);
if (mod.enabled()) {
if (m_result->mods.contains(mod.internal_id())) {
m_result->mods[mod.internal_id()].setStatus(ModStatus::Installed);
}
else {
m_result->mods[mod.internal_id()] = mod;
m_result->mods[mod.internal_id()].setStatus(ModStatus::NoMetadata);
}
}
else {
QString chopped_id = mod.internal_id().chopped(9);
if (m_result->mods.contains(chopped_id)) {
m_result->mods[mod.internal_id()] = mod;
auto metadata = m_result->mods[chopped_id].metadata();
if (metadata) {
mod.setMetadata(new Metadata::ModStruct(*metadata));
m_result->mods[mod.internal_id()].setStatus(ModStatus::Installed);
m_result->mods.remove(chopped_id);
}
}
else {
m_result->mods[mod.internal_id()] = mod;
m_result->mods[mod.internal_id()].setStatus(ModStatus::NoMetadata);
}
}
}
emit succeeded();
}
void ModFolderLoadTask::getFromMetadata()
{
m_index_dir.refresh();
for (auto entry : m_index_dir.entryList(QDir::Files)) {
auto metadata = Metadata::get(m_index_dir, entry);
if(!metadata.isValid()){
return;
}
Mod mod(m_mods_dir, metadata);
mod.setStatus(ModStatus::NotInstalled);
m_result->mods[mod.internal_id()] = mod;
}
}

View File

@ -0,0 +1,71 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
* 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 <QDir>
#include <QMap>
#include <QObject>
#include <QRunnable>
#include <memory>
#include "minecraft/mod/Mod.h"
class ModFolderLoadTask : public QObject, public QRunnable
{
Q_OBJECT
public:
struct Result {
QMap<QString, Mod> mods;
};
using ResultPtr = std::shared_ptr<Result>;
ResultPtr result() const {
return m_result;
}
public:
ModFolderLoadTask(QDir& mods_dir, QDir& index_dir, bool is_indexed);
void run();
signals:
void succeeded();
private:
void getFromMetadata();
private:
QDir& m_mods_dir, m_index_dir;
bool m_is_indexed;
ResultPtr m_result;
};

View File

@ -0,0 +1,6 @@
{
"pack": {
"pack_format": 1,
"description": "Some resource pack maybe"
}
}

View File

@ -0,0 +1 @@

View File

@ -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()));
}

View File

@ -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()));
}

View File

@ -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()));
}

Some files were not shown because too many files have changed in this diff Show More