diff options
40 files changed, 442 insertions, 272 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 62724323..6cb806a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,12 +79,12 @@ set(Launcher_NEWS_OPEN_URL "https://polymc.org/news" CACHE STRING "URL that gets set(Launcher_HELP_URL "https://polymc.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help") ######## Set version numbers ######## -set(Launcher_VERSION_MAJOR 1) -set(Launcher_VERSION_MINOR 4) -set(Launcher_VERSION_HOTFIX 0) +set(Launcher_VERSION_MAJOR 5) +set(Launcher_VERSION_MINOR 0) -# Build number -set(Launcher_VERSION_BUILD -1 CACHE STRING "Build number. -1 for no build number.") +set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}") +set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.0.0") +set(Launcher_VERSION_NAME4_COMMA "${Launcher_VERSION_MAJOR},${Launcher_VERSION_MINOR},0,0") # Build platform. set(Launcher_BUILD_PLATFORM "" CACHE STRING "A short string identifying the platform that this build was built for. Only used to display in the about dialog.") @@ -143,15 +143,8 @@ message(STATUS "Git commit: ${Launcher_GIT_COMMIT}") message(STATUS "Git tag: ${Launcher_GIT_TAG}") message(STATUS "Git refspec: ${Launcher_GIT_REFSPEC}") -set(Launcher_RELEASE_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}") -set(Launcher_RELEASE_VERSION_NAME4 "${Launcher_RELEASE_VERSION_NAME}.0") -set(Launcher_RELEASE_VERSION_NAME4_COMMA "${Launcher_VERSION_MAJOR},${Launcher_VERSION_MINOR},${Launcher_VERSION_HOTFIX},0") string(TIMESTAMP TODAY "%Y-%m-%d") -set(Launcher_RELEASE_TIMESTAMP "${TODAY}") - -#### Custom target to just print the version. -add_custom_target(version echo "Version: ${Launcher_RELEASE_VERSION_NAME}") -add_custom_target(tcversion echo "\\#\\#teamcity[setParameter name=\\'env.LAUNCHER_VERSION\\' value=\\'${Launcher_RELEASE_VERSION_NAME}\\']") +set(Launcher_BUILD_TIMESTAMP "${TODAY}") ################################ 3rd Party Libs ################################ @@ -226,9 +219,9 @@ if(UNIX AND APPLE) set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_Name}") set(MACOSX_BUNDLE_INFO_STRING "${Launcher_Name}: A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.") set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.polymc.${Launcher_Name}") - set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}") - set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}") - set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}") + set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_NAME}") + set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}") + set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}") set(MACOSX_BUNDLE_ICON_FILE ${Launcher_Name}.icns) set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2021-2022 ${Launcher_Copyright}") set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "idALcUIazingvKSSsEa9U7coDVxZVx/ORpOEE/QtJfg=") diff --git a/buildconfig/BuildConfig.cpp.in b/buildconfig/BuildConfig.cpp.in index 7da66f36..50e5e8a4 100644 --- a/buildconfig/BuildConfig.cpp.in +++ b/buildconfig/BuildConfig.cpp.in @@ -55,10 +55,9 @@ Config::Config() // Version information VERSION_MAJOR = @Launcher_VERSION_MAJOR@; VERSION_MINOR = @Launcher_VERSION_MINOR@; - VERSION_HOTFIX = @Launcher_VERSION_HOTFIX@; - VERSION_BUILD = @Launcher_VERSION_BUILD@; BUILD_PLATFORM = "@Launcher_BUILD_PLATFORM@"; + BUILD_DATE = "@Launcher_BUILD_TIMESTAMP@"; UPDATER_BASE = "@Launcher_UPDATER_BASE@"; MAC_SPARKLE_PUB_KEY = "@MACOSX_SPARKLE_UPDATE_PUBLIC_KEY@"; @@ -85,7 +84,7 @@ Config::Config() { VERSION_CHANNEL = GIT_REFSPEC; VERSION_CHANNEL.remove("refs/heads/"); - if(!UPDATER_BASE.isEmpty() && !BUILD_PLATFORM.isEmpty() && VERSION_BUILD >= 0) { + if(!UPDATER_BASE.isEmpty() && !BUILD_PLATFORM.isEmpty()) { UPDATER_ENABLED = true; } } @@ -98,7 +97,6 @@ Config::Config() VERSION_CHANNEL = "unknown"; } - VERSION_STR = "@Launcher_VERSION_STRING@"; NEWS_RSS_URL = "@Launcher_NEWS_RSS_URL@"; NEWS_OPEN_URL = "@Launcher_NEWS_OPEN_URL@"; HELP_URL = "@Launcher_HELP_URL@"; @@ -116,7 +114,7 @@ Config::Config() QString Config::versionString() const { - return QString("%1.%2.%3").arg(VERSION_MAJOR).arg(VERSION_MINOR).arg(VERSION_HOTFIX); + return QString("%1.%2").arg(VERSION_MAJOR).arg(VERSION_MINOR); } QString Config::printableVersionString() const @@ -128,11 +126,5 @@ QString Config::printableVersionString() const { vstr += "-" + VERSION_CHANNEL; } - - // if a build number is set, also add it to the end - if(VERSION_BUILD >= 0) - { - vstr += "+build." + QString::number(VERSION_BUILD); - } return vstr; } diff --git a/buildconfig/BuildConfig.h b/buildconfig/BuildConfig.h index 95786d82..de66cec4 100644 --- a/buildconfig/BuildConfig.h +++ b/buildconfig/BuildConfig.h @@ -55,10 +55,6 @@ class Config { int VERSION_MAJOR; /// The minor version number. int VERSION_MINOR; - /// The hotfix number. - int VERSION_HOTFIX; - /// The build number. - int VERSION_BUILD; /** * The version channel @@ -71,6 +67,9 @@ class Config { /// A short string identifying this build's platform. For example, "lin64" or "win32". QString BUILD_PLATFORM; + /// A string containing the build timestamp + QString BUILD_DATE; + /// URL for the updater's channel QString UPDATER_BASE; @@ -95,9 +94,6 @@ class Config { /// The git refspec of this build QString GIT_REFSPEC; - /// This is printed on start to standard output - QString VERSION_STR; - /** * This is used to fetch the news RSS feed. * It defaults in CMakeLists.txt to "https://multimc.org/rss.xml" diff --git a/launcher/Application.cpp b/launcher/Application.cpp index cb8088be..553b3229 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -774,7 +774,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) auto platform = getIdealPlatform(BuildConfig.BUILD_PLATFORM); auto channelUrl = BuildConfig.UPDATER_BASE + platform + "/channels.json"; qDebug() << "Initializing updater with platform: " << platform << " -- " << channelUrl; - m_updateChecker.reset(new UpdateChecker(m_network, channelUrl, BuildConfig.VERSION_CHANNEL, BuildConfig.VERSION_BUILD)); + m_updateChecker.reset(new UpdateChecker(m_network, channelUrl, BuildConfig.VERSION_CHANNEL)); qDebug() << "<> Updater started."; } diff --git a/launcher/BaseInstance.cpp b/launcher/BaseInstance.cpp index 5a84a931..e6d4d8e3 100644 --- a/launcher/BaseInstance.cpp +++ b/launcher/BaseInstance.cpp @@ -53,15 +53,22 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s : QObject() { m_settings = settings; + m_global_settings = globalSettings; m_rootDir = rootDir; m_settings->registerSetting("name", "Unnamed Instance"); m_settings->registerSetting("iconKey", "default"); m_settings->registerSetting("notes", ""); + m_settings->registerSetting("lastLaunchTime", 0); m_settings->registerSetting("totalTimePlayed", 0); m_settings->registerSetting("lastTimePlayed", 0); + // Game time override + auto gameTimeOverride = m_settings->registerSetting("OverrideGameTime", false); + m_settings->registerOverride(globalSettings->getSetting("ShowGameTime"), gameTimeOverride); + m_settings->registerOverride(globalSettings->getSetting("RecordGameTime"), gameTimeOverride); + // NOTE: Sometimees InstanceType is already registered, as it was used to identify the type of // a locally stored instance if (!m_settings->getSetting("InstanceType")) @@ -149,7 +156,7 @@ void BaseInstance::setManagedPack(const QString& type, const QString& id, const int BaseInstance::getConsoleMaxLines() const { - auto lineSetting = settings()->getSetting("ConsoleMaxLines"); + auto lineSetting = m_settings->getSetting("ConsoleMaxLines"); bool conversionOk = false; int maxLines = lineSetting->get().toInt(&conversionOk); if(!conversionOk) @@ -162,7 +169,7 @@ int BaseInstance::getConsoleMaxLines() const bool BaseInstance::shouldStopOnConsoleOverflow() const { - return settings()->get("ConsoleOverflowStop").toBool(); + return m_settings->get("ConsoleOverflowStop").toBool(); } void BaseInstance::iconUpdated(QString key) @@ -237,7 +244,7 @@ void BaseInstance::setRunning(bool running) int64_t BaseInstance::totalTimePlayed() const { - qint64 current = settings()->get("totalTimePlayed").toLongLong(); + qint64 current = m_settings->get("totalTimePlayed").toLongLong(); if(m_isRunning) { QDateTime timeNow = QDateTime::currentDateTime(); @@ -253,7 +260,7 @@ int64_t BaseInstance::lastTimePlayed() const QDateTime timeNow = QDateTime::currentDateTime(); return m_timeStarted.secsTo(timeNow); } - return settings()->get("lastTimePlayed").toLongLong(); + return m_settings->get("lastTimePlayed").toLongLong(); } void BaseInstance::resetTimePlayed() @@ -272,8 +279,10 @@ QString BaseInstance::instanceRoot() const return m_rootDir; } -SettingsObjectPtr BaseInstance::settings() const +SettingsObjectPtr BaseInstance::settings() { + loadSpecificSettings(); + return m_settings; } @@ -340,7 +349,7 @@ QString BaseInstance::windowTitle() const } // FIXME: why is this here? move it to MinecraftInstance!!! -QStringList BaseInstance::extraArguments() const +QStringList BaseInstance::extraArguments() { return Commandline::splitArgs(settings()->get("JvmArgs").toString()); } diff --git a/launcher/BaseInstance.h b/launcher/BaseInstance.h index 2a94dcc6..3af104e9 100644 --- a/launcher/BaseInstance.h +++ b/launcher/BaseInstance.h @@ -154,7 +154,7 @@ public: return level; }; - virtual QStringList extraArguments() const; + virtual QStringList extraArguments(); /// Traits. Normally inside the version, depends on instance implementation. virtual QSet <QString> traits() const = 0; @@ -170,9 +170,18 @@ public: /*! * \brief Gets this instance's settings object. * This settings object stores instance-specific settings. + * + * Note that this method is not const. + * It may call loadSpecificSettings() to ensure those are loaded. + * * \return A pointer to this instance's settings object. */ - virtual SettingsObjectPtr settings() const; + virtual SettingsObjectPtr settings(); + + /*! + * \brief Loads settings specific to an instance type if they're not already loaded. + */ + virtual void loadSpecificSettings() = 0; /// returns a valid update task virtual Task::Ptr createUpdateTask(Net::Mode mode) = 0; @@ -206,7 +215,7 @@ public: virtual QString instanceConfigFolder() const = 0; /// get variables this instance exports - virtual QMap<QString, QString> getVariables() const = 0; + virtual QMap<QString, QString> getVariables() = 0; virtual QString typeName() const = 0; @@ -268,6 +277,11 @@ public: protected: void changeStatus(Status newStatus); + SettingsObjectPtr globalSettings() const { return m_global_settings.lock(); }; + + bool isSpecificSettingsLoaded() const { return m_specific_settings_loaded; } + void setSpecificSettingsLoaded(bool loaded) { m_specific_settings_loaded = loaded; } + signals: /*! * \brief Signal emitted when properties relevant to the instance view change @@ -296,6 +310,10 @@ private: /* data */ bool m_crashed = false; bool m_hasUpdate = false; bool m_hasBrokenVersion = false; + + SettingsObjectWeakPtr m_global_settings; + bool m_specific_settings_loaded = false; + }; Q_DECLARE_METATYPE(shared_qobject_ptr<BaseInstance>) diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 4ce033f9..cff07b4b 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -851,6 +851,8 @@ SET(LAUNCHER_SOURCES ui/dialogs/ModDownloadDialog.h ui/dialogs/ScrollMessageBox.cpp ui/dialogs/ScrollMessageBox.h + ui/dialogs/BlockedModsDialog.cpp + ui/dialogs/BlockedModsDialog.h ui/dialogs/ChooseProviderDialog.h ui/dialogs/ChooseProviderDialog.cpp ui/dialogs/ModUpdateDialog.cpp @@ -960,6 +962,7 @@ qt_wrap_ui(LAUNCHER_UI ui/dialogs/EditAccountDialog.ui ui/dialogs/ReviewMessageBox.ui ui/dialogs/ScrollMessageBox.ui + ui/dialogs/BlockedModsDialog.ui ui/dialogs/ChooseProviderDialog.ui ) diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp index 14e1cd47..de0afc96 100644 --- a/launcher/InstanceImportTask.cpp +++ b/launcher/InstanceImportTask.cpp @@ -60,7 +60,7 @@ #include "net/ChecksumValidator.h" #include "ui/dialogs/CustomMessageBox.h" -#include "ui/dialogs/ScrollMessageBox.h" +#include "ui/dialogs/BlockedModsDialog.h" #include <algorithm> @@ -396,21 +396,24 @@ void InstanceImportTask::processFlame() auto results = m_modIdResolver->getResults(); //first check for blocked mods QString text; + QList<QUrl> urls; 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); + urls.append(QUrl(result.websiteUrl)); anyBlocked = true; } } if(anyBlocked) { qWarning() << "Blocked mods found, displaying mod list"; - auto message_dialog = new ScrollMessageBox(m_parent, + auto message_dialog = new BlockedModsDialog(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); + text, + urls); message_dialog->setModal(true); if (message_dialog->exec()) { diff --git a/launcher/NullInstance.h b/launcher/NullInstance.h index 9b0a9331..53e64a05 100644 --- a/launcher/NullInstance.h +++ b/launcher/NullInstance.h @@ -15,6 +15,10 @@ public: void saveNow() override { } + void loadSpecificSettings() override + { + setSpecificSettingsLoaded(true); + } QString getStatusbarDescription() override { return tr("Unknown instance type"); @@ -43,7 +47,7 @@ public: { return QProcessEnvironment(); } - QMap<QString, QString> getVariables() const override + QMap<QString, QString> getVariables() override { return QMap<QString, QString>(); } diff --git a/launcher/QObjectPtr.h b/launcher/QObjectPtr.h index 173dc5e7..b1ef1c8d 100644 --- a/launcher/QObjectPtr.h +++ b/launcher/QObjectPtr.h @@ -1,91 +1,37 @@ #pragma once +#include <QObject> +#include <QSharedPointer> + #include <functional> #include <memory> -#include <QObject> -namespace details -{ -struct DeleteQObjectLater -{ - void operator()(QObject *obj) const - { - obj->deleteLater(); - } -}; -} /** * A unique pointer class with unique pointer semantics intended for derivates of QObject * Calls deleteLater() instead of destroying the contained object immediately */ -template<typename T> using unique_qobject_ptr = std::unique_ptr<T, details::DeleteQObjectLater>; +template <typename T> +using unique_qobject_ptr = QScopedPointer<T, QScopedPointerDeleteLater>; /** * A shared pointer class with shared pointer semantics intended for derivates of QObject * Calls deleteLater() instead of destroying the contained object immediately */ template <typename T> -class shared_qobject_ptr -{ -public: - shared_qobject_ptr(){} - shared_qobject_ptr(T * wrap) - { - reset(wrap); - } - shared_qobject_ptr(const shared_qobject_ptr<T>& other) - { - m_ptr = other.m_ptr; - } - template<typename Derived> - shared_qobject_ptr(const shared_qobject_ptr<Derived> &other) - { - m_ptr = other.unwrap(); - } +class shared_qobject_ptr : public QSharedPointer<T> { + public: + constexpr shared_qobject_ptr() : QSharedPointer<T>() {} + constexpr shared_qobject_ptr(T* ptr) : QSharedPointer<T>(ptr, &QObject::deleteLater) {} + constexpr shared_qobject_ptr(std::nullptr_t null_ptr) : QSharedPointer<T>(null_ptr, &QObject::deleteLater) {} -public: - void reset(T * wrap) - { - using namespace std::placeholders; - m_ptr.reset(wrap, std::bind(&QObject::deleteLater, _1)); - } - void reset(const shared_qobject_ptr<T> &other) - { - m_ptr = other.m_ptr; - } - void reset() - { - m_ptr.reset(); - } - T * get() const - { - return m_ptr.get(); - } - T * operator->() const - { - return m_ptr.get(); - } - T & operator*() const - { - return *m_ptr.get(); - } - operator bool() const - { - return m_ptr.get() != nullptr; - } - const std::shared_ptr <T> unwrap() const + template <typename Derived> + constexpr shared_qobject_ptr(const shared_qobject_ptr<Derived>& other) : QSharedPointer<T>(other) + {} + + void reset() { QSharedPointer<T>::reset(); } + void reset(const shared_qobject_ptr<T>& other) { - return m_ptr; + shared_qobject_ptr<T> t(other); + this->swap(t); } - template<typename U> - bool operator==(const shared_qobject_ptr<U>& other) const { - return m_ptr == other.m_ptr; - } - template<typename U> - bool operator!=(const shared_qobject_ptr<U>& other) const { - return m_ptr != other.m_ptr; - } - -private: - std::shared_ptr <T> m_ptr; }; diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 5a6f8de0..c677b677 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -115,6 +115,19 @@ private: MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir) : BaseInstance(globalSettings, settings, rootDir) { + m_components.reset(new PackProfile(this)); +} + +void MinecraftInstance::saveNow() +{ + m_components->saveNow(); +} + +void MinecraftInstance::loadSpecificSettings() +{ + if (isSpecificSettingsLoaded()) + return; + // Java Settings auto javaOverride = m_settings->registerSetting("OverrideJava", false); auto locationOverride = m_settings->registerSetting("OverrideJavaLocation", false); @@ -124,64 +137,58 @@ MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsO auto javaOrLocation = std::make_shared<OrSetting>("JavaOrLocationOverride", javaOverride, locationOverride); auto javaOrArgs = std::make_shared<OrSetting>("JavaOrArgsOverride", javaOverride, argsOverride); - m_settings->registerOverride(globalSettings->getSetting("JavaPath"), javaOrLocation); - m_settings->registerOverride(globalSettings->getSetting("JvmArgs"), javaOrArgs); - m_settings->registerOverride(globalSettings->getSetting("IgnoreJavaCompatibility"), javaOrLocation); - - // special! - m_settings->registerPassthrough(globalSettings->getSetting("JavaTimestamp"), javaOrLocation); - m_settings->registerPassthrough(globalSettings->getSetting("JavaVersion"), javaOrLocation); - m_settings->registerPassthrough(globalSettings->getSetting("JavaArchitecture"), javaOrLocation); - - // Window Size - auto windowSetting = m_settings->registerSetting("OverrideWindow", false); - m_settings->registerOverride(globalSettings->getSetting("LaunchMaximized"), windowSetting); - m_settings->registerOverride(globalSettings->getSetting("MinecraftWinWidth"), windowSetting); - m_settings->registerOverride(globalSettings->getSetting("MinecraftWinHeight"), windowSetting); - - // Memory - auto memorySetting = m_settings->registerSetting("OverrideMemory", false); - m_settings->registerOverride(globalSettings->getSetting("MinMemAlloc"), memorySetting); - m_settings->registerOverride(globalSettings->getSetting("MaxMemAlloc"), memorySetting); - m_settings->registerOverride(globalSettings->getSetting("PermGen"), memorySetting); - - // Minecraft launch method - auto launchMethodOverride = m_settings->registerSetting("OverrideMCLaunchMethod", false); - m_settings->registerOverride(globalSettings->getSetting("MCLaunchMethod"), launchMethodOverride); - - // Native library workarounds - auto nativeLibraryWorkaroundsOverride = m_settings->registerSetting("OverrideNativeWorkarounds", false); - m_settings->registerOverride(globalSettings->getSetting("UseNativeOpenAL"), nativeLibraryWorkaroundsOverride); - m_settings->registerOverride(globalSettings->getSetting("UseNativeGLFW"), nativeLibraryWorkaroundsOverride); - - // 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); - m_settings->registerOverride(globalSettings->getSetting("RecordGameTime"), gameTimeOverride); + if (auto global_settings = globalSettings()) { + m_settings->registerOverride(global_settings->getSetting("JavaPath"), javaOrLocation); + m_settings->registerOverride(global_settings->getSetting("JvmArgs"), javaOrArgs); + m_settings->registerOverride(global_settings->getSetting("IgnoreJavaCompatibility"), javaOrLocation); + + // special! + m_settings->registerPassthrough(global_settings->getSetting("JavaTimestamp"), javaOrLocation); + m_settings->registerPassthrough(global_settings->getSetting("JavaVersion"), javaOrLocation); + m_settings->registerPassthrough(global_settings->getSetting("JavaArchitecture"), javaOrLocation); + + // Window Size + auto windowSetting = m_settings->registerSetting("OverrideWindow", false); + m_settings->registerOverride(global_settings->getSetting("LaunchMaximized"), windowSetting); + m_settings->registerOverride(global_settings->getSetting("MinecraftWinWidth"), windowSetting); + m_settings->registerOverride(global_settings->getSetting("MinecraftWinHeight"), windowSetting); + + // Memory + auto memorySetting = m_settings->registerSetting("OverrideMemory", false); + m_settings->registerOverride(global_settings->getSetting("MinMemAlloc"), memorySetting); + m_settings->registerOverride(global_settings->getSetting("MaxMemAlloc"), memorySetting); + m_settings->registerOverride(global_settings->getSetting("PermGen"), memorySetting); + + // Minecraft launch method + auto launchMethodOverride = m_settings->registerSetting("OverrideMCLaunchMethod", false); + m_settings->registerOverride(global_settings->getSetting("MCLaunchMethod"), launchMethodOverride); + + // Native library workarounds + auto nativeLibraryWorkaroundsOverride = m_settings->registerSetting("OverrideNativeWorkarounds", false); + m_settings->registerOverride(global_settings->getSetting("UseNativeOpenAL"), nativeLibraryWorkaroundsOverride); + m_settings->registerOverride(global_settings->getSetting("UseNativeGLFW"), nativeLibraryWorkaroundsOverride); + + // Peformance related options + auto performanceOverride = m_settings->registerSetting("OverridePerformance", false); + m_settings->registerOverride(global_settings->getSetting("EnableFeralGamemode"), performanceOverride); + m_settings->registerOverride(global_settings->getSetting("EnableMangoHud"), performanceOverride); + m_settings->registerOverride(global_settings->getSetting("UseDiscreteGpu"), performanceOverride); + + // Miscellaneous + auto miscellaneousOverride = m_settings->registerSetting("OverrideMiscellaneous", false); + m_settings->registerOverride(global_settings->getSetting("CloseAfterLaunch"), miscellaneousOverride); + m_settings->registerOverride(global_settings->getSetting("QuitAfterGameStop"), miscellaneousOverride); + + m_settings->set("InstanceType", "OneSix"); + } // Join server on launch, this does not have a global override m_settings->registerSetting("JoinServerOnLaunch", false); m_settings->registerSetting("JoinServerOnLaunchAddress", ""); - // Miscellaneous - auto miscellaneousOverride = m_settings->registerSetting("OverrideMiscellaneous", false); - m_settings->registerOverride(globalSettings->getSetting("CloseAfterLaunch"), miscellaneousOverride); - m_settings->registerOverride(globalSettings->getSetting("QuitAfterGameStop"), miscellaneousOverride); - - m_settings->set("InstanceType", "OneSix"); + qDebug() << "Instance-type specific settings were loaded!"; - m_components.reset(new PackProfile(this)); -} - -void MinecraftInstance::saveNow() -{ - m_components->saveNow(); + setSpecificSettingsLoaded(true); } QString MinecraftInstance::typeName() const @@ -308,7 +315,7 @@ QDir MinecraftInstance::versionsPath() const return QDir::current().absoluteFilePath("versions"); } -QStringList MinecraftInstance::getClassPath() const +QStringList MinecraftInstance::getClassPath() { QStringList jars, nativeJars; auto javaArchitecture = settings()->get("JavaArchitecture").toString(); @@ -323,7 +330,7 @@ QString MinecraftInstance::getMainClass() const return profile->getMainClass(); } -QStringList MinecraftInstance::getNativeJars() const +QStringList MinecraftInstance::getNativeJars() { QStringList jars, nativeJars; auto javaArchitecture = settings()->get("JavaArchitecture").toString(); @@ -332,7 +339,7 @@ QStringList MinecraftInstance::getNativeJars() const return nativeJars; } -QStringList MinecraftInstance::extraArguments() const +QStringList MinecraftInstance::extraArguments() { auto list = BaseInstance::extraArguments(); auto version = getPackProfile(); @@ -358,7 +365,7 @@ QStringList MinecraftInstance::extraArguments() const return list; } -QStringList MinecraftInstance::javaArguments() const +QStringList MinecraftInstance::javaArguments() { QStringList args; @@ -415,7 +422,7 @@ QStringList MinecraftInstance::javaArguments() const return args; } -QMap<QString, QString> MinecraftInstance::getVariables() const +QMap<QString, QString> MinecraftInstance::getVariables() { QMap<QString, QString> out; out.insert("INST_NAME", name()); @@ -943,9 +950,9 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt process->appendStep(new CreateGameFolders(pptr)); } - if (!serverToJoin && m_settings->get("JoinServerOnLaunch").toBool()) + if (!serverToJoin && settings()->get("JoinServerOnLaunch").toBool()) { - QString fullAddress = m_settings->get("JoinServerOnLaunchAddress").toString(); + QString fullAddress = settings()->get("JoinServerOnLaunchAddress").toString(); serverToJoin.reset(new MinecraftServerTarget(MinecraftServerTarget::parse(fullAddress))); } @@ -1053,10 +1060,10 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt QString MinecraftInstance::launchMethod() { - return m_settings->get("MCLaunchMethod").toString(); + return settings()->get("MCLaunchMethod").toString(); } -JavaVersion MinecraftInstance::getJavaVersion() const +JavaVersion MinecraftInstance::getJavaVersion() { return JavaVersion(settings()->get("JavaVersion").toString()); } diff --git a/launcher/minecraft/MinecraftInstance.h b/launcher/minecraft/MinecraftInstance.h index 8e1c67f2..7a75f452 100644 --- a/launcher/minecraft/MinecraftInstance.h +++ b/launcher/minecraft/MinecraftInstance.h @@ -20,6 +20,8 @@ public: virtual ~MinecraftInstance() {}; virtual void saveNow() override; + void loadSpecificSettings() override; + // FIXME: remove QString typeName() const override; // FIXME: remove @@ -79,15 +81,15 @@ public: ////// Launch stuff ////// Task::Ptr createUpdateTask(Net::Mode mode) override; shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) override; - QStringList extraArguments() const override; + QStringList extraArguments() override; QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override; QList<Mod*> getJarMods() const; QString createLaunchScript(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin); /// get arguments passed to java - QStringList javaArguments() const; + QStringList javaArguments(); /// get variables for launch command variable substitution/environment - QMap<QString, QString> getVariables() const override; + QMap<QString, QString> getVariables() override; /// create an environment for launching processes QProcessEnvironment createEnvironment() override; @@ -103,16 +105,16 @@ public: QString getStatusbarDescription() override; // FIXME: remove - virtual QStringList getClassPath() const; + virtual QStringList getClassPath(); // FIXME: remove - virtual QStringList getNativeJars() const; + virtual QStringList getNativeJars(); // FIXME: remove virtual QString getMainClass() const; // FIXME: remove virtual QStringList processMinecraftArgs(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) const; - virtual JavaVersion getJavaVersion() const; + virtual JavaVersion getJavaVersion(); protected: QMap<QString, QString> createCensorFilterFromSession(AuthSessionPtr session); diff --git a/launcher/minecraft/MinecraftUpdate.cpp b/launcher/minecraft/MinecraftUpdate.cpp index 0ce0c347..3a3aa864 100644 --- a/launcher/minecraft/MinecraftUpdate.cpp +++ b/launcher/minecraft/MinecraftUpdate.cpp @@ -43,7 +43,7 @@ void MinecraftUpdate::executeTask() m_tasks.clear(); // create folders { - m_tasks.append(std::make_shared<FoldersTask>(m_inst)); + m_tasks.append(new FoldersTask(m_inst)); } // add metadata update task if necessary @@ -53,23 +53,23 @@ void MinecraftUpdate::executeTask() auto task = components->getCurrentTask(); if(task) { - m_tasks.append(task.unwrap()); + m_tasks.append(task); } } // libraries download { - m_tasks.append(std::make_shared<LibrariesTask>(m_inst)); + m_tasks.append(new LibrariesTask(m_inst)); } // FML libraries download and copy into the instance { - m_tasks.append(std::make_shared<FMLLibrariesTask>(m_inst)); + m_tasks.append(new FMLLibrariesTask(m_inst)); } // assets update { - m_tasks.append(std::make_shared<AssetUpdateTask>(m_inst)); + m_tasks.append(new AssetUpdateTask(m_inst)); } if(!m_preFailure.isEmpty()) diff --git a/launcher/minecraft/MinecraftUpdate.h b/launcher/minecraft/MinecraftUpdate.h index acf2eb86..c9cf8624 100644 --- a/launcher/minecraft/MinecraftUpdate.h +++ b/launcher/minecraft/MinecraftUpdate.h @@ -50,7 +50,7 @@ private: private: MinecraftInstance *m_inst = nullptr; - QList<std::shared_ptr<Task>> m_tasks; + QList<Task::Ptr> m_tasks; QString m_preFailure; int m_currentTask = -1; bool m_abort = false; diff --git a/launcher/minecraft/auth/MinecraftAccount.cpp b/launcher/minecraft/auth/MinecraftAccount.cpp index a5c6f542..73d570f1 100644 --- a/launcher/minecraft/auth/MinecraftAccount.cpp +++ b/launcher/minecraft/auth/MinecraftAccount.cpp @@ -238,7 +238,7 @@ void MinecraftAccount::authFailed(QString reason) } bool MinecraftAccount::isActive() const { - return m_currentTask; + return !m_currentTask.isNull(); } bool MinecraftAccount::shouldRefresh() const { diff --git a/launcher/minecraft/mod/ModFolderModel.cpp b/launcher/minecraft/mod/ModFolderModel.cpp index 112d219e..d4c5e819 100644 --- a/launcher/minecraft/mod/ModFolderModel.cpp +++ b/launcher/minecraft/mod/ModFolderModel.cpp @@ -63,6 +63,9 @@ void ModFolderModel::startWatching() if(is_watching) return; + // Remove orphaned metadata next time + m_first_folder_load = true; + update(); // Watch the mods folder @@ -113,7 +116,8 @@ bool ModFolderModel::update() } auto index_dir = indexDir(); - auto task = new ModFolderLoadTask(dir(), index_dir, m_is_indexed); + auto task = new ModFolderLoadTask(dir(), index_dir, m_is_indexed, m_first_folder_load); + m_first_folder_load = false; m_update = task->result(); diff --git a/launcher/minecraft/mod/ModFolderModel.h b/launcher/minecraft/mod/ModFolderModel.h index a7d3ece0..3d6efac3 100644 --- a/launcher/minecraft/mod/ModFolderModel.h +++ b/launcher/minecraft/mod/ModFolderModel.h @@ -172,6 +172,7 @@ protected: bool interaction_disabled = false; QDir m_dir; bool m_is_indexed; + bool m_first_folder_load = true; QMap<QString, int> modsIndex; QMap<int, LocalModParseTask::ResultPtr> activeTickets; int nextResolutionTicket = 0; diff --git a/launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp b/launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp index 9b70e7a1..015ead80 100644 --- a/launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp +++ b/launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp @@ -38,8 +38,8 @@ #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()) +ModFolderLoadTask::ModFolderLoadTask(QDir& mods_dir, QDir& index_dir, bool is_indexed, bool clean_orphan) + : m_mods_dir(mods_dir), m_index_dir(index_dir), m_is_indexed(is_indexed), m_clean_orphan(clean_orphan), m_result(new Result()) {} void ModFolderLoadTask::run() @@ -85,12 +85,14 @@ void ModFolderLoadTask::run() // Remove orphan metadata to prevent issues // See https://github.com/PolyMC/PolyMC/issues/996 - QMutableMapIterator<QString, Mod::Ptr> iter(m_result->mods); - while (iter.hasNext()) { - auto mod = iter.next().value(); - if (mod->status() == ModStatus::NotInstalled) { - mod->destroy(m_index_dir, false); - iter.remove(); + if (m_clean_orphan) { + QMutableMapIterator<QString, Mod::Ptr> iter(m_result->mods); + while (iter.hasNext()) { + auto mod = iter.next().value(); + if (mod->status() == ModStatus::NotInstalled) { + mod->destroy(m_index_dir, false); + iter.remove(); + } } } diff --git a/launcher/minecraft/mod/tasks/ModFolderLoadTask.h b/launcher/minecraft/mod/tasks/ModFolderLoadTask.h index 0b6bb6cc..1f2015d2 100644 --- a/launcher/minecraft/mod/tasks/ModFolderLoadTask.h +++ b/launcher/minecraft/mod/tasks/ModFolderLoadTask.h @@ -56,7 +56,7 @@ public: } public: - ModFolderLoadTask(QDir& mods_dir, QDir& index_dir, bool is_indexed); + ModFolderLoadTask(QDir& mods_dir, QDir& index_dir, bool is_indexed, bool clean_orphan = false); void run(); signals: void succeeded(); @@ -67,5 +67,6 @@ private: private: QDir& m_mods_dir, m_index_dir; bool m_is_indexed; + bool m_clean_orphan; ResultPtr m_result; }; diff --git a/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp b/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp index 16013070..3c15667c 100644 --- a/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp +++ b/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp @@ -48,7 +48,7 @@ #include "Application.h" #include "BuildConfig.h" -#include "ui/dialogs/ScrollMessageBox.h" +#include "ui/dialogs/BlockedModsDialog.h" namespace ModpacksCH { @@ -173,6 +173,7 @@ void PackInstallTask::onResolveModsSucceeded() m_abortable = false; QString text; + QList<QUrl> urls; auto anyBlocked = false; Flame::Manifest results = m_mod_id_resolver_task->getResults(); @@ -190,6 +191,7 @@ void PackInstallTask::onResolveModsSucceeded() type[0] = type[0].toUpper(); text += QString("%1: %2 - <a href='%3'>%3</a><br/>").arg(type, local_file.name, results_file.websiteUrl); + urls.append(QUrl(results_file.websiteUrl)); anyBlocked = true; } else { local_file.url = results_file.url.toString(); @@ -201,10 +203,11 @@ void PackInstallTask::onResolveModsSucceeded() if (anyBlocked) { qDebug() << "Blocked files found, displaying file list"; - auto message_dialog = new ScrollMessageBox(m_parent, tr("Blocked files found"), + auto message_dialog = new BlockedModsDialog(m_parent, tr("Blocked files found"), tr("The following files are not available for download in third party launchers.<br/>" "You will need to manually download them and add them to the instance."), - text); + text, + urls); if (message_dialog->exec() == QDialog::Accepted) downloadPack(); diff --git a/launcher/settings/SettingsObject.h b/launcher/settings/SettingsObject.h index 3d61e707..6200bc3a 100644 --- a/launcher/settings/SettingsObject.h +++ b/launcher/settings/SettingsObject.h @@ -25,6 +25,7 @@ class Setting; class SettingsObject; typedef std::shared_ptr<SettingsObject> SettingsObjectPtr; +typedef std::weak_ptr<SettingsObject> SettingsObjectWeakPtr; /*! * \brief The SettingsObject handles communicating settings between the application and a diff --git a/launcher/ui/dialogs/AboutDialog.cpp b/launcher/ui/dialogs/AboutDialog.cpp index c5367d5b..743c34f1 100644 --- a/launcher/ui/dialogs/AboutDialog.cpp +++ b/launcher/ui/dialogs/AboutDialog.cpp @@ -147,10 +147,15 @@ AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDia else ui->platformLabel->setVisible(false); - if (BuildConfig.VERSION_BUILD >= 0) - ui->buildNumLabel->setText(tr("Build Number") +": " + QString::number(BuildConfig.VERSION_BUILD)); + if (!BuildConfig.GIT_COMMIT.isEmpty()) + ui->commitLabel->setText(tr("Commit: %1").arg(BuildConfig.GIT_COMMIT)); else - ui->buildNumLabel->setVisible(false); + ui->commitLabel->setVisible(false); + + if (!BuildConfig.BUILD_DATE.isEmpty()) + ui->buildDateLabel->setText(tr("Build date: %1").arg(BuildConfig.BUILD_DATE)); + else + ui->buildDateLabel->setVisible(false); if (!BuildConfig.VERSION_CHANNEL.isEmpty()) ui->channelLabel->setText(tr("Channel") +": " + BuildConfig.VERSION_CHANNEL); diff --git a/launcher/ui/dialogs/AboutDialog.ui b/launcher/ui/dialogs/AboutDialog.ui index 6323992b..6eaa0c4e 100644 --- a/launcher/ui/dialogs/AboutDialog.ui +++ b/launcher/ui/dialogs/AboutDialog.ui @@ -184,12 +184,28 @@ </widget> </item> <item> - <widget class="QLabel" name="buildNumLabel"> + <widget class="QLabel" name="buildDateLabel"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> </property> <property name="text"> - <string>Build Number:</string> + <string>Build Date:</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="textInteractionFlags"> + <set>Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="commitLabel"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>Commit:</string> </property> <property name="alignment"> <set>Qt::AlignCenter</set> diff --git a/launcher/ui/dialogs/BlockedModsDialog.cpp b/launcher/ui/dialogs/BlockedModsDialog.cpp new file mode 100644 index 00000000..fe87b517 --- /dev/null +++ b/launcher/ui/dialogs/BlockedModsDialog.cpp @@ -0,0 +1,28 @@ +#include "BlockedModsDialog.h" +#include "ui_BlockedModsDialog.h" +#include <QPushButton> +#include <QDialogButtonBox> +#include <QDesktopServices> + + +BlockedModsDialog::BlockedModsDialog(QWidget *parent, const QString &title, const QString &text, const QString &body, const QList<QUrl> &urls) : + QDialog(parent), ui(new Ui::BlockedModsDialog), urls(urls) { + ui->setupUi(this); + + auto openAllButton = ui->buttonBox->addButton(tr("Open All"), QDialogButtonBox::ActionRole); + connect(openAllButton, &QPushButton::clicked, this, &BlockedModsDialog::openAll); + + this->setWindowTitle(title); + ui->label->setText(text); + ui->textBrowser->setText(body); +} + +BlockedModsDialog::~BlockedModsDialog() { + delete ui; +} + +void BlockedModsDialog::openAll() { + for(auto &url : urls) { + QDesktopServices::openUrl(url); + } +} diff --git a/launcher/ui/dialogs/BlockedModsDialog.h b/launcher/ui/dialogs/BlockedModsDialog.h new file mode 100644 index 00000000..5f5bd61b --- /dev/null +++ b/launcher/ui/dialogs/BlockedModsDialog.h @@ -0,0 +1,22 @@ +#pragma once + +#include <QDialog> + + +QT_BEGIN_NAMESPACE +namespace Ui { class BlockedModsDialog; } +QT_END_NAMESPACE + +class BlockedModsDialog : public QDialog { +Q_OBJECT + +public: + BlockedModsDialog(QWidget *parent, const QString &title, const QString &text, const QString &body, const QList<QUrl> &urls); + + ~BlockedModsDialog() override; + +private: + Ui::BlockedModsDialog *ui; + const QList<QUrl> &urls; + void openAll(); +}; diff --git a/launcher/ui/dialogs/BlockedModsDialog.ui b/launcher/ui/dialogs/BlockedModsDialog.ui new file mode 100644 index 00000000..f4ae95b6 --- /dev/null +++ b/launcher/ui/dialogs/BlockedModsDialog.ui @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>BlockedModsDialog</class> + <widget class="QDialog" name="BlockedModsDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>455</height> + </rect> + </property> + <property name="windowTitle"> + <string notr="true">BlockedModsDialog</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string notr="true"/> + </property> + <property name="textFormat"> + <enum>Qt::RichText</enum> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QTextBrowser" name="textBrowser"> + <property name="acceptRichText"> + <bool>true</bool> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>BlockedModsDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>199</x> + <y>425</y> + </hint> + <hint type="destinationlabel"> + <x>199</x> + <y>227</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>BlockedModsDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>199</x> + <y>425</y> + </hint> + <hint type="destinationlabel"> + <x>199</x> + <y>227</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/launcher/ui/dialogs/LoginDialog.cpp b/launcher/ui/dialogs/LoginDialog.cpp index 194315a7..30394b72 100644 --- a/launcher/ui/dialogs/LoginDialog.cpp +++ b/launcher/ui/dialogs/LoginDialog.cpp @@ -115,5 +115,5 @@ MinecraftAccountPtr LoginDialog::newAccount(QWidget *parent, QString msg) { return dlg.m_account; } - return 0; + return nullptr; } diff --git a/launcher/ui/dialogs/MSALoginDialog.cpp b/launcher/ui/dialogs/MSALoginDialog.cpp index b11b6980..be49babb 100644 --- a/launcher/ui/dialogs/MSALoginDialog.cpp +++ b/launcher/ui/dialogs/MSALoginDialog.cpp @@ -169,5 +169,5 @@ MinecraftAccountPtr MSALoginDialog::newAccount(QWidget *parent, QString msg) { return dlg.m_account; } - return 0; + return nullptr; } diff --git a/launcher/ui/dialogs/OfflineLoginDialog.cpp b/launcher/ui/dialogs/OfflineLoginDialog.cpp index 4f3d8be4..a69537ab 100644 --- a/launcher/ui/dialogs/OfflineLoginDialog.cpp +++ b/launcher/ui/dialogs/OfflineLoginDialog.cpp @@ -103,5 +103,5 @@ MinecraftAccountPtr OfflineLoginDialog::newAccount(QWidget *parent, QString msg) { return dlg.m_account; } - return 0; + return nullptr; } diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.cpp b/launcher/ui/pages/instance/ExternalResourcesPage.cpp index 69c20309..39fbe3e2 100644 --- a/launcher/ui/pages/instance/ExternalResourcesPage.cpp +++ b/launcher/ui/pages/instance/ExternalResourcesPage.cpp @@ -101,7 +101,7 @@ ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared { ui->setupUi(this); - runningStateChanged(m_instance && m_instance->isRunning()); + ExternalResourcesPage::runningStateChanged(m_instance && m_instance->isRunning()); ui->actionsToolbar->insertSpacer(ui->actionViewConfigs); diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.h b/launcher/ui/pages/instance/ExternalResourcesPage.h index 41237139..ff294678 100644 --- a/launcher/ui/pages/instance/ExternalResourcesPage.h +++ b/launcher/ui/pages/instance/ExternalResourcesPage.h @@ -46,7 +46,7 @@ class ExternalResourcesPage : public QMainWindow, public BasePage { protected slots: void itemActivated(const QModelIndex& index); void filterTextChanged(const QString& newContents); - void runningStateChanged(bool running); + virtual void runningStateChanged(bool running); virtual void addItem(); virtual void removeItem(); diff --git a/launcher/ui/pages/instance/ModFolderPage.cpp b/launcher/ui/pages/instance/ModFolderPage.cpp index 14e1f1e5..45678db1 100644 --- a/launcher/ui/pages/instance/ModFolderPage.cpp +++ b/launcher/ui/pages/instance/ModFolderPage.cpp @@ -84,49 +84,44 @@ ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> ui->actionsToolbar->insertActionAfter(ui->actionAddItem, ui->actionUpdateItem); connect(ui->actionUpdateItem, &QAction::triggered, this, &ModFolderPage::updateMods); - connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, - [this] { ui->actionUpdateItem->setEnabled(ui->treeView->selectionModel()->hasSelection() || !m_model->empty()); }); + auto check_allow_update = [this] { + return (!m_instance || !m_instance->isRunning()) && + (ui->treeView->selectionModel()->hasSelection() || !m_model->empty()); + }; - connect(mods.get(), &ModFolderModel::rowsInserted, this, - [this] { ui->actionUpdateItem->setEnabled(ui->treeView->selectionModel()->hasSelection() || !m_model->empty()); }); - - connect(mods.get(), &ModFolderModel::updateFinished, this, [this, mods] { - ui->actionUpdateItem->setEnabled(ui->treeView->selectionModel()->hasSelection() || !m_model->empty()); + connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this, check_allow_update] { + ui->actionUpdateItem->setEnabled(check_allow_update()); + }); + + connect(mods.get(), &ModFolderModel::rowsInserted, this, [this, check_allow_update] { + ui->actionUpdateItem->setEnabled(check_allow_update()); + }); + + connect(mods.get(), &ModFolderModel::rowsRemoved, this, [this, check_allow_update] { + ui->actionUpdateItem->setEnabled(check_allow_update()); + }); + + connect(mods.get(), &ModFolderModel::updateFinished, this, [this, check_allow_update, mods] { + ui->actionUpdateItem->setEnabled(check_allow_update()); // Prevent a weird crash when trying to open the mods page twice in a session o.O disconnect(mods.get(), &ModFolderModel::updateFinished, this, 0); }); + + ModFolderPage::runningStateChanged(m_instance && m_instance->isRunning()); } } -CoreModFolderPage::CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent) - : ModFolderPage(inst, mods, parent) -{} - -bool ModFolderPage::shouldDisplay() const +void ModFolderPage::runningStateChanged(bool running) { - return true; + ExternalResourcesPage::runningStateChanged(running); + ui->actionDownloadItem->setEnabled(!running); + ui->actionUpdateItem->setEnabled(!running); } -bool CoreModFolderPage::shouldDisplay() const +bool ModFolderPage::shouldDisplay() const { - if (ModFolderPage::shouldDisplay()) { - auto inst = dynamic_cast<MinecraftInstance*>(m_instance); - if (!inst) - return true; - - auto version = inst->getPackProfile(); - - if (!version) - return true; - if (!version->getComponent("net.minecraftforge")) - return false; - if (!version->getComponent("net.minecraft")) - return false; - if (version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate) - return true; - } - return false; + return true; } void ModFolderPage::installMods() @@ -232,3 +227,28 @@ void ModFolderPage::updateMods() m_model->update(); } } + +CoreModFolderPage::CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent) + : ModFolderPage(inst, mods, parent) +{} + +bool CoreModFolderPage::shouldDisplay() const +{ + if (ModFolderPage::shouldDisplay()) { + auto inst = dynamic_cast<MinecraftInstance*>(m_instance); + if (!inst) + return true; + + auto version = inst->getPackProfile(); + + if (!version) + return true; + if (!version->getComponent("net.minecraftforge")) + return false; + if (!version->getComponent("net.minecraft")) + return false; + if (version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate) + return true; + } + return false; +} diff --git a/launcher/ui/pages/instance/ModFolderPage.h b/launcher/ui/pages/instance/ModFolderPage.h index 0a7fc9fa..7e305951 100644 --- a/launcher/ui/pages/instance/ModFolderPage.h +++ b/launcher/ui/pages/instance/ModFolderPage.h @@ -53,6 +53,7 @@ class ModFolderPage : public ExternalResourcesPage { virtual QString helpPage() const override { return "Loader-mods"; } virtual bool shouldDisplay() const override; + void runningStateChanged(bool running) override; private slots: void installMods(); @@ -63,5 +64,11 @@ class CoreModFolderPage : public ModFolderPage { public: explicit CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent = 0); virtual ~CoreModFolderPage() = default; - virtual bool shouldDisplay() const; + + virtual QString displayName() const override { return tr("Core mods"); } + virtual QIcon icon() const override { return APPLICATION->getThemedIcon("coremods"); } + virtual QString id() const override { return "coremods"; } + virtual QString helpPage() const override { return "Core-mods"; } + + virtual bool shouldDisplay() const override; }; diff --git a/launcher/updater/UpdateChecker.cpp b/launcher/updater/UpdateChecker.cpp index fa6e5a97..78d979ff 100644 --- a/launcher/updater/UpdateChecker.cpp +++ b/launcher/updater/UpdateChecker.cpp @@ -25,12 +25,11 @@ #include "BuildConfig.h" -UpdateChecker::UpdateChecker(shared_qobject_ptr<QNetworkAccessManager> nam, QString channelUrl, QString currentChannel, int currentBuild) +UpdateChecker::UpdateChecker(shared_qobject_ptr<QNetworkAccessManager> nam, QString channelUrl, QString currentChannel) { m_network = nam; m_channelUrl = channelUrl; m_currentChannel = currentChannel; - m_currentBuild = currentBuild; #ifdef Q_OS_MAC m_externalUpdater = new MacSparkleUpdater(); diff --git a/launcher/updater/UpdateChecker.h b/launcher/updater/UpdateChecker.h index 94e4312b..42ef318b 100644 --- a/launcher/updater/UpdateChecker.h +++ b/launcher/updater/UpdateChecker.h @@ -28,7 +28,7 @@ class UpdateChecker : public QObject Q_OBJECT public: - UpdateChecker(shared_qobject_ptr<QNetworkAccessManager> nam, QString channelUrl, QString currentChannel, int currentBuild); + UpdateChecker(shared_qobject_ptr<QNetworkAccessManager> nam, QString channelUrl, QString currentChannel); void checkForUpdate(const QString& updateChannel, bool notifyNoUpdate); /*! diff --git a/program_info/CMakeLists.txt b/program_info/CMakeLists.txt index b1ba89df..ac8ea6ce 100644 --- a/program_info/CMakeLists.txt +++ b/program_info/CMakeLists.txt @@ -15,7 +15,7 @@ set(Launcher_Copyright "${Launcher_Copyright}" PARENT_SCOPE) set(Launcher_Domain "polymc.org" PARENT_SCOPE) set(Launcher_Name "${Launcher_CommonName}" PARENT_SCOPE) set(Launcher_DisplayName "${Launcher_CommonName}" PARENT_SCOPE) -set(Launcher_UserAgent "${Launcher_CommonName}/${Launcher_RELEASE_VERSION_NAME}" PARENT_SCOPE) +set(Launcher_UserAgent "${Launcher_CommonName}/${Launcher_VERSION_NAME}" PARENT_SCOPE) set(Launcher_ConfigFile "polymc.cfg" PARENT_SCOPE) set(Launcher_Git "https://github.com/PolyMC/PolyMC" PARENT_SCOPE) set(Launcher_DesktopFileName "org.polymc.PolyMC.desktop" PARENT_SCOPE) diff --git a/program_info/org.polymc.PolyMC.metainfo.xml.in b/program_info/org.polymc.PolyMC.metainfo.xml.in index ea665655..db0ab882 100644 --- a/program_info/org.polymc.PolyMC.metainfo.xml.in +++ b/program_info/org.polymc.PolyMC.metainfo.xml.in @@ -6,7 +6,7 @@ </provides> <launchable type="desktop-id">org.polymc.PolyMC.desktop</launchable> <name>PolyMC</name> - <developer_name>PolyMC Team</developer_name> + <developer_name>PolyMC</developer_name> <summary>A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once</summary> <metadata_license>CC0-1.0</metadata_license> <project_license>GPL-3.0-only</project_license> @@ -16,39 +16,43 @@ <p>PolyMC is a custom launcher for Minecraft that focuses on predictability, long term stability and simplicity.</p> <p>Features:</p> <ul> - <li>Easily install game modifications, such as Fabric or Forge</li> + <li>Easily install game modifications, such as Fabric, Forge and Quilt</li> <li>Control your java settings</li> <li>Manage worlds and resource packs from the launcher</li> <li>See logs and other details easily</li> <li>Kill Minecraft in case of a crash/freeze</li> <li>Isolate minecraft instances to keep everything clean</li> - <li>Install mods directly from the launcher</li> + <li>Install and update mods directly from the launcher</li> </ul> </description> <screenshots> <screenshot type="default"> <caption>The main PolyMC window</caption> - <image type="source" width="931" height="759">https://polymc.org/img/screenshots/LauncherDark.png</image> + <image type="source" width="578" height="452">https://polymc.org/img/screenshots/LauncherDark.png</image> </screenshot> <screenshot> <caption>Modpack installation</caption> - <image type="source" width="860" height="848">https://polymc.org/img/screenshots/ModpackInstallDark.png</image> + <image type="source" width="523" height="452">https://polymc.org/img/screenshots/ModpackInstallDark.png</image> </screenshot> <screenshot> <caption>Mod installation</caption> - <image type="source" width="1018" height="858">https://polymc.org/img/screenshots/ModInstallDark.png</image> + <image type="source" width="654" height="452">https://polymc.org/img/screenshots/ModInstallDark.png</image> + </screenshot> + <screenshot> + <caption>Mod updating</caption> + <image type="source" width="490" height="452">https://polymc.org/img/screenshots/ModUpdateDark.png</image> </screenshot> <screenshot> <caption>Instance management</caption> - <image type="source" width="777" height="693">https://polymc.org/img/screenshots/PropertiesDark.png</image> + <image type="source" width="667" height="452">https://polymc.org/img/screenshots/PropertiesDark.png</image> </screenshot> <screenshot> <caption>Cat :)</caption> - <image type="source" width="931" height="759">https://polymc.org/img/screenshots/LauncherCatDark.png</image> + <image type="source" width="555" height="452">https://polymc.org/img/screenshots/LauncherCatDark.png</image> </screenshot> </screenshots> <releases> - <release version="@Launcher_RELEASE_VERSION_NAME@" date="@Launcher_RELEASE_TIMESTAMP@"></release> + <release version="@Launcher_VERSION_NAME@" date="@Launcher_BUILD_TIMESTAMP@"></release> </releases> <content_rating type="oars-1.1"> <content_attribute id="violence-fantasy">moderate</content_attribute> diff --git a/program_info/polymc.manifest.in b/program_info/polymc.manifest.in index 0eefacac..b85b6d46 100644 --- a/program_info/polymc.manifest.in +++ b/program_info/polymc.manifest.in @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> - <assemblyIdentity name="PolyMC.Application.1" type="win32" version="@Launcher_RELEASE_VERSION_NAME4@" /> + <assemblyIdentity name="PolyMC.Application.1" type="win32" version="@Launcher_VERSION_NAME4@" /> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> diff --git a/program_info/polymc.rc.in b/program_info/polymc.rc.in index 0ea9b73a..be51ad71 100644 --- a/program_info/polymc.rc.in +++ b/program_info/polymc.rc.in @@ -7,7 +7,7 @@ IDI_ICON1 ICON DISCARDABLE "polymc.ico" 1 RT_MANIFEST "polymc.manifest" VS_VERSION_INFO VERSIONINFO -FILEVERSION @Launcher_RELEASE_VERSION_NAME4_COMMA@ +FILEVERSION @Launcher_VERSION_NAME4_COMMA@ FILEOS VOS_NT_WINDOWS32 FILETYPE VFT_APP BEGIN @@ -17,9 +17,9 @@ BEGIN BEGIN VALUE "CompanyName", "MultiMC & PolyMC Contributors" VALUE "FileDescription", "PolyMC" - VALUE "FileVersion", "@Launcher_RELEASE_VERSION_NAME4@" + VALUE "FileVersion", "@Launcher_VERSION_NAME4@" VALUE "ProductName", "PolyMC" - VALUE "ProductVersion", "@Launcher_RELEASE_VERSION_NAME4@" + VALUE "ProductVersion", "@Launcher_VERSION_NAME4@" END END BLOCK "VarFileInfo" diff --git a/program_info/win_install.nsi.in b/program_info/win_install.nsi.in index 84c3766e..87e266f8 100644 --- a/program_info/win_install.nsi.in +++ b/program_info/win_install.nsi.in @@ -102,13 +102,13 @@ OutFile "../@Launcher_CommonName@-Setup.exe" ;-------------------------------- ; Version info -VIProductVersion "@Launcher_RELEASE_VERSION_NAME4@" -VIFileVersion "@Launcher_RELEASE_VERSION_NAME4@" +VIProductVersion "@Launcher_VERSION_NAME4@" +VIFileVersion "@Launcher_VERSION_NAME4@" VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductName" "@Launcher_CommonName@" VIAddVersionKey /LANG=${LANG_ENGLISH} "FileDescription" "@Launcher_CommonName@ Installer" VIAddVersionKey /LANG=${LANG_ENGLISH} "LegalCopyright" "@Launcher_Copyright@" -VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "@Launcher_RELEASE_VERSION_NAME4@" -VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductVersion" "@Launcher_RELEASE_VERSION_NAME4@" +VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "@Launcher_VERSION_NAME4@" +VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductVersion" "@Launcher_VERSION_NAME4@" ;-------------------------------- @@ -145,8 +145,8 @@ Section "@Launcher_CommonName@" WriteRegStr HKCU "${UNINST_KEY}" "QuietUninstallString" '"$INSTDIR\uninstall.exe" /S' WriteRegStr HKCU "${UNINST_KEY}" "InstallLocation" "$INSTDIR" WriteRegStr HKCU "${UNINST_KEY}" "Publisher" "@Launcher_CommonName@ Contributors" - WriteRegStr HKCU "${UNINST_KEY}" "Version" "@Launcher_RELEASE_VERSION_NAME4@" - WriteRegStr HKCU "${UNINST_KEY}" "DisplayVersion" "@Launcher_RELEASE_VERSION_NAME@" + WriteRegStr HKCU "${UNINST_KEY}" "Version" "@Launcher_VERSION_NAME4@" + WriteRegStr HKCU "${UNINST_KEY}" "DisplayVersion" "@Launcher_VERSION_NAME@" WriteRegStr HKCU "${UNINST_KEY}" "VersionMajor" "@Launcher_VERSION_MAJOR@" WriteRegStr HKCU "${UNINST_KEY}" "VersionMinor" "@Launcher_VERSION_MINOR@" ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 |