aboutsummaryrefslogtreecommitdiff
path: root/launcher
diff options
context:
space:
mode:
Diffstat (limited to 'launcher')
-rw-r--r--launcher/Application.cpp113
-rw-r--r--launcher/BaseInstance.cpp5
-rw-r--r--launcher/BaseInstance.h8
-rw-r--r--launcher/CMakeLists.txt3
-rw-r--r--launcher/Commandline.cpp408
-rw-r--r--launcher/Commandline.h213
-rw-r--r--launcher/NullInstance.h39
-rw-r--r--launcher/RuntimeContext.h80
-rw-r--r--launcher/launch/steps/CheckJava.cpp20
-rw-r--r--launcher/minecraft/Component.cpp37
-rw-r--r--launcher/minecraft/LaunchProfile.cpp24
-rw-r--r--launcher/minecraft/LaunchProfile.h8
-rw-r--r--launcher/minecraft/Library.cpp84
-rw-r--r--launcher/minecraft/Library.h54
-rw-r--r--launcher/minecraft/MinecraftInstance.cpp30
-rw-r--r--launcher/minecraft/MinecraftInstance.h37
-rw-r--r--launcher/minecraft/MojangVersionFormat.cpp9
-rw-r--r--launcher/minecraft/OpSys.cpp46
-rw-r--r--launcher/minecraft/OpSys.h38
-rw-r--r--launcher/minecraft/PackProfile.cpp7
-rw-r--r--launcher/minecraft/PackProfile.h43
-rw-r--r--launcher/minecraft/Rule.cpp46
-rw-r--r--launcher/minecraft/Rule.h60
-rw-r--r--launcher/minecraft/VersionFile.cpp8
-rw-r--r--launcher/minecraft/VersionFile.h3
-rw-r--r--launcher/minecraft/launch/ModMinecraftJar.cpp43
-rw-r--r--launcher/minecraft/launch/ScanModFolders.cpp41
-rw-r--r--launcher/minecraft/update/FoldersTask.cpp35
-rw-r--r--launcher/minecraft/update/LibrariesTask.cpp2
-rw-r--r--launcher/ui/pages/global/LauncherPage.ui2
-rw-r--r--launcher/ui/pages/instance/InstanceSettingsPage.cpp3
-rw-r--r--launcher/ui/pages/modplatform/ModModel.cpp8
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp58
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp4
-rw-r--r--launcher/ui/themes/BrightTheme.cpp26
-rw-r--r--launcher/ui/themes/DarkTheme.cpp14
-rw-r--r--launcher/ui/widgets/InfoFrame.cpp63
-rw-r--r--launcher/ui/widgets/ProjectItem.cpp37
38 files changed, 724 insertions, 1035 deletions
diff --git a/launcher/Application.cpp b/launcher/Application.cpp
index 0d1db11c..968dd08e 100644
--- a/launcher/Application.cpp
+++ b/launcher/Application.cpp
@@ -78,6 +78,7 @@
#include <iostream>
#include <QAccessible>
+#include <QCommandLineParser>
#include <QDir>
#include <QFileInfo>
#include <QNetworkAccessManager>
@@ -110,7 +111,6 @@
#include "translations/TranslationsModel.h"
#include "meta/Index.h"
-#include <Commandline.h>
#include <FileSystem.h>
#include <DesktopServices.h>
#include <LocalPeer.h>
@@ -136,12 +136,6 @@
static const QLatin1String liveCheckFile("live.check");
-using namespace Commandline;
-
-#define MACOS_HINT "If you are on macOS Sierra, you might have to move the app to your /Applications or ~/Applications folder. "\
- "This usually fixes the problem and you can move the application elsewhere afterwards.\n"\
- "\n"
-
namespace {
void appDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
@@ -242,80 +236,27 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
this->setQuitOnLastWindowClosed(false);
// Commandline parsing
- QHash<QString, QVariant> args;
- {
- Parser parser(FlagStyle::GNU, ArgumentStyle::SpaceAndEquals);
-
- // --help
- parser.addSwitch("help");
- parser.addShortOpt("help", 'h');
- parser.addDocumentation("help", "Display this help and exit.");
- // --version
- parser.addSwitch("version");
- parser.addShortOpt("version", 'V');
- parser.addDocumentation("version", "Display program version and exit.");
- // --dir
- parser.addOption("dir");
- parser.addShortOpt("dir", 'd');
- parser.addDocumentation("dir", "Use the supplied folder as application root instead of the binary location (use '.' for current)");
- // --launch
- parser.addOption("launch");
- parser.addShortOpt("launch", 'l');
- parser.addDocumentation("launch", "Launch the specified instance (by instance ID)");
- // --server
- parser.addOption("server");
- parser.addShortOpt("server", 's');
- parser.addDocumentation("server", "Join the specified server on launch (only valid in combination with --launch)");
- // --profile
- parser.addOption("profile");
- parser.addShortOpt("profile", 'a');
- parser.addDocumentation("profile", "Use the account specified by its profile name (only valid in combination with --launch)");
- // --alive
- parser.addSwitch("alive");
- parser.addDocumentation("alive", "Write a small '" + liveCheckFile + "' file after the launcher starts");
- // --import
- parser.addOption("import");
- parser.addShortOpt("import", 'I');
- parser.addDocumentation("import", "Import instance from specified zip (local path or URL)");
-
- // parse the arguments
- try
- {
- args = parser.parse(arguments());
- }
- catch (const ParsingError &e)
- {
- std::cerr << "CommandLineError: " << e.what() << std::endl;
- if(argc > 0)
- std::cerr << "Try '" << argv[0] << " -h' to get help on command line parameters."
- << std::endl;
- m_status = Application::Failed;
- return;
- }
-
- // display help and exit
- if (args["help"].toBool())
- {
- std::cout << qPrintable(parser.compileHelp(arguments()[0]));
- m_status = Application::Succeeded;
- return;
- }
+ QCommandLineParser parser;
+ parser.setApplicationDescription(BuildConfig.LAUNCHER_NAME);
+
+ parser.addOptions({
+ {{"d", "dir"}, "Use a custom path as application root (use '.' for current directory)", "directory"},
+ {{"l", "launch"}, "Launch the specified instance (by instance ID)", "instance"},
+ {{"s", "server"}, "Join the specified server on launch (only valid in combination with --launch)", "address"},
+ {{"a", "profile"}, "Use the account specified by its profile name (only valid in combination with --launch)", "profile"},
+ {"alive", "Write a small '" + liveCheckFile + "' file after the launcher starts"},
+ {{"I", "import"}, "Import instance from specified zip (local path or URL)", "file"}
+ });
+ parser.addHelpOption();
+ parser.addVersionOption();
- // display version and exit
- if (args["version"].toBool())
- {
- std::cout << "Version " << BuildConfig.printableVersionString().toStdString() << std::endl;
- std::cout << "Git " << BuildConfig.GIT_COMMIT.toStdString() << std::endl;
- m_status = Application::Succeeded;
- return;
- }
- }
+ parser.process(arguments());
- m_instanceIdToLaunch = args["launch"].toString();
- m_serverToJoin = args["server"].toString();
- m_profileToUse = args["profile"].toString();
- m_liveCheck = args["alive"].toBool();
- m_zipToImport = args["import"].toUrl();
+ m_instanceIdToLaunch = parser.value("launch");
+ m_serverToJoin = parser.value("server");
+ m_profileToUse = parser.value("profile");
+ m_liveCheck = parser.isSet("alive");
+ m_zipToImport = parser.value("import");
// error if --launch is missing with --server or --profile
if((!m_serverToJoin.isEmpty() || !m_profileToUse.isEmpty()) && m_instanceIdToLaunch.isEmpty())
@@ -346,7 +287,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
QString adjustedBy;
QString dataPath;
// change folder
- QString dirParam = args["dir"].toString();
+ QString dirParam = parser.value("dir");
if (!dirParam.isEmpty())
{
// the dir param. it makes multimc data path point to whatever the user specified
@@ -385,9 +326,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
QString(
"The launcher data folder could not be created.\n"
"\n"
-#if defined(Q_OS_MAC)
- MACOS_HINT
-#endif
"Make sure you have the right permissions to the launcher data folder and any folder needed to access it.\n"
"(%1)\n"
"\n"
@@ -403,9 +341,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
QString(
"The launcher data folder could not be opened.\n"
"\n"
-#if defined(Q_OS_MAC)
- MACOS_HINT
-#endif
"Make sure you have the right permissions to the launcher data folder.\n"
"(%1)\n"
"\n"
@@ -486,9 +421,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
QString(
"The launcher couldn't create a log file - the data folder is not writable.\n"
"\n"
- #if defined(Q_OS_MAC)
- MACOS_HINT
- #endif
"Make sure you have write permissions to the data folder.\n"
"(%1)\n"
"\n"
@@ -927,12 +859,13 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
qDebug() << "<> Application theme set.";
}
+ updateCapabilities();
+
if(createSetupWizard())
{
return;
}
- updateCapabilities();
performMainStartupAction();
}
diff --git a/launcher/BaseInstance.cpp b/launcher/BaseInstance.cpp
index 2995df6f..a0bd8823 100644
--- a/launcher/BaseInstance.cpp
+++ b/launcher/BaseInstance.cpp
@@ -368,3 +368,8 @@ shared_qobject_ptr<LaunchTask> BaseInstance::getLaunchTask()
{
return m_launchProcess;
}
+
+void BaseInstance::updateRuntimeContext()
+{
+ // NOOP
+}
diff --git a/launcher/BaseInstance.h b/launcher/BaseInstance.h
index 21cc3413..307240e0 100644
--- a/launcher/BaseInstance.h
+++ b/launcher/BaseInstance.h
@@ -54,6 +54,7 @@
#include "net/Mode.h"
#include "minecraft/launch/MinecraftServerTarget.h"
+#include "RuntimeContext.h"
class QDir;
class Task;
@@ -220,6 +221,12 @@ public:
virtual QString typeName() const = 0;
+ void updateRuntimeContext();
+ RuntimeContext runtimeContext() const
+ {
+ return m_runtimeContext;
+ }
+
bool hasVersionBroken() const
{
return m_hasBrokenVersion;
@@ -305,6 +312,7 @@ protected: /* data */
bool m_isRunning = false;
shared_qobject_ptr<LaunchTask> m_launchProcess;
QDateTime m_timeStarted;
+ RuntimeContext m_runtimeContext;
private: /* data */
Status m_status = Status::Present;
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index 0bdfcd44..c5894268 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -26,6 +26,7 @@ set(CORE_SOURCES
MMCZip.cpp
MMCStrings.h
MMCStrings.cpp
+ RuntimeContext.h
# Basic instance manipulation tasks (derived from InstanceTask)
InstanceCreationTask.h
@@ -288,8 +289,6 @@ set(MINECRAFT_SOURCES
minecraft/Rule.h
minecraft/OneSixVersionFormat.cpp
minecraft/OneSixVersionFormat.h
- minecraft/OpSys.cpp
- minecraft/OpSys.h
minecraft/ParseUtils.cpp
minecraft/ParseUtils.h
minecraft/ProfileUtils.cpp
diff --git a/launcher/Commandline.cpp b/launcher/Commandline.cpp
index 8e7356bb..6d97918d 100644
--- a/launcher/Commandline.cpp
+++ b/launcher/Commandline.cpp
@@ -92,412 +92,4 @@ QStringList splitArgs(QString args)
argv << current;
return argv;
}
-
-Parser::Parser(FlagStyle::Enum flagStyle, ArgumentStyle::Enum argStyle)
-{
- m_flagStyle = flagStyle;
- m_argStyle = argStyle;
-}
-
-// styles setter/getter
-void Parser::setArgumentStyle(ArgumentStyle::Enum style)
-{
- m_argStyle = style;
-}
-ArgumentStyle::Enum Parser::argumentStyle()
-{
- return m_argStyle;
-}
-
-void Parser::setFlagStyle(FlagStyle::Enum style)
-{
- m_flagStyle = style;
-}
-FlagStyle::Enum Parser::flagStyle()
-{
- return m_flagStyle;
-}
-
-// setup methods
-void Parser::addSwitch(QString name, bool def)
-{
- if (m_params.contains(name))
- throw "Name not unique";
-
- OptionDef *param = new OptionDef;
- param->type = otSwitch;
- param->name = name;
- param->metavar = QString("<%1>").arg(name);
- param->def = def;
-
- m_options[name] = param;
- m_params[name] = (CommonDef *)param;
- m_optionList.append(param);
-}
-
-void Parser::addOption(QString name, QVariant def)
-{
- if (m_params.contains(name))
- throw "Name not unique";
-
- OptionDef *param = new OptionDef;
- param->type = otOption;
- param->name = name;
- param->metavar = QString("<%1>").arg(name);
- param->def = def;
-
- m_options[name] = param;
- m_params[name] = (CommonDef *)param;
- m_optionList.append(param);
-}
-
-void Parser::addArgument(QString name, bool required, QVariant def)
-{
- if (m_params.contains(name))
- throw "Name not unique";
-
- PositionalDef *param = new PositionalDef;
- param->name = name;
- param->def = def;
- param->required = required;
- param->metavar = name;
-
- m_positionals.append(param);
- m_params[name] = (CommonDef *)param;
-}
-
-void Parser::addDocumentation(QString name, QString doc, QString metavar)
-{
- if (!m_params.contains(name))
- throw "Name does not exist";
-
- CommonDef *param = m_params[name];
- param->doc = doc;
- if (!metavar.isNull())
- param->metavar = metavar;
-}
-
-void Parser::addShortOpt(QString name, QChar flag)
-{
- if (!m_params.contains(name))
- throw "Name does not exist";
- if (!m_options.contains(name))
- throw "Name is not an Option or Swtich";
-
- OptionDef *param = m_options[name];
- m_flags[flag] = param;
- param->flag = flag;
-}
-
-// help methods
-QString Parser::compileHelp(QString progName, int helpIndent, bool useFlags)
-{
- QStringList help;
- help << compileUsage(progName, useFlags) << "\r\n";
-
- // positionals
- if (!m_positionals.isEmpty())
- {
- help << "\r\n";
- help << "Positional arguments:\r\n";
- QListIterator<PositionalDef *> it2(m_positionals);
- while (it2.hasNext())
- {
- PositionalDef *param = it2.next();
- help << " " << param->metavar;
- help << " " << QString(helpIndent - param->metavar.length() - 1, ' ');
- help << param->doc << "\r\n";
- }
- }
-
- // Options
- if (!m_optionList.isEmpty())
- {
- help << "\r\n";
- QString optPrefix, flagPrefix;
- getPrefix(optPrefix, flagPrefix);
-
- help << "Options & Switches:\r\n";
- QListIterator<OptionDef *> it(m_optionList);
- while (it.hasNext())
- {
- OptionDef *option = it.next();
- help << " ";
- int nameLength = optPrefix.length() + option->name.length();
- if (!option->flag.isNull())
- {
- nameLength += 3 + flagPrefix.length();
- help << flagPrefix << option->flag << ", ";
- }
- help << optPrefix << option->name;
- if (option->type == otOption)
- {
- QString arg = QString("%1%2").arg(
- ((m_argStyle == ArgumentStyle::Equals) ? "=" : " "), option->metavar);
- nameLength += arg.length();
- help << arg;
- }
- help << " " << QString(helpIndent - nameLength - 1, ' ');
- help << option->doc << "\r\n";
- }
- }
-
- return help.join("");
-}
-
-QString Parser::compileUsage(QString progName, bool useFlags)
-{
- QStringList usage;
- usage << "Usage: " << progName;
-
- QString optPrefix, flagPrefix;
- getPrefix(optPrefix, flagPrefix);
-
- // options
- QListIterator<OptionDef *> it(m_optionList);
- while (it.hasNext())
- {
- OptionDef *option = it.next();
- usage << " [";
- if (!option->flag.isNull() && useFlags)
- usage << flagPrefix << option->flag;
- else
- usage << optPrefix << option->name;
- if (option->type == otOption)
- usage << ((m_argStyle == ArgumentStyle::Equals) ? "=" : " ") << option->metavar;
- usage << "]";
- }
-
- // arguments
- QListIterator<PositionalDef *> it2(m_positionals);
- while (it2.hasNext())
- {
- PositionalDef *param = it2.next();
- usage << " " << (param->required ? "<" : "[");
- usage << param->metavar;
- usage << (param->required ? ">" : "]");
- }
-
- return usage.join("");
-}
-
-// parsing
-QHash<QString, QVariant> Parser::parse(QStringList argv)
-{
- QHash<QString, QVariant> map;
-
- QStringListIterator it(argv);
- QString programName = it.next();
-
- QString optionPrefix;
- QString flagPrefix;
- QListIterator<PositionalDef *> positionals(m_positionals);
- QStringList expecting;
-
- getPrefix(optionPrefix, flagPrefix);
-
- while (it.hasNext())
- {
- QString arg = it.next();
-
- if (!expecting.isEmpty())
- // we were expecting an argument
- {
- QString name = expecting.first();
-/*
- if (map.contains(name))
- throw ParsingError(
- QString("Option %2%1 was given multiple times").arg(name, optionPrefix));
-*/
- map[name] = QVariant(arg);
-
- expecting.removeFirst();
- continue;
- }
-
- if (arg.startsWith(optionPrefix))
- // we have an option
- {
- // qDebug("Found option %s", qPrintable(arg));
-
- QString name = arg.mid(optionPrefix.length());
- QString equals;
-
- if ((m_argStyle == ArgumentStyle::Equals ||
- m_argStyle == ArgumentStyle::SpaceAndEquals) &&
- name.contains("="))
- {
- int i = name.indexOf("=");
- equals = name.mid(i + 1);
- name = name.left(i);
- }
-
- if (m_options.contains(name))
- {
- /*
- if (map.contains(name))
- throw ParsingError(QString("Option %2%1 was given multiple times")
- .arg(name, optionPrefix));
-*/
- OptionDef *option = m_options[name];
- if (option->type == otSwitch)
- map[name] = true;
- else // if (option->type == otOption)
- {
- if (m_argStyle == ArgumentStyle::Space)
- expecting.append(name);
- else if (!equals.isNull())
- map[name] = equals;
- else if (m_argStyle == ArgumentStyle::SpaceAndEquals)
- expecting.append(name);
- else
- throw ParsingError(QString("Option %2%1 reqires an argument.")
- .arg(name, optionPrefix));
- }
-
- continue;
- }
-
- throw ParsingError(QString("Unknown Option %2%1").arg(name, optionPrefix));
- }
-
- if (arg.startsWith(flagPrefix))
- // we have (a) flag(s)
- {
- // qDebug("Found flags %s", qPrintable(arg));
-
- QString flags = arg.mid(flagPrefix.length());
- QString equals;
-
- if ((m_argStyle == ArgumentStyle::Equals ||
- m_argStyle == ArgumentStyle::SpaceAndEquals) &&
- flags.contains("="))
- {
- int i = flags.indexOf("=");
- equals = flags.mid(i + 1);
- flags = flags.left(i);
- }
-
- for (int i = 0; i < flags.length(); i++)
- {
- QChar flag = flags.at(i);
-
- if (!m_flags.contains(flag))
- throw ParsingError(QString("Unknown flag %2%1").arg(flag, flagPrefix));
-
- OptionDef *option = m_flags[flag];
-/*
- if (map.contains(option->name))
- throw ParsingError(QString("Option %2%1 was given multiple times")
- .arg(option->name, optionPrefix));
-*/
- if (option->type == otSwitch)
- map[option->name] = true;
- else // if (option->type == otOption)
- {
- if (m_argStyle == ArgumentStyle::Space)
- expecting.append(option->name);
- else if (!equals.isNull())
- if (i == flags.length() - 1)
- map[option->name] = equals;
- else
- throw ParsingError(QString("Flag %4%2 of Argument-requiring Option "
- "%1 not last flag in %4%3")
- .arg(option->name, flag, flags, flagPrefix));
- else if (m_argStyle == ArgumentStyle::SpaceAndEquals)
- expecting.append(option->name);
- else
- throw ParsingError(QString("Option %1 reqires an argument. (flag %3%2)")
- .arg(option->name, flag, flagPrefix));
- }
- }
-
- continue;
- }
-
- // must be a positional argument
- if (!positionals.hasNext())
- throw ParsingError(QString("Don't know what to do with '%1'").arg(arg));
-
- PositionalDef *param = positionals.next();
-
- map[param->name] = arg;
- }
-
- // check if we're missing something
- if (!expecting.isEmpty())
- throw ParsingError(QString("Was still expecting arguments for %2%1").arg(
- expecting.join(QString(", ") + optionPrefix), optionPrefix));
-
- while (positionals.hasNext())
- {
- PositionalDef *param = positionals.next();
- if (param->required)
- throw ParsingError(
- QString("Missing required positional argument '%1'").arg(param->name));
- else
- map[param->name] = param->def;
- }
-
- // fill out gaps
- QListIterator<OptionDef *> iter(m_optionList);
- while (iter.hasNext())
- {
- OptionDef *option = iter.next();
- if (!map.contains(option->name))
- map[option->name] = option->def;
- }
-
- return map;
-}
-
-// clear defs
-void Parser::clear()
-{
- m_flags.clear();
- m_params.clear();
- m_options.clear();
-
- QMutableListIterator<OptionDef *> it(m_optionList);
- while (it.hasNext())
- {
- OptionDef *option = it.next();
- it.remove();
- delete option;
- }
-
- QMutableListIterator<PositionalDef *> it2(m_positionals);
- while (it2.hasNext())
- {
- PositionalDef *arg = it2.next();
- it2.remove();
- delete arg;
- }
-}
-
-// Destructor
-Parser::~Parser()
-{
- clear();
-}
-
-// getPrefix
-void Parser::getPrefix(QString &opt, QString &flag)
-{
- if (m_flagStyle == FlagStyle::Windows)
- opt = flag = "/";
- else if (m_flagStyle == FlagStyle::Unix)
- opt = flag = "-";
- // else if (m_flagStyle == FlagStyle::GNU)
- else
- {
- opt = "--";
- flag = "-";
- }
-}
-
-// ParsingError
-ParsingError::ParsingError(const QString &what) : std::runtime_error(what.toStdString())
-{
-}
}
diff --git a/launcher/Commandline.h b/launcher/Commandline.h
index a4e7aa61..8bd79180 100644
--- a/launcher/Commandline.h
+++ b/launcher/Commandline.h
@@ -17,12 +17,7 @@
#pragma once
-#include <exception>
-#include <stdexcept>
-
#include <QString>
-#include <QVariant>
-#include <QHash>
#include <QStringList>
/**
@@ -39,212 +34,4 @@ namespace Commandline
* @return a QStringList containing all arguments
*/
QStringList splitArgs(QString args);
-
-/**
- * @brief The FlagStyle enum
- * Specifies how flags are decorated
- */
-
-namespace FlagStyle
-{
-enum Enum
-{
- GNU, /**< --option and -o (GNU Style) */
- Unix, /**< -option and -o (Unix Style) */
- Windows, /**< /option and /o (Windows Style) */
-#ifdef Q_OS_WIN32
- Default = Windows
-#else
- Default = GNU
-#endif
-};
-}
-
-/**
- * @brief The ArgumentStyle enum
- */
-namespace ArgumentStyle
-{
-enum Enum
-{
- Space, /**< --option value */
- Equals, /**< --option=value */
- SpaceAndEquals, /**< --option[= ]value */
-#ifdef Q_OS_WIN32
- Default = Equals
-#else
- Default = SpaceAndEquals
-#endif
-};
-}
-
-/**
- * @brief The ParsingError class
- */
-class ParsingError : public std::runtime_error
-{
-public:
- ParsingError(const QString &what);
-};
-
-/**
- * @brief The Parser class
- */
-class Parser
-{
-public:
- /**
- * @brief Parser constructor
- * @param flagStyle the FlagStyle to use in this Parser
- * @param argStyle the ArgumentStyle to use in this Parser
- */
- Parser(FlagStyle::Enum flagStyle = FlagStyle::Default,
- ArgumentStyle::Enum argStyle = ArgumentStyle::Default);
-
- /**
- * @brief set the flag style
- * @param style
- */
- void setFlagStyle(FlagStyle::Enum style);
-
- /**
- * @brief get the flag style
- * @return
- */
- FlagStyle::Enum flagStyle();
-
- /**
- * @brief set the argument style
- * @param style
- */
- void setArgumentStyle(ArgumentStyle::Enum style);
-
- /**
- * @brief get the argument style
- * @return
- */
- ArgumentStyle::Enum argumentStyle();
-
- /**
- * @brief define a boolean switch
- * @param name the parameter name
- * @param def the default value
- */
- void addSwitch(QString name, bool def = false);
-
- /**
- * @brief define an option that takes an additional argument
- * @param name the parameter name
- * @param def the default value
- */
- void addOption(QString name, QVariant def = QVariant());
-
- /**
- * @brief define a positional argument
- * @param name the parameter name
- * @param required wether this argument is required
- * @param def the default value
- */
- void addArgument(QString name, bool required = true, QVariant def = QVariant());
-
- /**
- * @brief adds a flag to an existing parameter
- * @param name the (existing) parameter name
- * @param flag the flag character
- * @see addSwitch addArgument addOption
- * Note: any one parameter can only have one flag
- */
- void addShortOpt(QString name, QChar flag);
-
- /**
- * @brief adds documentation to a Parameter
- * @param name the parameter name
- * @param metavar a string to be displayed as placeholder for the value
- * @param doc a QString containing the documentation
- * Note: on positional arguments, metavar replaces the name as displayed.
- * on options , metavar replaces the value placeholder
- */
- void addDocumentation(QString name, QString doc, QString metavar = QString());
-
- /**
- * @brief generate a help message
- * @param progName the program name to use in the help message
- * @param helpIndent how much the parameter documentation should be indented
- * @param flagsInUsage whether we should use flags instead of options in the usage
- * @return a help message
- */
- QString compileHelp(QString progName, int helpIndent = 22, bool flagsInUsage = true);
-
- /**
- * @brief generate a short usage message
- * @param progName the program name to use in the usage message
- * @param useFlags whether we should use flags instead of options
- * @return a usage message
- */
- QString compileUsage(QString progName, bool useFlags = true);
-
- /**
- * @brief parse
- * @param argv a QStringList containing the program ARGV
- * @return a QHash mapping argument names to their values
- */
- QHash<QString, QVariant> parse(QStringList argv);
-
- /**
- * @brief clear all definitions
- */
- void clear();
-
- ~Parser();
-
-private:
- FlagStyle::Enum m_flagStyle;
- ArgumentStyle::Enum m_argStyle;
-
- enum OptionType
- {
- otSwitch,
- otOption
- };
-
- // Important: the common part MUST BE COMMON ON ALL THREE structs
- struct CommonDef
- {
- QString name;
- QString doc;
- QString metavar;
- QVariant def;
- };
-
- struct OptionDef
- {
- // common
- QString name;
- QString doc;
- QString metavar;
- QVariant def;
- // option
- OptionType type;
- QChar flag;
- };
-
- struct PositionalDef
- {
- // common
- QString name;
- QString doc;
- QString metavar;
- QVariant def;
- // positional
- bool required;
- };
-
- QHash<QString, OptionDef *> m_options;
- QHash<QChar, OptionDef *> m_flags;
- QHash<QString, CommonDef *> m_params;
- QList<PositionalDef *> m_positionals;
- QList<OptionDef *> m_optionList;
-
- void getPrefix(QString &opt, QString &flag);
-};
}
diff --git a/launcher/NullInstance.h b/launcher/NullInstance.h
index 53e64a05..53edfa0b 100644
--- a/launcher/NullInstance.h
+++ b/launcher/NullInstance.h
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#pragma once
#include "BaseInstance.h"
#include "launch/LaunchTask.h"
@@ -84,4 +119,8 @@ public:
QString modsRoot() const override {
return QString();
}
+ void updateRuntimeContext()
+ {
+ // NOOP
+ }
};
diff --git a/launcher/RuntimeContext.h b/launcher/RuntimeContext.h
new file mode 100644
index 00000000..c1b71318
--- /dev/null
+++ b/launcher/RuntimeContext.h
@@ -0,0 +1,80 @@
+// 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/>.
+ */
+
+#pragma once
+
+#include <QSet>
+#include <QString>
+#include "settings/SettingsObject.h"
+
+struct RuntimeContext {
+ QString javaArchitecture;
+ QString javaRealArchitecture;
+ QString javaPath;
+ QString system;
+
+ QString mappedJavaRealArchitecture() const {
+ if (javaRealArchitecture == "aarch64") {
+ return "arm64";
+ }
+ return javaRealArchitecture;
+ }
+
+ void updateFromInstanceSettings(SettingsObjectPtr instanceSettings) {
+ javaArchitecture = instanceSettings->get("JavaArchitecture").toString();
+ javaRealArchitecture = instanceSettings->get("JavaRealArchitecture").toString();
+ javaPath = instanceSettings->get("JavaPath").toString();
+ system = currentSystem();
+ }
+
+ QString getClassifier() const {
+ return system + "-" + mappedJavaRealArchitecture();
+ }
+
+ // "Legacy" refers to the fact that Mojang assumed that these are the only two architectures
+ bool isLegacyArch() const {
+ QSet<QString> legacyArchitectures{"amd64", "x86_64", "i386", "i686", "x86"};
+ return legacyArchitectures.contains(mappedJavaRealArchitecture());
+ }
+
+ bool classifierMatches(QString target) const {
+ // try to match precise classifier "[os]-[arch]"
+ bool x = target == getClassifier();
+ // try to match imprecise classifier on legacy architectures "[os]"
+ if (!x && isLegacyArch())
+ x = target == system;
+
+ return x;
+ }
+
+ static QString currentSystem() {
+#if defined(Q_OS_LINUX)
+ return "linux";
+#elif defined(Q_OS_MACOS)
+ return "osx";
+#elif defined(Q_OS_WINDOWS)
+ return "windows";
+#elif defined(Q_OS_FREEBSD)
+ return "freebsd";
+#elif defined(Q_OS_OPENBSD)
+ return "openbsd";
+#else
+ return "unknown";
+#endif
+ }
+};
diff --git a/launcher/launch/steps/CheckJava.cpp b/launcher/launch/steps/CheckJava.cpp
index db56b652..7aeb61bf 100644
--- a/launcher/launch/steps/CheckJava.cpp
+++ b/launcher/launch/steps/CheckJava.cpp
@@ -121,7 +121,6 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
emit logLine(QString("Could not start java:"), MessageLevel::Error);
emit logLines(result.errorLog.split('\n'), MessageLevel::Error);
emit logLine(QString("\nCheck your Java settings."), MessageLevel::Launcher);
- printSystemInfo(false, false);
emitFailed(QString("Could not start java!"));
return;
}
@@ -130,7 +129,6 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
emit logLine(QString("Java checker returned some invalid data we don't understand:"), MessageLevel::Error);
emit logLines(result.outLog.split('\n'), MessageLevel::Warning);
emit logLine("\nMinecraft might not start properly.", MessageLevel::Launcher);
- printSystemInfo(false, false);
emitSucceeded();
return;
}
@@ -138,7 +136,6 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
{
auto instance = m_parent->instance();
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);
@@ -155,20 +152,3 @@ void CheckJava::printJavaInfo(const QString& version, const QString& architectur
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)
-{
- auto cpu64 = Sys::isCPU64bit();
- auto system64 = Sys::isSystem64bit();
- if(cpu64 != system64)
- {
- emit logLine(QString("Your CPU architecture is not matching your system architecture. You might want to install a 64bit Operating System.\n\n"), MessageLevel::Error);
- }
- if(javaIsKnown)
- {
- if(javaIs64bit != system64)
- {
- emit logLine(QString("Your Java architecture is not matching your system architecture. You might want to install a 64bit Java version.\n\n"), MessageLevel::Error);
- }
- }
-}
diff --git a/launcher/minecraft/Component.cpp b/launcher/minecraft/Component.cpp
index c7dd5e36..7e5b6058 100644
--- a/launcher/minecraft/Component.cpp
+++ b/launcher/minecraft/Component.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#include <meta/VersionList.h>
#include <meta/Index.h>
#include "Component.h"
@@ -60,7 +95,7 @@ void Component::applyTo(LaunchProfile* profile)
auto vfile = getVersionFile();
if(vfile)
{
- vfile->applyTo(profile);
+ vfile->applyTo(profile, m_parent->runtimeContext());
}
else
{
diff --git a/launcher/minecraft/LaunchProfile.cpp b/launcher/minecraft/LaunchProfile.cpp
index 39a342ca..9a6cea11 100644
--- a/launcher/minecraft/LaunchProfile.cpp
+++ b/launcher/minecraft/LaunchProfile.cpp
@@ -173,9 +173,9 @@ void LaunchProfile::applyCompatibleJavaMajors(QList<int>& javaMajor)
m_compatibleJavaMajors.append(javaMajor);
}
-void LaunchProfile::applyLibrary(LibraryPtr library)
+void LaunchProfile::applyLibrary(LibraryPtr library, const RuntimeContext & runtimeContext)
{
- if(!library->isActive())
+ if(!library->isActive(runtimeContext))
{
return;
}
@@ -205,9 +205,9 @@ void LaunchProfile::applyLibrary(LibraryPtr library)
}
}
-void LaunchProfile::applyMavenFile(LibraryPtr mavenFile)
+void LaunchProfile::applyMavenFile(LibraryPtr mavenFile, const RuntimeContext & runtimeContext)
{
- if(!mavenFile->isActive())
+ if(!mavenFile->isActive(runtimeContext))
{
return;
}
@@ -221,10 +221,10 @@ void LaunchProfile::applyMavenFile(LibraryPtr mavenFile)
m_mavenFiles.append(Library::limitedCopy(mavenFile));
}
-void LaunchProfile::applyAgent(AgentPtr agent)
+void LaunchProfile::applyAgent(AgentPtr agent, const RuntimeContext & runtimeContext)
{
auto lib = agent->library();
- if(!lib->isActive())
+ if(!lib->isActive(runtimeContext))
{
return;
}
@@ -354,7 +354,7 @@ const QList<int> & LaunchProfile::getCompatibleJavaMajors() const
}
void LaunchProfile::getLibraryFiles(
- const QString& architecture,
+ const RuntimeContext & runtimeContext,
QStringList& jars,
QStringList& nativeJars,
const QString& overridePath,
@@ -366,7 +366,7 @@ void LaunchProfile::getLibraryFiles(
nativeJars.clear();
for (auto lib : getLibraries())
{
- lib->getApplicableFiles(currentSystem, jars, nativeJars, native32, native64, overridePath);
+ lib->getApplicableFiles(runtimeContext, jars, nativeJars, native32, native64, overridePath);
}
// NOTE: order is important here, add main jar last to the lists
if(m_mainJar)
@@ -379,18 +379,18 @@ void LaunchProfile::getLibraryFiles(
}
else
{
- m_mainJar->getApplicableFiles(currentSystem, jars, nativeJars, native32, native64, overridePath);
+ m_mainJar->getApplicableFiles(runtimeContext, jars, nativeJars, native32, native64, overridePath);
}
}
for (auto lib : getNativeLibraries())
{
- lib->getApplicableFiles(currentSystem, jars, nativeJars, native32, native64, overridePath);
+ lib->getApplicableFiles(runtimeContext, jars, nativeJars, native32, native64, overridePath);
}
- if(architecture == "32")
+ if(runtimeContext.javaArchitecture == "32")
{
nativeJars.append(native32);
}
- else if(architecture == "64")
+ else if(runtimeContext.javaArchitecture == "64")
{
nativeJars.append(native64);
}
diff --git a/launcher/minecraft/LaunchProfile.h b/launcher/minecraft/LaunchProfile.h
index b55cf661..49c1217d 100644
--- a/launcher/minecraft/LaunchProfile.h
+++ b/launcher/minecraft/LaunchProfile.h
@@ -56,9 +56,9 @@ public: /* application of profile variables from patches */
void applyTweakers(const QStringList &tweakers);
void applyJarMods(const QList<LibraryPtr> &jarMods);
void applyMods(const QList<LibraryPtr> &jarMods);
- void applyLibrary(LibraryPtr library);
- void applyMavenFile(LibraryPtr library);
- void applyAgent(AgentPtr agent);
+ void applyLibrary(LibraryPtr library, const RuntimeContext & runtimeContext);
+ void applyMavenFile(LibraryPtr library, const RuntimeContext & runtimeContext);
+ void applyAgent(AgentPtr agent, const RuntimeContext & runtimeContext);
void applyCompatibleJavaMajors(QList<int>& javaMajor);
void applyMainJar(LibraryPtr jar);
void applyProblemSeverity(ProblemSeverity severity);
@@ -83,7 +83,7 @@ public: /* getters for profile variables */
const QList<int> & getCompatibleJavaMajors() const;
const LibraryPtr getMainJar() const;
void getLibraryFiles(
- const QString & architecture,
+ const RuntimeContext & runtimeContext,
QStringList & jars,
QStringList & nativeJars,
const QString & overridePath,
diff --git a/launcher/minecraft/Library.cpp b/launcher/minecraft/Library.cpp
index ba7aed4b..cb2b5254 100644
--- a/launcher/minecraft/Library.cpp
+++ b/launcher/minecraft/Library.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#include "Library.h"
#include "MinecraftInstance.h"
@@ -7,7 +42,7 @@
#include <BuildConfig.h>
-void Library::getApplicableFiles(OpSys system, QStringList& jar, QStringList& native, QStringList& native32,
+void Library::getApplicableFiles(const RuntimeContext & runtimeContext, QStringList& jar, QStringList& native, QStringList& native32,
QStringList& native64, const QString &overridePath) const
{
bool local = isLocal();
@@ -21,7 +56,7 @@ void Library::getApplicableFiles(OpSys system, QStringList& jar, QStringList& na
}
return out.absoluteFilePath();
};
- QString raw_storage = storageSuffix(system);
+ QString raw_storage = storageSuffix(runtimeContext);
if(isNative())
{
if (raw_storage.contains("${arch}"))
@@ -45,7 +80,7 @@ void Library::getApplicableFiles(OpSys system, QStringList& jar, QStringList& na
}
QList<NetAction::Ptr> Library::getDownloads(
- OpSys system,
+ const RuntimeContext & runtimeContext,
class HttpMetaCache* cache,
QStringList& failedLocalFiles,
const QString & overridePath
@@ -107,14 +142,14 @@ QList<NetAction::Ptr> Library::getDownloads(
return true;
};
- QString raw_storage = storageSuffix(system);
+ QString raw_storage = storageSuffix(runtimeContext);
if(m_mojangDownloads)
{
if(isNative())
{
- if(m_nativeClassifiers.contains(system))
+ auto nativeClassifier = getCompatibleNative(runtimeContext);
+ if(!nativeClassifier.isNull())
{
- auto nativeClassifier = m_nativeClassifiers[system];
if(nativeClassifier.contains("${arch}"))
{
auto nat32Classifier = nativeClassifier;
@@ -203,7 +238,7 @@ QList<NetAction::Ptr> Library::getDownloads(
return out;
}
-bool Library::isActive() const
+bool Library::isActive(const RuntimeContext & runtimeContext) const
{
bool result = true;
if (m_rules.empty())
@@ -215,7 +250,7 @@ bool Library::isActive() const
RuleAction ruleResult = Disallow;
for (auto rule : m_rules)
{
- RuleAction temp = rule->apply(this);
+ RuleAction temp = rule->apply(this, runtimeContext);
if (temp != Defer)
ruleResult = temp;
}
@@ -223,7 +258,7 @@ bool Library::isActive() const
}
if (isNative())
{
- result = result && m_nativeClassifiers.contains(currentSystem);
+ result = result && !getCompatibleNative(runtimeContext).isNull();
}
return result;
}
@@ -238,6 +273,19 @@ bool Library::isAlwaysStale() const
return m_hint == "always-stale";
}
+QString Library::getCompatibleNative(const RuntimeContext & runtimeContext) const {
+ // try to match precise classifier "[os]-[arch]"
+ auto entry = m_nativeClassifiers.constFind(runtimeContext.getClassifier());
+ // try to match imprecise classifier on legacy architectures "[os]"
+ if (entry == m_nativeClassifiers.constEnd() && runtimeContext.isLegacyArch())
+ entry = m_nativeClassifiers.constFind(runtimeContext.system);
+
+ if (entry == m_nativeClassifiers.constEnd())
+ return QString();
+
+ return entry.value();
+}
+
void Library::setStoragePrefix(QString prefix)
{
m_storagePrefix = prefix;
@@ -257,7 +305,7 @@ QString Library::storagePrefix() const
return m_storagePrefix;
}
-QString Library::filename(OpSys system) const
+QString Library::filename(const RuntimeContext & runtimeContext) const
{
if(!m_filename.isEmpty())
{
@@ -271,9 +319,10 @@ QString Library::filename(OpSys system) const
// otherwise native, override classifiers. Mojang HACK!
GradleSpecifier nativeSpec = m_name;
- if (m_nativeClassifiers.contains(system))
+ QString nativeClassifier = getCompatibleNative(runtimeContext);
+ if (!nativeClassifier.isNull())
{
- nativeSpec.setClassifier(m_nativeClassifiers[system]);
+ nativeSpec.setClassifier(nativeClassifier);
}
else
{
@@ -282,14 +331,14 @@ QString Library::filename(OpSys system) const
return nativeSpec.getFileName();
}
-QString Library::displayName(OpSys system) const
+QString Library::displayName(const RuntimeContext & runtimeContext) const
{
if(!m_displayname.isEmpty())
return m_displayname;
- return filename(system);
+ return filename(runtimeContext);
}
-QString Library::storageSuffix(OpSys system) const
+QString Library::storageSuffix(const RuntimeContext & runtimeContext) const
{
// non-native? use only the gradle specifier
if (!isNative())
@@ -299,9 +348,10 @@ QString Library::storageSuffix(OpSys system) const
// otherwise native, override classifiers. Mojang HACK!
GradleSpecifier nativeSpec = m_name;
- if (m_nativeClassifiers.contains(system))
+ QString nativeClassifier = getCompatibleNative(runtimeContext);
+ if (!nativeClassifier.isNull())
{
- nativeSpec.setClassifier(m_nativeClassifiers[system]);
+ nativeSpec.setClassifier(nativeClassifier);
}
else
{
diff --git a/launcher/minecraft/Library.h b/launcher/minecraft/Library.h
index 0740a7ca..950aec9d 100644
--- a/launcher/minecraft/Library.h
+++ b/launcher/minecraft/Library.h
@@ -1,8 +1,44 @@
+// 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 <net/NetAction.h>
#include <QPair>
#include <QList>
+#include <QString>
#include <QStringList>
#include <QMap>
#include <QDir>
@@ -10,9 +46,9 @@
#include <memory>
#include "Rule.h"
-#include "minecraft/OpSys.h"
#include "GradleSpecifier.h"
#include "MojangDownloadInfo.h"
+#include "RuntimeContext.h"
class Library;
class MinecraftInstance;
@@ -98,7 +134,7 @@ public: /* methods */
m_repositoryURL = base_url;
}
- void getApplicableFiles(OpSys system, QStringList & jar, QStringList & native,
+ void getApplicableFiles(const RuntimeContext & runtimeContext, QStringList & jar, QStringList & native,
QStringList & native32, QStringList & native64, const QString & overridePath) const;
void setAbsoluteUrl(const QString &absolute_url)
@@ -112,7 +148,7 @@ public: /* methods */
}
/// Get the file name of the library
- QString filename(OpSys system) const;
+ QString filename(const RuntimeContext & runtimeContext) const;
// DEPRECATED: set a display name, used by jar mods only
void setDisplayName(const QString & displayName)
@@ -121,7 +157,7 @@ public: /* methods */
}
/// Get the file name of the library
- QString displayName(OpSys system) const;
+ QString displayName(const RuntimeContext & runtimeContext) const;
void setMojangDownloadInfo(MojangLibraryDownloadInfo::Ptr info)
{
@@ -140,7 +176,7 @@ public: /* methods */
}
/// Returns true if the library should be loaded (or extracted, in case of natives)
- bool isActive() const;
+ bool isActive(const RuntimeContext & runtimeContext) const;
/// Returns true if the library is contained in an instance and false if it is shared
bool isLocal() const;
@@ -152,9 +188,11 @@ public: /* methods */
bool isForge() const;
// Get a list of downloads for this library
- QList<NetAction::Ptr> getDownloads(OpSys system, class HttpMetaCache * cache,
+ QList<NetAction::Ptr> getDownloads(const RuntimeContext & runtimeContext, class HttpMetaCache * cache,
QStringList & failedLocalFiles, const QString & overridePath) const;
+ QString getCompatibleNative(const RuntimeContext & runtimeContext) const;
+
private: /* methods */
/// the default storage prefix used by PolyMC
static QString defaultStoragePrefix();
@@ -163,7 +201,7 @@ private: /* methods */
QString storagePrefix() const;
/// Get the relative file path where the library should be saved
- QString storageSuffix(OpSys system) const;
+ QString storageSuffix(const RuntimeContext & runtimeContext) const;
QString hint() const
{
@@ -204,7 +242,7 @@ protected: /* data */
QStringList m_extractExcludes;
/// native suffixes per OS
- QMap<OpSys, QString> m_nativeClassifiers;
+ QMap<QString, QString> m_nativeClassifiers;
/// true if the library had a rules section (even empty)
bool applyRules = false;
diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp
index 62540c75..3a820951 100644
--- a/launcher/minecraft/MinecraftInstance.cpp
+++ b/launcher/minecraft/MinecraftInstance.cpp
@@ -147,6 +147,7 @@ void MinecraftInstance::loadSpecificSettings()
m_settings->registerPassthrough(global_settings->getSetting("JavaTimestamp"), javaOrLocation);
m_settings->registerPassthrough(global_settings->getSetting("JavaVersion"), javaOrLocation);
m_settings->registerPassthrough(global_settings->getSetting("JavaArchitecture"), javaOrLocation);
+ m_settings->registerPassthrough(global_settings->getSetting("JavaRealArchitecture"), javaOrLocation);
// Window Size
auto windowSetting = m_settings->registerSetting("OverrideWindow", false);
@@ -190,6 +191,13 @@ void MinecraftInstance::loadSpecificSettings()
qDebug() << "Instance-type specific settings were loaded!";
setSpecificSettingsLoaded(true);
+
+ updateRuntimeContext();
+}
+
+void MinecraftInstance::updateRuntimeContext()
+{
+ m_runtimeContext.updateFromInstanceSettings(m_settings);
}
QString MinecraftInstance::typeName() const
@@ -327,9 +335,8 @@ QDir MinecraftInstance::versionsPath() const
QStringList MinecraftInstance::getClassPath()
{
QStringList jars, nativeJars;
- auto javaArchitecture = settings()->get("JavaArchitecture").toString();
auto profile = m_components->getProfile();
- profile->getLibraryFiles(javaArchitecture, jars, nativeJars, getLocalLibraryPath(), binRoot());
+ profile->getLibraryFiles(runtimeContext(), jars, nativeJars, getLocalLibraryPath(), binRoot());
return jars;
}
@@ -342,9 +349,8 @@ QString MinecraftInstance::getMainClass() const
QStringList MinecraftInstance::getNativeJars()
{
QStringList jars, nativeJars;
- auto javaArchitecture = settings()->get("JavaArchitecture").toString();
auto profile = m_components->getProfile();
- profile->getLibraryFiles(javaArchitecture, jars, nativeJars, getLocalLibraryPath(), binRoot());
+ profile->getLibraryFiles(runtimeContext(), jars, nativeJars, getLocalLibraryPath(), binRoot());
return nativeJars;
}
@@ -368,7 +374,7 @@ QStringList MinecraftInstance::extraArguments()
for (auto agent : agents)
{
QStringList jar, temp1, temp2, temp3;
- agent->library()->getApplicableFiles(currentSystem, jar, temp1, temp2, temp3, getLocalLibraryPath());
+ agent->library()->getApplicableFiles(runtimeContext(), jar, temp1, temp2, temp3, getLocalLibraryPath());
list.append("-javaagent:"+jar[0]+(agent->argument().isEmpty() ? "" : "="+agent->argument()));
}
return list;
@@ -625,8 +631,7 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS
// libraries and class path.
{
QStringList jars, nativeJars;
- auto javaArchitecture = settings()->get("JavaArchitecture").toString();
- profile->getLibraryFiles(javaArchitecture, jars, nativeJars, getLocalLibraryPath(), binRoot());
+ profile->getLibraryFiles(runtimeContext(), jars, nativeJars, getLocalLibraryPath(), binRoot());
for(auto file: jars)
{
launchScript += "cp " + file + "\n";
@@ -682,8 +687,7 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr
{
out << "Libraries:";
QStringList jars, nativeJars;
- auto javaArchitecture = settings->get("JavaArchitecture").toString();
- profile->getLibraryFiles(javaArchitecture, jars, nativeJars, getLocalLibraryPath(), binRoot());
+ profile->getLibraryFiles(runtimeContext(), jars, nativeJars, getLocalLibraryPath(), binRoot());
auto printLibFile = [&](const QString & path)
{
QFileInfo info(path);
@@ -748,8 +752,8 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr
out << "Jar Mods:";
for(auto & jarmod: jarMods)
{
- auto displayname = jarmod->displayName(currentSystem);
- auto realname = jarmod->filename(currentSystem);
+ auto displayname = jarmod->displayName(runtimeContext());
+ auto realname = jarmod->filename(runtimeContext());
if(displayname != realname)
{
out << " " + displayname + " (" + realname + ")";
@@ -911,6 +915,7 @@ QString MinecraftInstance::getStatusbarDescription()
Task::Ptr MinecraftInstance::createUpdateTask(Net::Mode mode)
{
+ updateRuntimeContext();
switch (mode)
{
case Net::Mode::Offline:
@@ -927,6 +932,7 @@ Task::Ptr MinecraftInstance::createUpdateTask(Net::Mode mode)
shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
{
+ updateRuntimeContext();
// FIXME: get rid of shared_from_this ...
auto process = LaunchTask::create(std::dynamic_pointer_cast<MinecraftInstance>(shared_from_this()));
auto pptr = process.get();
@@ -1157,7 +1163,7 @@ QList<Mod*> MinecraftInstance::getJarMods() const
for (auto jarmod : profile->getJarMods())
{
QStringList jar, temp1, temp2, temp3;
- jarmod->getApplicableFiles(currentSystem, jar, temp1, temp2, temp3, jarmodsPath().absolutePath());
+ jarmod->getApplicableFiles(runtimeContext(), jar, temp1, temp2, temp3, jarmodsPath().absolutePath());
// QString filePath = jarmodsPath().absoluteFilePath(jarmod->filename(currentSystem));
mods.push_back(new Mod(QFileInfo(jar[0])));
}
diff --git a/launcher/minecraft/MinecraftInstance.h b/launcher/minecraft/MinecraftInstance.h
index fe39674a..1895d187 100644
--- a/launcher/minecraft/MinecraftInstance.h
+++ b/launcher/minecraft/MinecraftInstance.h
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#pragma once
#include "BaseInstance.h"
#include <java/JavaVersion.h>
@@ -72,6 +107,8 @@ public:
/** Returns whether the instance, with its version, has support for demo mode. */
[[nodiscard]] bool supportsDemo() const;
+ void updateRuntimeContext();
+
////// Profile management //////
std::shared_ptr<PackProfile> getPackProfile() const;
diff --git a/launcher/minecraft/MojangVersionFormat.cpp b/launcher/minecraft/MojangVersionFormat.cpp
index 94c58676..e00d2c6e 100644
--- a/launcher/minecraft/MojangVersionFormat.cpp
+++ b/launcher/minecraft/MojangVersionFormat.cpp
@@ -362,11 +362,8 @@ LibraryPtr MojangVersionFormat::libraryFromJson(ProblemContainer & problems, con
{
qWarning() << filename << "contains an invalid native (skipping)";
}
- OpSys opSys = OpSys_fromString(it.key());
- if (opSys != Os_Other)
- {
- out->m_nativeClassifiers[opSys] = it.value().toString();
- }
+ // FIXME: Skip unknown platforms
+ out->m_nativeClassifiers[it.key()] = it.value().toString();
}
}
if (libObj.contains("rules"))
@@ -395,7 +392,7 @@ QJsonObject MojangVersionFormat::libraryToJson(Library *library)
auto iter = library->m_nativeClassifiers.begin();
while (iter != library->m_nativeClassifiers.end())
{
- nativeList.insert(OpSys_toString(iter.key()), iter.value());
+ nativeList.insert(iter.key(), iter.value());
iter++;
}
libRoot.insert("natives", nativeList);
diff --git a/launcher/minecraft/OpSys.cpp b/launcher/minecraft/OpSys.cpp
deleted file mode 100644
index 093ec419..00000000
--- a/launcher/minecraft/OpSys.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/* 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 "OpSys.h"
-
-OpSys OpSys_fromString(QString name)
-{
- if (name == "freebsd")
- return Os_FreeBSD;
- if (name == "linux")
- return Os_Linux;
- if (name == "windows")
- return Os_Windows;
- if (name == "osx")
- return Os_OSX;
- return Os_Other;
-}
-
-QString OpSys_toString(OpSys name)
-{
- switch (name)
- {
- case Os_FreeBSD:
- return "freebsd";
- case Os_Linux:
- return "linux";
- case Os_OSX:
- return "osx";
- case Os_Windows:
- return "windows";
- default:
- return "other";
- }
-} \ No newline at end of file
diff --git a/launcher/minecraft/OpSys.h b/launcher/minecraft/OpSys.h
deleted file mode 100644
index 0936f817..00000000
--- a/launcher/minecraft/OpSys.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* 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>
-enum OpSys
-{
- Os_Windows,
- Os_FreeBSD,
- Os_Linux,
- Os_OSX,
- Os_Other
-};
-
-OpSys OpSys_fromString(QString);
-QString OpSys_toString(OpSys);
-
-#ifdef Q_OS_WIN32
- #define currentSystem Os_Windows
-#elif defined Q_OS_MAC
- #define currentSystem Os_OSX
-#elif defined Q_OS_FREEBSD
- #define currentSystem Os_FreeBSD
-#else
- #define currentSystem Os_Linux
-#endif
diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp
index 5e76b892..1618458f 100644
--- a/launcher/minecraft/PackProfile.cpp
+++ b/launcher/minecraft/PackProfile.cpp
@@ -273,6 +273,11 @@ void PackProfile::scheduleSave()
d->m_saveTimer.start();
}
+RuntimeContext PackProfile::runtimeContext()
+{
+ return d->m_instance->runtimeContext();
+}
+
QString PackProfile::componentsFilePath() const
{
return FS::PathCombine(d->m_instance->instanceRoot(), "mmc-pack.json");
@@ -784,7 +789,7 @@ bool PackProfile::removeComponent_internal(ComponentPtr patch)
return true;
}
QStringList jar, temp1, temp2, temp3;
- jarMod->getApplicableFiles(currentSystem, jar, temp1, temp2, temp3, d->m_instance->jarmodsPath().absolutePath());
+ jarMod->getApplicableFiles(d->m_instance->runtimeContext(), jar, temp1, temp2, temp3, d->m_instance->jarmodsPath().absolutePath());
QFileInfo finfo (jar[0]);
if(finfo.exists())
{
diff --git a/launcher/minecraft/PackProfile.h b/launcher/minecraft/PackProfile.h
index 918e7f7a..807511a2 100644
--- a/launcher/minecraft/PackProfile.h
+++ b/launcher/minecraft/PackProfile.h
@@ -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
@@ -104,6 +124,9 @@ public:
/// if there is a save scheduled, do it now.
void saveNow();
+ /// helper method, returns RuntimeContext of instance
+ RuntimeContext runtimeContext();
+
signals:
void minecraftChanged();
diff --git a/launcher/minecraft/Rule.cpp b/launcher/minecraft/Rule.cpp
index af2861e3..ff3d75f2 100644
--- a/launcher/minecraft/Rule.cpp
+++ b/launcher/minecraft/Rule.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#include <QJsonObject>
@@ -60,10 +80,10 @@ QList<std::shared_ptr<Rule>> rulesFromJsonV4(const QJsonObject &objectWithRules)
auto osNameVal = osObj.value("name");
if (!osNameVal.isString())
continue;
- OpSys requiredOs = OpSys_fromString(osNameVal.toString());
+ QString osName = osNameVal.toString();
QString versionRegex = osObj.value("version").toString();
// add a new OS rule
- rules.append(OsRule::create(action, requiredOs, versionRegex));
+ rules.append(OsRule::create(action, osName, versionRegex));
}
return rules;
}
@@ -81,7 +101,7 @@ QJsonObject OsRule::toJson()
ruleObj.insert("action", m_result == Allow ? QString("allow") : QString("disallow"));
QJsonObject osObj;
{
- osObj.insert("name", OpSys_toString(m_system));
+ osObj.insert("name", m_system);
if(!m_version_regexp.isEmpty())
{
osObj.insert("version", m_version_regexp);
diff --git a/launcher/minecraft/Rule.h b/launcher/minecraft/Rule.h
index 7aa34d96..236f9a87 100644
--- a/launcher/minecraft/Rule.h
+++ b/launcher/minecraft/Rule.h
@@ -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
@@ -19,7 +39,7 @@
#include <QList>
#include <QJsonObject>
#include <memory>
-#include "OpSys.h"
+#include "RuntimeContext.h"
class Library;
class Rule;
@@ -37,7 +57,7 @@ class Rule
{
protected:
RuleAction m_result;
- virtual bool applies(const Library *parent) = 0;
+ virtual bool applies(const Library *parent, const RuntimeContext & runtimeContext) = 0;
public:
Rule(RuleAction result) : m_result(result)
@@ -45,9 +65,9 @@ public:
}
virtual ~Rule() {};
virtual QJsonObject toJson() = 0;
- RuleAction apply(const Library *parent)
+ RuleAction apply(const Library *parent, const RuntimeContext & runtimeContext)
{
- if (applies(parent))
+ if (applies(parent, runtimeContext))
return m_result;
else
return Defer;
@@ -58,23 +78,23 @@ class OsRule : public Rule
{
private:
// the OS
- OpSys m_system;
+ QString m_system;
// the OS version regexp
QString m_version_regexp;
protected:
- virtual bool applies(const Library *)
+ virtual bool applies(const Library *, const RuntimeContext & runtimeContext)
{
- return (m_system == currentSystem);
+ return runtimeContext.classifierMatches(m_system);
}
- OsRule(RuleAction result, OpSys system, QString version_regexp)
+ OsRule(RuleAction result, QString system, QString version_regexp)
: Rule(result), m_system(system), m_version_regexp(version_regexp)
{
}
public:
virtual QJsonObject toJson();
- static std::shared_ptr<OsRule> create(RuleAction result, OpSys system,
+ static std::shared_ptr<OsRule> create(RuleAction result, QString system,
QString version_regexp)
{
return std::shared_ptr<OsRule>(new OsRule(result, system, version_regexp));
@@ -84,7 +104,7 @@ public:
class ImplicitRule : public Rule
{
protected:
- virtual bool applies(const Library *)
+ virtual bool applies(const Library *, const RuntimeContext & runtimeContext)
{
return true;
}
diff --git a/launcher/minecraft/VersionFile.cpp b/launcher/minecraft/VersionFile.cpp
index a9a0f7f4..76f41600 100644
--- a/launcher/minecraft/VersionFile.cpp
+++ b/launcher/minecraft/VersionFile.cpp
@@ -51,7 +51,7 @@ static bool isMinecraftVersion(const QString &uid)
return uid == "net.minecraft";
}
-void VersionFile::applyTo(LaunchProfile *profile)
+void VersionFile::applyTo(LaunchProfile *profile, const RuntimeContext & runtimeContext)
{
// Only real Minecraft can set those. Don't let anything override them.
if (isMinecraftVersion(uid))
@@ -77,15 +77,15 @@ void VersionFile::applyTo(LaunchProfile *profile)
for (auto library : libraries)
{
- profile->applyLibrary(library);
+ profile->applyLibrary(library, runtimeContext);
}
for (auto mavenFile : mavenFiles)
{
- profile->applyMavenFile(mavenFile);
+ profile->applyMavenFile(mavenFile, runtimeContext);
}
for (auto agent : agents)
{
- profile->applyAgent(agent);
+ profile->applyAgent(agent, runtimeContext);
}
profile->applyProblemSeverity(getProblemSeverity());
}
diff --git a/launcher/minecraft/VersionFile.h b/launcher/minecraft/VersionFile.h
index d4b29719..e1b62f6a 100644
--- a/launcher/minecraft/VersionFile.h
+++ b/launcher/minecraft/VersionFile.h
@@ -41,7 +41,6 @@
#include <QSet>
#include <memory>
-#include "minecraft/OpSys.h"
#include "minecraft/Rule.h"
#include "ProblemProvider.h"
#include "Library.h"
@@ -60,7 +59,7 @@ class VersionFile : public ProblemContainer
friend class MojangVersionFormat;
friend class OneSixVersionFormat;
public: /* methods */
- void applyTo(LaunchProfile* profile);
+ void applyTo(LaunchProfile* profile, const RuntimeContext & runtimeContext);
public: /* data */
/// PolyMC: order hint for this version file if no explicit order is set
diff --git a/launcher/minecraft/launch/ModMinecraftJar.cpp b/launcher/minecraft/launch/ModMinecraftJar.cpp
index 93de9d59..1d6eecf2 100644
--- a/launcher/minecraft/launch/ModMinecraftJar.cpp
+++ b/launcher/minecraft/launch/ModMinecraftJar.cpp
@@ -1,22 +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 "ModMinecraftJar.h"
#include "launch/LaunchTask.h"
#include "MMCZip.h"
-#include "minecraft/OpSys.h"
#include "FileSystem.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
@@ -50,7 +69,7 @@ void ModMinecraftJar::executeTask()
{
auto mainJar = profile->getMainJar();
QStringList jars, temp1, temp2, temp3, temp4;
- mainJar->getApplicableFiles(currentSystem, jars, temp1, temp2, temp3, m_inst->getLocalLibraryPath());
+ mainJar->getApplicableFiles(m_inst->runtimeContext(), jars, temp1, temp2, temp3, m_inst->getLocalLibraryPath());
auto sourceJarPath = jars[0];
if(!MMCZip::createModdedJar(sourceJarPath, finalJarPath, jarMods))
{
diff --git a/launcher/minecraft/launch/ScanModFolders.cpp b/launcher/minecraft/launch/ScanModFolders.cpp
index 2a0e21b3..bdffeadd 100644
--- a/launcher/minecraft/launch/ScanModFolders.cpp
+++ b/launcher/minecraft/launch/ScanModFolders.cpp
@@ -1,22 +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 "ScanModFolders.h"
#include "launch/LaunchTask.h"
#include "MMCZip.h"
-#include "minecraft/OpSys.h"
#include "FileSystem.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/mod/ModFolderModel.h"
diff --git a/launcher/minecraft/update/FoldersTask.cpp b/launcher/minecraft/update/FoldersTask.cpp
index 22768bd9..b9ee9d98 100644
--- a/launcher/minecraft/update/FoldersTask.cpp
+++ b/launcher/minecraft/update/FoldersTask.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#include "FoldersTask.h"
#include "minecraft/MinecraftInstance.h"
#include <QDir>
diff --git a/launcher/minecraft/update/LibrariesTask.cpp b/launcher/minecraft/update/LibrariesTask.cpp
index aa2bf407..3b129fe1 100644
--- a/launcher/minecraft/update/LibrariesTask.cpp
+++ b/launcher/minecraft/update/LibrariesTask.cpp
@@ -34,7 +34,7 @@ void LibrariesTask::executeTask()
emitFailed(tr("Null jar is specified in the metadata, aborting."));
return false;
}
- auto dls = lib->getDownloads(currentSystem, metacache.get(), errors, localPath);
+ auto dls = lib->getDownloads(inst->runtimeContext(), metacache.get(), errors, localPath);
for(auto dl : dls)
{
downloadJob->addNetAction(dl);
diff --git a/launcher/ui/pages/global/LauncherPage.ui b/launcher/ui/pages/global/LauncherPage.ui
index 645f7ef6..0d14f147 100644
--- a/launcher/ui/pages/global/LauncherPage.ui
+++ b/launcher/ui/pages/global/LauncherPage.ui
@@ -176,7 +176,7 @@
<item>
<widget class="QLabel" name="metadataWarningLabel">
<property name="text">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; color:#f5c211;&quot;&gt;Warning&lt;/span&gt;&lt;span style=&quot; color:#f5c211;&quot;&gt;: Disabling mod metadata may also disable some upcoming QoL features, such as mod updating!&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; color:#f5c211;&quot;&gt;Warning&lt;/span&gt;&lt;span style=&quot; color:#f5c211;&quot;&gt;: Disabling mod metadata may also disable some QoL features, such as mod updating!&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp
index 03910745..5da7f19f 100644
--- a/launcher/ui/pages/instance/InstanceSettingsPage.cpp
+++ b/launcher/ui/pages/instance/InstanceSettingsPage.cpp
@@ -274,6 +274,9 @@ void InstanceSettingsPage::applySettings()
{
m_settings->reset("JoinServerOnLaunchAddress");
}
+
+ // FIXME: This should probably be called by a signal instead
+ m_instance->updateRuntimeContext();
}
void InstanceSettingsPage::loadSettings()
diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp
index 029e2be0..8961fadd 100644
--- a/launcher/ui/pages/modplatform/ModModel.cpp
+++ b/launcher/ui/pages/modplatform/ModModel.cpp
@@ -62,11 +62,7 @@ auto ListModel::data(const QModelIndex& index, int role) const -> QVariant
}
case Qt::DecorationRole: {
if (m_logoMap.contains(pack.logoName)) {
- auto icon = m_logoMap.value(pack.logoName);
- // FIXME: This doesn't really belong here, but Qt doesn't offer a good way right now ;(
- auto icon_scaled = QIcon(icon.pixmap(48, 48).scaledToWidth(48));
-
- return icon_scaled;
+ return m_logoMap.value(pack.logoName);
}
QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
// un-const-ify this
@@ -175,7 +171,7 @@ void ListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallbac
void ListModel::requestLogo(QString logo, QString url)
{
- if (m_loadingLogos.contains(logo) || m_failedLogos.contains(logo)) {
+ if (m_loadingLogos.contains(logo) || m_failedLogos.contains(logo) || url.isEmpty()) {
return;
}
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp
index 614be434..fd7a3537 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp
@@ -41,6 +41,7 @@
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
#include "ui/dialogs/ModDownloadDialog.h"
+#include "ui/widgets/ProjectItem.h"
#include <QMessageBox>
@@ -74,31 +75,40 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian
}
Modrinth::Modpack pack = modpacks.at(pos);
- if (role == Qt::DisplayRole) {
- return pack.name;
- } else if (role == Qt::ToolTipRole) {
- if (pack.description.length() > 100) {
- // some magic to prevent to long tooltips and replace html linebreaks
- QString edit = pack.description.left(97);
- edit = edit.left(edit.lastIndexOf("<br>")).left(edit.lastIndexOf(" ")).append("...");
- return edit;
+ switch (role) {
+ case Qt::ToolTipRole: {
+ if (pack.description.length() > 100) {
+ // some magic to prevent to long tooltips and replace html linebreaks
+ QString edit = pack.description.left(97);
+ edit = edit.left(edit.lastIndexOf("<br>")).left(edit.lastIndexOf(" ")).append("...");
+ return edit;
+ }
+ return pack.description;
}
- return pack.description;
- } else if (role == Qt::DecorationRole) {
- if (m_logoMap.contains(pack.iconName)) {
- auto icon = m_logoMap.value(pack.iconName);
- // FIXME: This doesn't really belong here, but Qt doesn't offer a good way right now ;(
- auto icon_scaled = QIcon(icon.pixmap(48, 48).scaledToWidth(48));
-
- return icon_scaled;
+ case Qt::DecorationRole: {
+ if (m_logoMap.contains(pack.iconName))
+ return m_logoMap.value(pack.iconName);
+
+ QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
+ ((ModpackListModel*)this)->requestLogo(pack.iconName, pack.iconUrl.toString());
+ return icon;
+ }
+ case Qt::UserRole: {
+ QVariant v;
+ v.setValue(pack);
+ return v;
}
- QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
- ((ModpackListModel*)this)->requestLogo(pack.iconName, pack.iconUrl.toString());
- return icon;
- } else if (role == Qt::UserRole) {
- QVariant v;
- v.setValue(pack);
- return v;
+ case Qt::SizeHintRole:
+ return QSize(0, 58);
+ // Custom data
+ case UserDataTypes::TITLE:
+ return pack.name;
+ case UserDataTypes::DESCRIPTION:
+ return pack.description;
+ case UserDataTypes::SELECTED:
+ return false;
+ default:
+ break;
}
return {};
@@ -217,7 +227,7 @@ void ModpackListModel::getLogo(const QString& logo, const QString& logoUrl, Logo
void ModpackListModel::requestLogo(QString logo, QString url)
{
- if (m_loadingLogos.contains(logo) || m_failedLogos.contains(logo)) {
+ if (m_loadingLogos.contains(logo) || m_failedLogos.contains(logo) || url.isEmpty()) {
return;
}
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp
index 16fec82c..cea6cdee 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp
@@ -43,6 +43,8 @@
#include "InstanceImportTask.h"
#include "Json.h"
+#include "ui/widgets/ProjectItem.h"
+
#include <HoeDown.h>
#include <QComboBox>
@@ -70,6 +72,8 @@ ModrinthPage::ModrinthPage(NewInstanceDialog* dialog, QWidget* parent) : QWidget
connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, SLOT(triggerSearch()));
connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthPage::onSelectionChanged);
connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &ModrinthPage::onVersionSelectionChanged);
+
+ ui->packView->setItemDelegate(new ProjectItemDelegate(this));
}
ModrinthPage::~ModrinthPage()
diff --git a/launcher/ui/themes/BrightTheme.cpp b/launcher/ui/themes/BrightTheme.cpp
index 7469edfc..696ffdfb 100644
--- a/launcher/ui/themes/BrightTheme.cpp
+++ b/launcher/ui/themes/BrightTheme.cpp
@@ -20,19 +20,19 @@ bool BrightTheme::hasColorScheme()
QPalette BrightTheme::colorScheme()
{
QPalette brightPalette;
- brightPalette.setColor(QPalette::Window, QColor(239,240,241));
- brightPalette.setColor(QPalette::WindowText, QColor(49,54,59));
- brightPalette.setColor(QPalette::Base, QColor(252,252,252));
- brightPalette.setColor(QPalette::AlternateBase, QColor(239,240,241));
- brightPalette.setColor(QPalette::ToolTipBase, QColor(49,54,59));
- brightPalette.setColor(QPalette::ToolTipText, QColor(239,240,241));
- brightPalette.setColor(QPalette::Text, QColor(49,54,59));
- brightPalette.setColor(QPalette::Button, QColor(239,240,241));
- brightPalette.setColor(QPalette::ButtonText, QColor(49,54,59));
+ brightPalette.setColor(QPalette::Window, QColor(255,255,255));
+ brightPalette.setColor(QPalette::WindowText, QColor(17,17,17));
+ brightPalette.setColor(QPalette::Base, QColor(250,250,250));
+ brightPalette.setColor(QPalette::AlternateBase, QColor(240,240,240));
+ brightPalette.setColor(QPalette::ToolTipBase, QColor(17,17,17));
+ brightPalette.setColor(QPalette::ToolTipText, QColor(255,255,255));
+ brightPalette.setColor(QPalette::Text, Qt::black);
+ brightPalette.setColor(QPalette::Button, QColor(249,249,249));
+ brightPalette.setColor(QPalette::ButtonText, Qt::black);
brightPalette.setColor(QPalette::BrightText, Qt::red);
- brightPalette.setColor(QPalette::Link, QColor(41, 128, 185));
- brightPalette.setColor(QPalette::Highlight, QColor(61, 174, 233));
- brightPalette.setColor(QPalette::HighlightedText, QColor(239,240,241));
+ brightPalette.setColor(QPalette::Link, QColor(37,137,164));
+ brightPalette.setColor(QPalette::Highlight, QColor(137,207,84));
+ brightPalette.setColor(QPalette::HighlightedText, Qt::black);
return fadeInactive(brightPalette, fadeAmount(), fadeColor());
}
@@ -43,7 +43,7 @@ double BrightTheme::fadeAmount()
QColor BrightTheme::fadeColor()
{
- return QColor(239,240,241);
+ return QColor(255,255,255);
}
bool BrightTheme::hasStyleSheet()
diff --git a/launcher/ui/themes/DarkTheme.cpp b/launcher/ui/themes/DarkTheme.cpp
index c2a6a8df..07a2efd2 100644
--- a/launcher/ui/themes/DarkTheme.cpp
+++ b/launcher/ui/themes/DarkTheme.cpp
@@ -20,18 +20,18 @@ bool DarkTheme::hasColorScheme()
QPalette DarkTheme::colorScheme()
{
QPalette darkPalette;
- darkPalette.setColor(QPalette::Window, QColor(49,54,59));
+ darkPalette.setColor(QPalette::Window, QColor(49,49,49));
darkPalette.setColor(QPalette::WindowText, Qt::white);
- darkPalette.setColor(QPalette::Base, QColor(35,38,41));
- darkPalette.setColor(QPalette::AlternateBase, QColor(49,54,59));
+ darkPalette.setColor(QPalette::Base, QColor(34,34,34));
+ darkPalette.setColor(QPalette::AlternateBase, QColor(42,42,42));
darkPalette.setColor(QPalette::ToolTipBase, Qt::white);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
- darkPalette.setColor(QPalette::Button, QColor(49,54,59));
+ darkPalette.setColor(QPalette::Button, QColor(48,48,48));
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::BrightText, Qt::red);
- darkPalette.setColor(QPalette::Link, QColor(42, 130, 218));
- darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218));
+ darkPalette.setColor(QPalette::Link, QColor(47,163,198));
+ darkPalette.setColor(QPalette::Highlight, QColor(145,205,92));
darkPalette.setColor(QPalette::HighlightedText, Qt::black);
darkPalette.setColor(QPalette::PlaceholderText, Qt::darkGray);
return fadeInactive(darkPalette, fadeAmount(), fadeColor());
@@ -44,7 +44,7 @@ double DarkTheme::fadeAmount()
QColor DarkTheme::fadeColor()
{
- return QColor(49,54,59);
+ return QColor(49,49,49);
}
bool DarkTheme::hasStyleSheet()
diff --git a/launcher/ui/widgets/InfoFrame.cpp b/launcher/ui/widgets/InfoFrame.cpp
index f78dbe16..fdc581b4 100644
--- a/launcher/ui/widgets/InfoFrame.cpp
+++ b/launcher/ui/widgets/InfoFrame.cpp
@@ -97,14 +97,6 @@ void InfoFrame::updateWithResource(const Resource& resource)
setImage();
}
-// https://www.sportskeeda.com/minecraft-wiki/color-codes
-static const QMap<QChar, QString> s_value_to_color = {
- {'0', "#000000"}, {'1', "#0000AA"}, {'2', "#00AA00"}, {'3', "#00AAAA"}, {'4', "#AA0000"},
- {'5', "#AA00AA"}, {'6', "#FFAA00"}, {'7', "#AAAAAA"}, {'8', "#555555"}, {'9', "#5555FF"},
- {'a', "#55FF55"}, {'b', "#55FFFF"}, {'c', "#FF5555"}, {'d', "#FF55FF"}, {'e', "#FFFF55"},
- {'f', "#FFFFFF"}
-};
-
QString InfoFrame::renderColorCodes(QString input) {
// We have to manually set the colors for use.
//
@@ -113,32 +105,53 @@ QString InfoFrame::renderColorCodes(QString input) {
// We traverse the description and, when one of those is found, we create
// a span element with that color set.
//
- // TODO: Make the same logic for font formatting too.
// TODO: Wrap links inside <a> tags
+ // https://minecraft.fandom.com/wiki/Formatting_codes#Color_codes
+ const QMap<QChar, QString> color_codes_map = {
+ {'0', "#000000"}, {'1', "#0000AA"}, {'2', "#00AA00"}, {'3', "#00AAAA"}, {'4', "#AA0000"},
+ {'5', "#AA00AA"}, {'6', "#FFAA00"}, {'7', "#AAAAAA"}, {'8', "#555555"}, {'9', "#5555FF"},
+ {'a', "#55FF55"}, {'b', "#55FFFF"}, {'c', "#FF5555"}, {'d', "#FF55FF"}, {'e', "#FFFF55"},
+ {'f', "#FFFFFF"}
+ };
+ // https://minecraft.fandom.com/wiki/Formatting_codes#Formatting_codes
+ const QMap<QChar, QString> formatting_codes_map = {
+ {'l', "b"}, {'m', "s"}, {'n', "u"}, {'o', "i"}
+ };
+
QString html("<html>");
- bool in_div = false;
+ QList<QString> tags{};
auto it = input.constBegin();
while (it != input.constEnd()) {
- if (*it == u'§') {
- if (in_div)
- html += "</span>";
-
- auto const& num = *(++it);
- html += QString("<span style=\"color: %1;\">").arg(s_value_to_color.constFind(num).value());
+ // is current char § and is there a following char
+ if (*it == u'§' && (it + 1) != input.constEnd()) {
+ auto const& code = *(++it); // incrementing here!
- in_div = true;
+ auto const color_entry = color_codes_map.constFind(code);
+ auto const tag_entry = formatting_codes_map.constFind(code);
- it++;
+ if (color_entry != color_codes_map.constEnd()) { // color code
+ html += QString("<span style=\"color: %1;\">").arg(color_entry.value());
+ tags << "span";
+ } else if (tag_entry != formatting_codes_map.constEnd()) { // formatting code
+ html += QString("<%1>").arg(tag_entry.value());
+ tags << tag_entry.value();
+ } else if (code == 'r') { // reset all formatting
+ while (!tags.isEmpty()) {
+ html += QString("</%1>").arg(tags.takeLast());
+ }
+ } else { // pass unknown codes through
+ html += QString("§%1").arg(code);
+ }
+ } else {
+ html += *it;
}
-
- html += *it;
it++;
}
-
- if (in_div)
- html += "</span>";
+ while (!tags.isEmpty()) {
+ html += QString("</%1>").arg(tags.takeLast());
+ }
html += "</html>";
html.replace("\n", "<br>");
@@ -147,14 +160,14 @@ QString InfoFrame::renderColorCodes(QString input) {
void InfoFrame::updateWithResourcePack(ResourcePack& resource_pack)
{
- setName(resource_pack.name());
+ setName(renderColorCodes(resource_pack.name()));
setDescription(renderColorCodes(resource_pack.description()));
setImage(resource_pack.image({64, 64}));
}
void InfoFrame::updateWithTexturePack(TexturePack& texture_pack)
{
- setName(texture_pack.name());
+ setName(renderColorCodes(texture_pack.name()));
setDescription(renderColorCodes(texture_pack.description()));
setImage(texture_pack.image({64, 64}));
}
diff --git a/launcher/ui/widgets/ProjectItem.cpp b/launcher/ui/widgets/ProjectItem.cpp
index 56ae35fb..01be88d9 100644
--- a/launcher/ui/widgets/ProjectItem.cpp
+++ b/launcher/ui/widgets/ProjectItem.cpp
@@ -14,9 +14,7 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o
QStyleOptionViewItem opt(option);
initStyleOption(&opt, index);
- auto& rect = opt.rect;
- auto icon_width = rect.height(), icon_height = rect.height();
- auto remaining_width = rect.width() - icon_width;
+ auto rect = opt.rect;
if (opt.state & QStyle::State_Selected) {
painter->fillRect(rect, opt.palette.highlight());
@@ -25,11 +23,34 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o
painter->fillRect(rect, opt.palette.window());
}
- { // Icon painting
- // Square-sized, occupying the left portion
- opt.icon.paint(painter, rect.x(), rect.y(), icon_width, icon_height);
+ // The default icon size will be a square (and height is usually the lower value).
+ auto icon_width = rect.height(), icon_height = rect.height();
+ int icon_x_margin = (rect.height() - icon_width) / 2;
+ int icon_y_margin = (rect.height() - icon_height) / 2;
+
+ if (!opt.icon.isNull()) { // Icon painting
+ {
+ auto icon_size = opt.decorationSize;
+ icon_width = icon_size.width();
+ icon_height = icon_size.height();
+
+ icon_x_margin = (rect.height() - icon_width) / 2;
+ icon_y_margin = (rect.height() - icon_height) / 2;
+ }
+
+ // Centralize icon with a margin to separate from the other elements
+ int x = rect.x() + icon_x_margin;
+ int y = rect.y() + icon_y_margin;
+
+ // Prevent 'scaling null pixmap' warnings
+ if (icon_width > 0 && icon_height > 0)
+ opt.icon.paint(painter, x, y, icon_width, icon_height);
}
+ // Change the rect so that funther painting is easier
+ auto remaining_width = rect.width() - icon_width - 2 * icon_x_margin;
+ rect.setRect(rect.x() + icon_width + 2 * icon_x_margin, rect.y(), remaining_width, rect.height());
+
{ // Title painting
auto title = index.data(UserDataTypes::TITLE).toString();
@@ -46,7 +67,7 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o
painter->setFont(font);
// On the top, aligned to the left after the icon
- painter->drawText(rect.x() + icon_width, rect.y() + QFontMetrics(font).height(), title);
+ painter->drawText(rect.x(), rect.y() + QFontMetrics(font).height(), title);
painter->restore();
}
@@ -70,7 +91,7 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o
}
// On the bottom, aligned to the left after the icon, and featuring at most two lines of text (with some margin space to spare)
- painter->drawText(rect.x() + icon_width, rect.y() + rect.height() - 2.2 * opt.fontMetrics.height(), remaining_width,
+ painter->drawText(rect.x(), rect.y() + rect.height() - 2.2 * opt.fontMetrics.height(), remaining_width,
2 * opt.fontMetrics.height(), Qt::TextWordWrap, description);
}