Compare commits
49 Commits
develop
...
release-5.
Author | SHA1 | Date | |
---|---|---|---|
|
790e077ca8 | ||
|
10ac6cb266 | ||
|
4c9859b16e | ||
|
4b2c7a8a64 | ||
|
0120d170b7 | ||
|
79617d0c50 | ||
|
6e58635bfb | ||
|
3aee1d60d8 | ||
|
a1fbf2b137 | ||
|
0b98a0884e | ||
|
1582bb57ed | ||
|
d8044ababe | ||
|
32b526b729 | ||
|
7f6515dbe4 | ||
|
a39390b8b4 | ||
|
63a3dd1919 | ||
|
7a5a4de6ea | ||
|
664d4e701e | ||
|
a4ba8d8288 | ||
|
392bf7a97b | ||
|
34687049b1 | ||
|
9337ec6706 | ||
|
5bcb6962c4 | ||
|
0617b43190 | ||
|
ed28234cfb | ||
|
9c4455ca03 | ||
|
9ec7837275 | ||
|
549b5a6488 | ||
|
2652f37453 | ||
|
0eaff22145 | ||
|
2f5393b9d0 | ||
|
e28480a8e4 | ||
|
fcef6321fc | ||
|
35e792c5de | ||
|
c08b632b51 | ||
|
cac800bfd8 | ||
|
2eb8173951 | ||
|
75abf2c124 | ||
|
d40a18d6c5 | ||
|
a74fdc588c | ||
|
25b0ec6eff | ||
|
04e8982d33 | ||
|
58bd449db8 | ||
|
c984e9b5d6 | ||
|
ddd319369a | ||
|
de3c336213 | ||
|
6e94e9bff1 | ||
|
93b8d9e454 | ||
|
6d46081864 |
16
.github/workflows/build.yml
vendored
@ -30,12 +30,12 @@ jobs:
|
|||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
name: "Windows-Legacy"
|
name: "Windows-Legacy"
|
||||||
msystem: mingw32
|
msystem: clang32
|
||||||
qt_ver: 5
|
qt_ver: 5
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
name: "Windows"
|
name: "Windows"
|
||||||
msystem: mingw32
|
msystem: clang64
|
||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
|
|
||||||
- os: macos-12
|
- os: macos-12
|
||||||
@ -89,6 +89,7 @@ jobs:
|
|||||||
update: true
|
update: true
|
||||||
install: >-
|
install: >-
|
||||||
git
|
git
|
||||||
|
mingw-w64-x86_64-binutils
|
||||||
pacboy: >-
|
pacboy: >-
|
||||||
toolchain:p
|
toolchain:p
|
||||||
cmake:p
|
cmake:p
|
||||||
@ -99,12 +100,11 @@ jobs:
|
|||||||
qt${{ matrix.qt_ver }}-imageformats:p
|
qt${{ matrix.qt_ver }}-imageformats:p
|
||||||
quazip-qt${{ matrix.qt_ver }}:p
|
quazip-qt${{ matrix.qt_ver }}:p
|
||||||
ccache:p
|
ccache:p
|
||||||
nsis:p
|
|
||||||
${{ matrix.qt_ver == 6 && 'qt6-5compat:p' || '' }}
|
${{ matrix.qt_ver == 6 && 'qt6-5compat:p' || '' }}
|
||||||
|
|
||||||
- name: Setup ccache
|
- name: Setup ccache
|
||||||
if: runner.os != 'Windows' && inputs.build_type == 'Debug'
|
if: runner.os != 'Windows' && inputs.build_type == 'Debug'
|
||||||
uses: hendrikmuhs/ccache-action@v1.2.1
|
uses: hendrikmuhs/ccache-action@v1.2.3
|
||||||
with:
|
with:
|
||||||
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}
|
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Retrieve ccache cache (Windows)
|
- name: Retrieve ccache cache (Windows)
|
||||||
if: runner.os == 'Windows' && inputs.build_type == 'Debug'
|
if: runner.os == 'Windows' && inputs.build_type == 'Debug'
|
||||||
uses: actions/cache@v3.0.2
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: '${{ github.workspace }}\.ccache'
|
path: '${{ github.workspace }}\.ccache'
|
||||||
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}
|
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}
|
||||||
@ -194,7 +194,7 @@ jobs:
|
|||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
run: |
|
run: |
|
||||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -G Ninja
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OBJDUMP=/mingw64/bin/objdump.exe -G Ninja
|
||||||
|
|
||||||
- name: Configure CMake (Linux)
|
- name: Configure CMake (Linux)
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
@ -251,6 +251,7 @@ jobs:
|
|||||||
cd ${{ env.INSTALL_DIR }}
|
cd ${{ env.INSTALL_DIR }}
|
||||||
chmod +x "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
chmod +x "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
||||||
sudo codesign --sign - --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
sudo codesign --sign - --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
||||||
|
mv "PrismLauncher.app" "Prism Launcher.app"
|
||||||
tar -czf ../PrismLauncher.tar.gz *
|
tar -czf ../PrismLauncher.tar.gz *
|
||||||
|
|
||||||
- name: Make Sparkle signature (macOS)
|
- name: Make Sparkle signature (macOS)
|
||||||
@ -280,7 +281,7 @@ jobs:
|
|||||||
|
|
||||||
cd ${{ env.INSTALL_DIR }}
|
cd ${{ env.INSTALL_DIR }}
|
||||||
if [ "${{ matrix.qt_ver }}" == "5" ]; then
|
if [ "${{ matrix.qt_ver }}" == "5" ]; then
|
||||||
cp /mingw32/bin/libcrypto-1_1.dll /mingw32/bin/libssl-1_1.dll ./
|
cp /clang32/bin/libcrypto-1_1.dll /clang32/bin/libssl-1_1.dll ./
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Package (Windows, portable)
|
- name: Package (Windows, portable)
|
||||||
@ -292,7 +293,6 @@ jobs:
|
|||||||
|
|
||||||
- name: Package (Windows, installer)
|
- name: Package (Windows, installer)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
shell: msys2 {0}
|
|
||||||
run: |
|
run: |
|
||||||
cd ${{ env.INSTALL_DIR }}
|
cd ${{ env.INSTALL_DIR }}
|
||||||
makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/program_info/win_install.nsi"
|
makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/program_info/win_install.nsi"
|
||||||
|
2
.github/workflows/trigger_release.yml
vendored
@ -65,7 +65,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ github.ref }}
|
tag_name: ${{ github.ref }}
|
||||||
name: PrismLauncher ${{ env.VERSION }}
|
name: Prism Launcher ${{ env.VERSION }}
|
||||||
draft: true
|
draft: true
|
||||||
prerelease: false
|
prerelease: false
|
||||||
files: |
|
files: |
|
||||||
|
@ -34,6 +34,11 @@ set(CMAKE_C_STANDARD 11)
|
|||||||
include(GenerateExportHeader)
|
include(GenerateExportHeader)
|
||||||
set(CMAKE_CXX_FLAGS "-Wall -pedantic -fstack-protector-strong --param=ssp-buffer-size=4 ${CMAKE_CXX_FLAGS}")
|
set(CMAKE_CXX_FLAGS "-Wall -pedantic -fstack-protector-strong --param=ssp-buffer-size=4 ${CMAKE_CXX_FLAGS}")
|
||||||
|
|
||||||
|
# ATL's packlist needs more than the default 1 Mib stack on windows
|
||||||
|
if(WIN32)
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--stack,8388608 ${CMAKE_EXE_LINKER_FLAGS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Fix build with Qt 5.13
|
# Fix build with Qt 5.13
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y")
|
||||||
|
|
||||||
@ -71,13 +76,13 @@ endif()
|
|||||||
##################################### Set Application options #####################################
|
##################################### Set Application options #####################################
|
||||||
|
|
||||||
######## Set URLs ########
|
######## Set URLs ########
|
||||||
set(Launcher_NEWS_RSS_URL "https://prismlauncher.org/feed/feed.xml" CACHE STRING "URL to fetch PrismLauncher's news RSS feed from.")
|
set(Launcher_NEWS_RSS_URL "https://prismlauncher.org/feed/feed.xml" CACHE STRING "URL to fetch Prism Launcher's news RSS feed from.")
|
||||||
set(Launcher_NEWS_OPEN_URL "https://prismlauncher.org/news" CACHE STRING "URL that gets opened when the user clicks 'More News'")
|
set(Launcher_NEWS_OPEN_URL "https://prismlauncher.org/news" CACHE STRING "URL that gets opened when the user clicks 'More News'")
|
||||||
set(Launcher_HELP_URL "https://prismlauncher.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help")
|
set(Launcher_HELP_URL "https://prismlauncher.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help")
|
||||||
|
|
||||||
######## Set version numbers ########
|
######## Set version numbers ########
|
||||||
set(Launcher_VERSION_MAJOR 5)
|
set(Launcher_VERSION_MAJOR 5)
|
||||||
set(Launcher_VERSION_MINOR 0)
|
set(Launcher_VERSION_MINOR 2)
|
||||||
|
|
||||||
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}")
|
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}")
|
||||||
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.0.0")
|
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.0.0")
|
||||||
@ -222,14 +227,14 @@ if(UNIX AND APPLE)
|
|||||||
set(APPS "\${CMAKE_INSTALL_PREFIX}/${Launcher_Name}.app")
|
set(APPS "\${CMAKE_INSTALL_PREFIX}/${Launcher_Name}.app")
|
||||||
|
|
||||||
# Mac bundle settings
|
# Mac bundle settings
|
||||||
set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_Name}")
|
set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_DisplayName}")
|
||||||
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_Name}: A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.")
|
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_DisplayName}: A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.")
|
||||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.prismlauncher.${Launcher_Name}")
|
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.prismlauncher.${Launcher_Name}")
|
||||||
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_NAME}")
|
||||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}")
|
||||||
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}")
|
||||||
set(MACOSX_BUNDLE_ICON_FILE ${Launcher_Name}.icns)
|
set(MACOSX_BUNDLE_ICON_FILE ${Launcher_Name}.icns)
|
||||||
set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2021-2022 ${Launcher_Copyright}")
|
set(MACOSX_BUNDLE_COPYRIGHT "© 2022 ${Launcher_Copyright_Mac}")
|
||||||
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=")
|
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=")
|
||||||
set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml")
|
set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml")
|
||||||
|
|
||||||
@ -249,7 +254,7 @@ if(UNIX AND APPLE)
|
|||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
set(BINARY_DEST_DIR "bin")
|
set(BINARY_DEST_DIR "bin")
|
||||||
set(LIBRARY_DEST_DIR "lib${LIB_SUFFIX}")
|
set(LIBRARY_DEST_DIR "lib${LIB_SUFFIX}")
|
||||||
set(JARS_DEST_DIR "share/jars")
|
set(JARS_DEST_DIR "share/${Launcher_APP_BINARY_NAME}")
|
||||||
set(LAUNCHER_DESKTOP_DEST_DIR "share/applications" CACHE STRING "Path to the desktop file directory")
|
set(LAUNCHER_DESKTOP_DEST_DIR "share/applications" CACHE STRING "Path to the desktop file directory")
|
||||||
set(LAUNCHER_METAINFO_DEST_DIR "share/metainfo" CACHE STRING "Path to the metainfo directory")
|
set(LAUNCHER_METAINFO_DEST_DIR "share/metainfo" CACHE STRING "Path to the metainfo directory")
|
||||||
set(LAUNCHER_ICON_DEST_DIR "share/icons/hicolor/scalable/apps" CACHE STRING "Path to the scalable icon directory")
|
set(LAUNCHER_ICON_DEST_DIR "share/icons/hicolor/scalable/apps" CACHE STRING "Path to the scalable icon directory")
|
||||||
|
@ -42,12 +42,14 @@ Config::Config()
|
|||||||
{
|
{
|
||||||
// Name and copyright
|
// Name and copyright
|
||||||
LAUNCHER_NAME = "@Launcher_Name@";
|
LAUNCHER_NAME = "@Launcher_Name@";
|
||||||
|
LAUNCHER_APP_BINARY_NAME = "@Launcher_APP_BINARY_NAME@";
|
||||||
LAUNCHER_DISPLAYNAME = "@Launcher_DisplayName@";
|
LAUNCHER_DISPLAYNAME = "@Launcher_DisplayName@";
|
||||||
LAUNCHER_COPYRIGHT = "@Launcher_Copyright@";
|
LAUNCHER_COPYRIGHT = "@Launcher_Copyright@";
|
||||||
LAUNCHER_DOMAIN = "@Launcher_Domain@";
|
LAUNCHER_DOMAIN = "@Launcher_Domain@";
|
||||||
LAUNCHER_CONFIGFILE = "@Launcher_ConfigFile@";
|
LAUNCHER_CONFIGFILE = "@Launcher_ConfigFile@";
|
||||||
LAUNCHER_GIT = "@Launcher_Git@";
|
LAUNCHER_GIT = "@Launcher_Git@";
|
||||||
LAUNCHER_DESKTOPFILENAME = "@Launcher_DesktopFileName@";
|
LAUNCHER_DESKTOPFILENAME = "@Launcher_DesktopFileName@";
|
||||||
|
LAUNCHER_SVGFILENAME = "@Launcher_SVGFileName@";
|
||||||
|
|
||||||
USER_AGENT = "@Launcher_UserAgent@";
|
USER_AGENT = "@Launcher_UserAgent@";
|
||||||
USER_AGENT_UNCACHED = USER_AGENT + " (Uncached)";
|
USER_AGENT_UNCACHED = USER_AGENT + " (Uncached)";
|
||||||
|
@ -44,12 +44,14 @@ class Config {
|
|||||||
public:
|
public:
|
||||||
Config();
|
Config();
|
||||||
QString LAUNCHER_NAME;
|
QString LAUNCHER_NAME;
|
||||||
|
QString LAUNCHER_APP_BINARY_NAME;
|
||||||
QString LAUNCHER_DISPLAYNAME;
|
QString LAUNCHER_DISPLAYNAME;
|
||||||
QString LAUNCHER_COPYRIGHT;
|
QString LAUNCHER_COPYRIGHT;
|
||||||
QString LAUNCHER_DOMAIN;
|
QString LAUNCHER_DOMAIN;
|
||||||
QString LAUNCHER_CONFIGFILE;
|
QString LAUNCHER_CONFIGFILE;
|
||||||
QString LAUNCHER_GIT;
|
QString LAUNCHER_GIT;
|
||||||
QString LAUNCHER_DESKTOPFILENAME;
|
QString LAUNCHER_DESKTOPFILENAME;
|
||||||
|
QString LAUNCHER_SVGFILENAME;
|
||||||
|
|
||||||
/// The major version number.
|
/// The major version number.
|
||||||
int VERSION_MAJOR;
|
int VERSION_MAJOR;
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include "ui/WinDarkmode.h"
|
#include "ui/WinDarkmode.h"
|
||||||
|
#include <versionhelpers.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ui/setupwizard/SetupWizard.h"
|
#include "ui/setupwizard/SetupWizard.h"
|
||||||
@ -1124,15 +1125,6 @@ std::vector<ITheme *> Application::getValidApplicationThemes()
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Application::isFlatpak()
|
|
||||||
{
|
|
||||||
#ifdef Q_OS_LINUX
|
|
||||||
return QFile::exists("/.flatpak-info");
|
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::setApplicationTheme(const QString& name, bool initial)
|
void Application::setApplicationTheme(const QString& name, bool initial)
|
||||||
{
|
{
|
||||||
auto systemPalette = qApp->palette();
|
auto systemPalette = qApp->palette();
|
||||||
@ -1142,7 +1134,7 @@ void Application::setApplicationTheme(const QString& name, bool initial)
|
|||||||
auto & theme = (*themeIter).second;
|
auto & theme = (*themeIter).second;
|
||||||
theme->apply(initial);
|
theme->apply(initial);
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
if (m_mainWindow) {
|
if (m_mainWindow && IsWindows10OrGreater()) {
|
||||||
if (QString::compare(theme->id(), "dark") == 0) {
|
if (QString::compare(theme->id(), "dark") == 0) {
|
||||||
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), true);
|
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), true);
|
||||||
} else {
|
} else {
|
||||||
@ -1165,7 +1157,7 @@ void Application::setIconTheme(const QString& name)
|
|||||||
QIcon Application::getThemedIcon(const QString& name)
|
QIcon Application::getThemedIcon(const QString& name)
|
||||||
{
|
{
|
||||||
if(name == "logo") {
|
if(name == "logo") {
|
||||||
return QIcon(":/org.prismlauncher.PrismLauncher.svg"); // FIXME: Make this a BuildConfig variable
|
return QIcon(":/" + BuildConfig.LAUNCHER_SVGFILENAME);
|
||||||
}
|
}
|
||||||
return QIcon::fromTheme(name);
|
return QIcon::fromTheme(name);
|
||||||
}
|
}
|
||||||
@ -1383,10 +1375,13 @@ MainWindow* Application::showMainWindow(bool minimized)
|
|||||||
m_mainWindow->restoreState(QByteArray::fromBase64(APPLICATION->settings()->get("MainWindowState").toByteArray()));
|
m_mainWindow->restoreState(QByteArray::fromBase64(APPLICATION->settings()->get("MainWindowState").toByteArray()));
|
||||||
m_mainWindow->restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("MainWindowGeometry").toByteArray()));
|
m_mainWindow->restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("MainWindowGeometry").toByteArray()));
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
if (QString::compare(settings()->get("ApplicationTheme").toString(), "dark") == 0) {
|
if (IsWindows10OrGreater())
|
||||||
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), true);
|
{
|
||||||
} else {
|
if (QString::compare(settings()->get("ApplicationTheme").toString(), "dark") == 0) {
|
||||||
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), false);
|
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), true);
|
||||||
|
} else {
|
||||||
|
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if(minimized)
|
if(minimized)
|
||||||
@ -1571,7 +1566,7 @@ QString Application::getJarPath(QString jarFile)
|
|||||||
{
|
{
|
||||||
QStringList potentialPaths = {
|
QStringList potentialPaths = {
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
||||||
FS::PathCombine(m_rootPath, "share/jars"),
|
FS::PathCombine(m_rootPath, "share/" + BuildConfig.LAUNCHER_APP_BINARY_NAME),
|
||||||
#endif
|
#endif
|
||||||
FS::PathCombine(m_rootPath, "jars"),
|
FS::PathCombine(m_rootPath, "jars"),
|
||||||
FS::PathCombine(applicationDirPath(), "jars")
|
FS::PathCombine(applicationDirPath(), "jars")
|
||||||
|
@ -116,8 +116,6 @@ public:
|
|||||||
|
|
||||||
QIcon getThemedIcon(const QString& name);
|
QIcon getThemedIcon(const QString& name);
|
||||||
|
|
||||||
bool isFlatpak();
|
|
||||||
|
|
||||||
void setIconTheme(const QString& name);
|
void setIconTheme(const QString& name);
|
||||||
|
|
||||||
std::vector<ITheme *> getValidApplicationThemes();
|
std::vector<ITheme *> getValidApplicationThemes();
|
||||||
|
@ -17,13 +17,14 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "BaseVersion.h"
|
||||||
|
|
||||||
class MinecraftInstance;
|
class MinecraftInstance;
|
||||||
class QDir;
|
class QDir;
|
||||||
class QString;
|
class QString;
|
||||||
class QObject;
|
class QObject;
|
||||||
class Task;
|
class Task;
|
||||||
class BaseVersion;
|
class BaseVersion;
|
||||||
typedef std::shared_ptr<BaseVersion> BaseVersionPtr;
|
|
||||||
|
|
||||||
class BaseInstaller
|
class BaseInstaller
|
||||||
{
|
{
|
||||||
@ -35,7 +36,7 @@ public:
|
|||||||
virtual bool add(MinecraftInstance *to);
|
virtual bool add(MinecraftInstance *to);
|
||||||
virtual bool remove(MinecraftInstance *from);
|
virtual bool remove(MinecraftInstance *from);
|
||||||
|
|
||||||
virtual Task *createInstallTask(MinecraftInstance *instance, BaseVersionPtr version, QObject *parent) = 0;
|
virtual Task *createInstallTask(MinecraftInstance *instance, BaseVersion::Ptr version, QObject *parent) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual QString id() const = 0;
|
virtual QString id() const = 0;
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
class BaseVersion
|
class BaseVersion
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
using Ptr = std::shared_ptr<BaseVersion>;
|
||||||
virtual ~BaseVersion() {}
|
virtual ~BaseVersion() {}
|
||||||
/*!
|
/*!
|
||||||
* A string used to identify this version in config files.
|
* A string used to identify this version in config files.
|
||||||
@ -54,6 +55,4 @@ public:
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<BaseVersion> BaseVersionPtr;
|
Q_DECLARE_METATYPE(BaseVersion::Ptr)
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(BaseVersionPtr)
|
|
||||||
|
@ -40,20 +40,20 @@ BaseVersionList::BaseVersionList(QObject *parent) : QAbstractListModel(parent)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseVersionPtr BaseVersionList::findVersion(const QString &descriptor)
|
BaseVersion::Ptr BaseVersionList::findVersion(const QString &descriptor)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < count(); i++)
|
for (int i = 0; i < count(); i++)
|
||||||
{
|
{
|
||||||
if (at(i)->descriptor() == descriptor)
|
if (at(i)->descriptor() == descriptor)
|
||||||
return at(i);
|
return at(i);
|
||||||
}
|
}
|
||||||
return BaseVersionPtr();
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseVersionPtr BaseVersionList::getRecommended() const
|
BaseVersion::Ptr BaseVersionList::getRecommended() const
|
||||||
{
|
{
|
||||||
if (count() <= 0)
|
if (count() <= 0)
|
||||||
return BaseVersionPtr();
|
return nullptr;
|
||||||
else
|
else
|
||||||
return at(0);
|
return at(0);
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ QVariant BaseVersionList::data(const QModelIndex &index, int role) const
|
|||||||
if (index.row() > count())
|
if (index.row() > count())
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
BaseVersionPtr version = at(index.row());
|
BaseVersion::Ptr version = at(index.row());
|
||||||
|
|
||||||
switch (role)
|
switch (role)
|
||||||
{
|
{
|
||||||
|
@ -70,7 +70,7 @@ public:
|
|||||||
virtual bool isLoaded() = 0;
|
virtual bool isLoaded() = 0;
|
||||||
|
|
||||||
//! Gets the version at the given index.
|
//! Gets the version at the given index.
|
||||||
virtual const BaseVersionPtr at(int i) const = 0;
|
virtual const BaseVersion::Ptr at(int i) const = 0;
|
||||||
|
|
||||||
//! Returns the number of versions in the list.
|
//! Returns the number of versions in the list.
|
||||||
virtual int count() const = 0;
|
virtual int count() const = 0;
|
||||||
@ -90,13 +90,13 @@ public:
|
|||||||
* \return A const pointer to the version with the given descriptor. NULL if
|
* \return A const pointer to the version with the given descriptor. NULL if
|
||||||
* one doesn't exist.
|
* one doesn't exist.
|
||||||
*/
|
*/
|
||||||
virtual BaseVersionPtr findVersion(const QString &descriptor);
|
virtual BaseVersion::Ptr findVersion(const QString &descriptor);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Gets the recommended version from this list
|
* \brief Gets the recommended version from this list
|
||||||
* If the list doesn't support recommended versions, this works exactly as getLatestStable
|
* If the list doesn't support recommended versions, this works exactly as getLatestStable
|
||||||
*/
|
*/
|
||||||
virtual BaseVersionPtr getRecommended() const;
|
virtual BaseVersion::Ptr getRecommended() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Sorts the version list.
|
* Sorts the version list.
|
||||||
@ -117,5 +117,5 @@ slots:
|
|||||||
* then copies the versions and sets their parents correctly.
|
* then copies the versions and sets their parents correctly.
|
||||||
* \param versions List of versions whose parents should be set.
|
* \param versions List of versions whose parents should be set.
|
||||||
*/
|
*/
|
||||||
virtual void updateListData(QList<BaseVersionPtr> versions) = 0;
|
virtual void updateListData(QList<BaseVersion::Ptr> versions) = 0;
|
||||||
};
|
};
|
||||||
|
@ -24,8 +24,8 @@ set(CORE_SOURCES
|
|||||||
NullInstance.h
|
NullInstance.h
|
||||||
MMCZip.h
|
MMCZip.h
|
||||||
MMCZip.cpp
|
MMCZip.cpp
|
||||||
MMCStrings.h
|
StringUtils.h
|
||||||
MMCStrings.cpp
|
StringUtils.cpp
|
||||||
RuntimeContext.h
|
RuntimeContext.h
|
||||||
|
|
||||||
# Basic instance manipulation tasks (derived from InstanceTask)
|
# Basic instance manipulation tasks (derived from InstanceTask)
|
||||||
|
@ -119,7 +119,7 @@ bool openDirectory(const QString &path, bool ensureExists)
|
|||||||
return QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath()));
|
return QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath()));
|
||||||
};
|
};
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||||
if(!APPLICATION->isFlatpak())
|
if(!isFlatpak())
|
||||||
{
|
{
|
||||||
return IndirectOpen(f);
|
return IndirectOpen(f);
|
||||||
}
|
}
|
||||||
@ -140,7 +140,7 @@ bool openFile(const QString &path)
|
|||||||
return QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
return QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
||||||
};
|
};
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||||
if(!APPLICATION->isFlatpak())
|
if(!isFlatpak())
|
||||||
{
|
{
|
||||||
return IndirectOpen(f);
|
return IndirectOpen(f);
|
||||||
}
|
}
|
||||||
@ -158,7 +158,7 @@ bool openFile(const QString &application, const QString &path, const QString &wo
|
|||||||
qDebug() << "Opening file" << path << "using" << application;
|
qDebug() << "Opening file" << path << "using" << application;
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||||
// FIXME: the pid here is fake. So if something depends on it, it will likely misbehave
|
// FIXME: the pid here is fake. So if something depends on it, it will likely misbehave
|
||||||
if(!APPLICATION->isFlatpak())
|
if(!isFlatpak())
|
||||||
{
|
{
|
||||||
return IndirectOpen([&]()
|
return IndirectOpen([&]()
|
||||||
{
|
{
|
||||||
@ -178,7 +178,7 @@ bool run(const QString &application, const QStringList &args, const QString &wor
|
|||||||
{
|
{
|
||||||
qDebug() << "Running" << application << "with args" << args.join(' ');
|
qDebug() << "Running" << application << "with args" << args.join(' ');
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||||
if(!APPLICATION->isFlatpak())
|
if(!isFlatpak())
|
||||||
{
|
{
|
||||||
// FIXME: the pid here is fake. So if something depends on it, it will likely misbehave
|
// FIXME: the pid here is fake. So if something depends on it, it will likely misbehave
|
||||||
return IndirectOpen([&]()
|
return IndirectOpen([&]()
|
||||||
@ -203,7 +203,7 @@ bool openUrl(const QUrl &url)
|
|||||||
return QDesktopServices::openUrl(url);
|
return QDesktopServices::openUrl(url);
|
||||||
};
|
};
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||||
if(!APPLICATION->isFlatpak())
|
if(!isFlatpak())
|
||||||
{
|
{
|
||||||
return IndirectOpen(f);
|
return IndirectOpen(f);
|
||||||
}
|
}
|
||||||
@ -216,4 +216,13 @@ bool openUrl(const QUrl &url)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isFlatpak()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
return QFile::exists("/.flatpak-info");
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -33,4 +33,6 @@ namespace DesktopServices
|
|||||||
* Open the URL, most likely in a browser. Maybe.
|
* Open the URL, most likely in a browser. Maybe.
|
||||||
*/
|
*/
|
||||||
bool openUrl(const QUrl &url);
|
bool openUrl(const QUrl &url);
|
||||||
|
|
||||||
|
bool isFlatpak();
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,9 @@
|
|||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
|
#include "DesktopServices.h"
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
#include <objbase.h>
|
#include <objbase.h>
|
||||||
#include <objidl.h>
|
#include <objidl.h>
|
||||||
@ -78,22 +81,6 @@ namespace fs = std::filesystem;
|
|||||||
namespace fs = ghc::filesystem;
|
namespace fs = ghc::filesystem;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
|
||||||
|
|
||||||
std::wstring toStdString(QString s)
|
|
||||||
{
|
|
||||||
return s.toStdWString();
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
std::string toStdString(QString s)
|
|
||||||
{
|
|
||||||
return s.toStdString();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace FS {
|
namespace FS {
|
||||||
|
|
||||||
void ensureExists(const QDir& dir)
|
void ensureExists(const QDir& dir)
|
||||||
@ -182,6 +169,21 @@ bool copy::operator()(const QString& offset)
|
|||||||
if (!m_followSymlinks)
|
if (!m_followSymlinks)
|
||||||
opt |= copy_opts::copy_symlinks;
|
opt |= copy_opts::copy_symlinks;
|
||||||
|
|
||||||
|
// Function that'll do the actual copying
|
||||||
|
auto copy_file = [&](QString src_path, QString relative_dst_path) {
|
||||||
|
if (m_blacklist && m_blacklist->matches(relative_dst_path))
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto dst_path = PathCombine(dst, relative_dst_path);
|
||||||
|
ensureFilePathExists(dst_path);
|
||||||
|
|
||||||
|
fs::copy(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), opt, err);
|
||||||
|
if (err) {
|
||||||
|
qWarning() << "Failed to copy files:" << QString::fromStdString(err.message());
|
||||||
|
qDebug() << "Source file:" << src_path;
|
||||||
|
qDebug() << "Destination file:" << dst_path;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// We can't use copy_opts::recursive because we need to take into account the
|
// We can't use copy_opts::recursive because we need to take into account the
|
||||||
// blacklisted paths, so we iterate over the source directory, and if there's no blacklist
|
// blacklisted paths, so we iterate over the source directory, and if there's no blacklist
|
||||||
@ -193,20 +195,13 @@ bool copy::operator()(const QString& offset)
|
|||||||
auto src_path = source_it.next();
|
auto src_path = source_it.next();
|
||||||
auto relative_path = src_dir.relativeFilePath(src_path);
|
auto relative_path = src_dir.relativeFilePath(src_path);
|
||||||
|
|
||||||
if (m_blacklist && m_blacklist->matches(relative_path))
|
copy_file(src_path, relative_path);
|
||||||
continue;
|
|
||||||
|
|
||||||
auto dst_path = PathCombine(dst, relative_path);
|
|
||||||
ensureFilePathExists(dst_path);
|
|
||||||
|
|
||||||
fs::copy(toStdString(src_path), toStdString(dst_path), opt, err);
|
|
||||||
if (err) {
|
|
||||||
qWarning() << "Failed to copy files:" << QString::fromStdString(err.message());
|
|
||||||
qDebug() << "Source file:" << src_path;
|
|
||||||
qDebug() << "Destination file:" << dst_path;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the root src is not a directory, the previous iterator won't run.
|
||||||
|
if (!fs::is_directory(StringUtils::toStdString(src)))
|
||||||
|
copy_file(src, "");
|
||||||
|
|
||||||
return err.value() == 0;
|
return err.value() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +209,7 @@ bool deletePath(QString path)
|
|||||||
{
|
{
|
||||||
std::error_code err;
|
std::error_code err;
|
||||||
|
|
||||||
fs::remove_all(toStdString(path), err);
|
fs::remove_all(StringUtils::toStdString(path), err);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
qWarning() << "Failed to remove files:" << QString::fromStdString(err.message());
|
qWarning() << "Failed to remove files:" << QString::fromStdString(err.message());
|
||||||
@ -228,6 +223,9 @@ bool trash(QString path, QString *pathInTrash = nullptr)
|
|||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
|
// FIXME: Figure out trash in Flatpak. Qt seemingly doesn't use the Trash portal
|
||||||
|
if (DesktopServices::isFlatpak())
|
||||||
|
return false;
|
||||||
return QFile::moveToTrash(path, pathInTrash);
|
return QFile::moveToTrash(path, pathInTrash);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -401,7 +399,8 @@ bool overrideFolder(QString overwritten_path, QString override_path)
|
|||||||
std::error_code err;
|
std::error_code err;
|
||||||
fs::copy_options opt = copy_opts::recursive | copy_opts::overwrite_existing;
|
fs::copy_options opt = copy_opts::recursive | copy_opts::overwrite_existing;
|
||||||
|
|
||||||
fs::copy(toStdString(override_path), toStdString(overwritten_path), opt, err);
|
// FIXME: hello traveller! Apparently std::copy does NOT overwrite existing files on GNU libstdc++ on Windows?
|
||||||
|
fs::copy(StringUtils::toStdString(override_path), StringUtils::toStdString(overwritten_path), opt, err);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
qCritical() << QString("Failed to apply override from %1 to %2").arg(override_path, overwritten_path);
|
qCritical() << QString("Failed to apply override from %1 to %2").arg(override_path, overwritten_path);
|
||||||
|
@ -72,7 +72,7 @@ bool GZip::unzip(const QByteArray &compressedBytes, QByteArray &uncompressedByte
|
|||||||
uncompLength *= 2;
|
uncompLength *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
strm.next_out = (Bytef *)(uncompressedBytes.data() + strm.total_out);
|
strm.next_out = reinterpret_cast<Bytef *>((uncompressedBytes.data() + strm.total_out));
|
||||||
strm.avail_out = uncompLength - strm.total_out;
|
strm.avail_out = uncompLength - strm.total_out;
|
||||||
|
|
||||||
// Inflate another chunk.
|
// Inflate another chunk.
|
||||||
@ -129,7 +129,7 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes)
|
|||||||
{
|
{
|
||||||
compressedBytes.resize(compressedBytes.size() * 2);
|
compressedBytes.resize(compressedBytes.size() * 2);
|
||||||
}
|
}
|
||||||
zs.next_out = (Bytef *) (compressedBytes.data() + offset);
|
zs.next_out = reinterpret_cast<Bytef*>((compressedBytes.data() + offset));
|
||||||
temp = zs.avail_out = compressedBytes.size() - offset;
|
temp = zs.avail_out = compressedBytes.size() - offset;
|
||||||
ret = deflate(&zs, Z_FINISH);
|
ret = deflate(&zs, Z_FINISH);
|
||||||
offset += temp - zs.avail_out;
|
offset += temp - zs.avail_out;
|
||||||
|
@ -42,7 +42,7 @@ public:
|
|||||||
}
|
}
|
||||||
void put(QByteArray input)
|
void put(QByteArray input)
|
||||||
{
|
{
|
||||||
hoedown_buffer_put(buf, (uint8_t *) input.data(), input.size());
|
hoedown_buffer_put(buf, reinterpret_cast<uint8_t *>(input.data()), input.size());
|
||||||
}
|
}
|
||||||
const uint8_t * data() const
|
const uint8_t * data() const
|
||||||
{
|
{
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
#include "JavaCommon.h"
|
#include "JavaCommon.h"
|
||||||
#include "java/JavaUtils.h"
|
#include "java/JavaUtils.h"
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
#include <MMCStrings.h>
|
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
|
|
||||||
bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
|
bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
namespace Strings
|
|
||||||
{
|
|
||||||
int naturalCompare(const QString &s1, const QString &s2, Qt::CaseSensitivity cs);
|
|
||||||
}
|
|
@ -1,26 +1,28 @@
|
|||||||
#include "MMCStrings.h"
|
#include "StringUtils.h"
|
||||||
|
|
||||||
|
/// If you're wondering where these came from exactly, then know you're not the only one =D
|
||||||
|
|
||||||
/// TAKEN FROM Qt, because it doesn't expose it intelligently
|
/// TAKEN FROM Qt, because it doesn't expose it intelligently
|
||||||
static inline QChar getNextChar(const QString &s, int location)
|
static inline QChar getNextChar(const QString& s, int location)
|
||||||
{
|
{
|
||||||
return (location < s.length()) ? s.at(location) : QChar();
|
return (location < s.length()) ? s.at(location) : QChar();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TAKEN FROM Qt, because it doesn't expose it intelligently
|
/// TAKEN FROM Qt, because it doesn't expose it intelligently
|
||||||
int Strings::naturalCompare(const QString &s1, const QString &s2, Qt::CaseSensitivity cs)
|
int StringUtils::naturalCompare(const QString& s1, const QString& s2, Qt::CaseSensitivity cs)
|
||||||
{
|
{
|
||||||
for (int l1 = 0, l2 = 0; l1 <= s1.count() && l2 <= s2.count(); ++l1, ++l2)
|
int l1 = 0, l2 = 0;
|
||||||
{
|
while (l1 <= s1.count() && l2 <= s2.count()) {
|
||||||
// skip spaces, tabs and 0's
|
// skip spaces, tabs and 0's
|
||||||
QChar c1 = getNextChar(s1, l1);
|
QChar c1 = getNextChar(s1, l1);
|
||||||
while (c1.isSpace())
|
while (c1.isSpace())
|
||||||
c1 = getNextChar(s1, ++l1);
|
c1 = getNextChar(s1, ++l1);
|
||||||
|
|
||||||
QChar c2 = getNextChar(s2, l2);
|
QChar c2 = getNextChar(s2, l2);
|
||||||
while (c2.isSpace())
|
while (c2.isSpace())
|
||||||
c2 = getNextChar(s2, ++l2);
|
c2 = getNextChar(s2, ++l2);
|
||||||
|
|
||||||
if (c1.isDigit() && c2.isDigit())
|
if (c1.isDigit() && c2.isDigit()) {
|
||||||
{
|
|
||||||
while (c1.digitValue() == 0)
|
while (c1.digitValue() == 0)
|
||||||
c1 = getNextChar(s1, ++l1);
|
c1 = getNextChar(s1, ++l1);
|
||||||
while (c2.digitValue() == 0)
|
while (c2.digitValue() == 0)
|
||||||
@ -30,11 +32,8 @@ int Strings::naturalCompare(const QString &s1, const QString &s2, Qt::CaseSensit
|
|||||||
int lookAheadLocation2 = l2;
|
int lookAheadLocation2 = l2;
|
||||||
int currentReturnValue = 0;
|
int currentReturnValue = 0;
|
||||||
// find the last digit, setting currentReturnValue as we go if it isn't equal
|
// find the last digit, setting currentReturnValue as we go if it isn't equal
|
||||||
for (QChar lookAhead1 = c1, lookAhead2 = c2;
|
for (QChar lookAhead1 = c1, lookAhead2 = c2; (lookAheadLocation1 <= s1.length() && lookAheadLocation2 <= s2.length());
|
||||||
(lookAheadLocation1 <= s1.length() && lookAheadLocation2 <= s2.length());
|
lookAhead1 = getNextChar(s1, ++lookAheadLocation1), lookAhead2 = getNextChar(s2, ++lookAheadLocation2)) {
|
||||||
lookAhead1 = getNextChar(s1, ++lookAheadLocation1),
|
|
||||||
lookAhead2 = getNextChar(s2, ++lookAheadLocation2))
|
|
||||||
{
|
|
||||||
bool is1ADigit = !lookAhead1.isNull() && lookAhead1.isDigit();
|
bool is1ADigit = !lookAhead1.isNull() && lookAhead1.isDigit();
|
||||||
bool is2ADigit = !lookAhead2.isNull() && lookAhead2.isDigit();
|
bool is2ADigit = !lookAhead2.isNull() && lookAhead2.isDigit();
|
||||||
if (!is1ADigit && !is2ADigit)
|
if (!is1ADigit && !is2ADigit)
|
||||||
@ -43,14 +42,10 @@ int Strings::naturalCompare(const QString &s1, const QString &s2, Qt::CaseSensit
|
|||||||
return -1;
|
return -1;
|
||||||
if (!is2ADigit)
|
if (!is2ADigit)
|
||||||
return 1;
|
return 1;
|
||||||
if (currentReturnValue == 0)
|
if (currentReturnValue == 0) {
|
||||||
{
|
if (lookAhead1 < lookAhead2) {
|
||||||
if (lookAhead1 < lookAhead2)
|
|
||||||
{
|
|
||||||
currentReturnValue = -1;
|
currentReturnValue = -1;
|
||||||
}
|
} else if (lookAhead1 > lookAhead2) {
|
||||||
else if (lookAhead1 > lookAhead2)
|
|
||||||
{
|
|
||||||
currentReturnValue = 1;
|
currentReturnValue = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,19 +53,24 @@ int Strings::naturalCompare(const QString &s1, const QString &s2, Qt::CaseSensit
|
|||||||
if (currentReturnValue != 0)
|
if (currentReturnValue != 0)
|
||||||
return currentReturnValue;
|
return currentReturnValue;
|
||||||
}
|
}
|
||||||
if (cs == Qt::CaseInsensitive)
|
|
||||||
{
|
if (cs == Qt::CaseInsensitive) {
|
||||||
if (!c1.isLower())
|
if (!c1.isLower())
|
||||||
c1 = c1.toLower();
|
c1 = c1.toLower();
|
||||||
if (!c2.isLower())
|
if (!c2.isLower())
|
||||||
c2 = c2.toLower();
|
c2 = c2.toLower();
|
||||||
}
|
}
|
||||||
|
|
||||||
int r = QString::localeAwareCompare(c1, c2);
|
int r = QString::localeAwareCompare(c1, c2);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
l1 += 1;
|
||||||
|
l2 += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The two strings are the same (02 == 2) so fall back to the normal sort
|
// The two strings are the same (02 == 2) so fall back to the normal sort
|
||||||
return QString::compare(s1, s2, cs);
|
return QString::compare(s1, s2, cs);
|
||||||
}
|
}
|
32
launcher/StringUtils.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace StringUtils {
|
||||||
|
|
||||||
|
#if defined Q_OS_WIN32
|
||||||
|
using string = std::wstring;
|
||||||
|
|
||||||
|
inline string toStdString(QString s)
|
||||||
|
{
|
||||||
|
return s.toStdWString();
|
||||||
|
}
|
||||||
|
inline QString fromStdString(string s)
|
||||||
|
{
|
||||||
|
return QString::fromStdWString(s);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
using string = std::string;
|
||||||
|
|
||||||
|
inline string toStdString(QString s)
|
||||||
|
{
|
||||||
|
return s.toStdString();
|
||||||
|
}
|
||||||
|
inline QString fromStdString(string s)
|
||||||
|
{
|
||||||
|
return QString::fromStdString(s);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int naturalCompare(const QString& s1, const QString& s2, Qt::CaseSensitivity cs);
|
||||||
|
} // namespace StringUtils
|
@ -1,9 +1,10 @@
|
|||||||
#include "JavaInstall.h"
|
#include "JavaInstall.h"
|
||||||
#include <MMCStrings.h>
|
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
bool JavaInstall::operator<(const JavaInstall &rhs)
|
bool JavaInstall::operator<(const JavaInstall &rhs)
|
||||||
{
|
{
|
||||||
auto archCompare = Strings::naturalCompare(arch, rhs.arch, Qt::CaseInsensitive);
|
auto archCompare = StringUtils::naturalCompare(arch, rhs.arch, Qt::CaseInsensitive);
|
||||||
if(archCompare != 0)
|
if(archCompare != 0)
|
||||||
return archCompare < 0;
|
return archCompare < 0;
|
||||||
if(id < rhs.id)
|
if(id < rhs.id)
|
||||||
@ -14,7 +15,7 @@ bool JavaInstall::operator<(const JavaInstall &rhs)
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return Strings::naturalCompare(path, rhs.path, Qt::CaseInsensitive) < 0;
|
return StringUtils::naturalCompare(path, rhs.path, Qt::CaseInsensitive) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JavaInstall::operator==(const JavaInstall &rhs)
|
bool JavaInstall::operator==(const JavaInstall &rhs)
|
||||||
|
@ -41,7 +41,6 @@
|
|||||||
#include "java/JavaInstallList.h"
|
#include "java/JavaInstallList.h"
|
||||||
#include "java/JavaCheckerJob.h"
|
#include "java/JavaCheckerJob.h"
|
||||||
#include "java/JavaUtils.h"
|
#include "java/JavaUtils.h"
|
||||||
#include "MMCStrings.h"
|
|
||||||
#include "minecraft/VersionFilterData.h"
|
#include "minecraft/VersionFilterData.h"
|
||||||
|
|
||||||
JavaInstallList::JavaInstallList(QObject *parent) : BaseVersionList(parent)
|
JavaInstallList::JavaInstallList(QObject *parent) : BaseVersionList(parent)
|
||||||
@ -73,7 +72,7 @@ void JavaInstallList::load()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const BaseVersionPtr JavaInstallList::at(int i) const
|
const BaseVersion::Ptr JavaInstallList::at(int i) const
|
||||||
{
|
{
|
||||||
return m_vlist.at(i);
|
return m_vlist.at(i);
|
||||||
}
|
}
|
||||||
@ -122,7 +121,7 @@ BaseVersionList::RoleList JavaInstallList::providesRoles() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void JavaInstallList::updateListData(QList<BaseVersionPtr> versions)
|
void JavaInstallList::updateListData(QList<BaseVersion::Ptr> versions)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_vlist = versions;
|
m_vlist = versions;
|
||||||
@ -137,7 +136,7 @@ void JavaInstallList::updateListData(QList<BaseVersionPtr> versions)
|
|||||||
m_loadTask.reset();
|
m_loadTask.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sortJavas(BaseVersionPtr left, BaseVersionPtr right)
|
bool sortJavas(BaseVersion::Ptr left, BaseVersion::Ptr right)
|
||||||
{
|
{
|
||||||
auto rleft = std::dynamic_pointer_cast<JavaInstall>(right);
|
auto rleft = std::dynamic_pointer_cast<JavaInstall>(right);
|
||||||
auto rright = std::dynamic_pointer_cast<JavaInstall>(left);
|
auto rright = std::dynamic_pointer_cast<JavaInstall>(left);
|
||||||
@ -210,11 +209,11 @@ void JavaListLoadTask::javaCheckerFinished()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<BaseVersionPtr> javas_bvp;
|
QList<BaseVersion::Ptr> javas_bvp;
|
||||||
for (auto java : candidates)
|
for (auto java : candidates)
|
||||||
{
|
{
|
||||||
//qDebug() << java->id << java->arch << " at " << java->path;
|
//qDebug() << java->id << java->arch << " at " << java->path;
|
||||||
BaseVersionPtr bp_java = std::dynamic_pointer_cast<BaseVersion>(java);
|
BaseVersion::Ptr bp_java = std::dynamic_pointer_cast<BaseVersion>(java);
|
||||||
|
|
||||||
if (bp_java)
|
if (bp_java)
|
||||||
{
|
{
|
||||||
|
@ -42,7 +42,7 @@ public:
|
|||||||
|
|
||||||
Task::Ptr getLoadTask() override;
|
Task::Ptr getLoadTask() override;
|
||||||
bool isLoaded() override;
|
bool isLoaded() override;
|
||||||
const BaseVersionPtr at(int i) const override;
|
const BaseVersion::Ptr at(int i) const override;
|
||||||
int count() const override;
|
int count() const override;
|
||||||
void sortVersions() override;
|
void sortVersions() override;
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ public:
|
|||||||
RoleList providesRoles() const override;
|
RoleList providesRoles() const override;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateListData(QList<BaseVersionPtr> versions) override;
|
void updateListData(QList<BaseVersion::Ptr> versions) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void load();
|
void load();
|
||||||
@ -59,7 +59,7 @@ protected:
|
|||||||
protected:
|
protected:
|
||||||
Status m_status = Status::NotDone;
|
Status m_status = Status::NotDone;
|
||||||
shared_qobject_ptr<JavaListLoadTask> m_loadTask;
|
shared_qobject_ptr<JavaListLoadTask> m_loadTask;
|
||||||
QList<BaseVersionPtr> m_vlist;
|
QList<BaseVersion::Ptr> m_vlist;
|
||||||
};
|
};
|
||||||
|
|
||||||
class JavaListLoadTask : public Task
|
class JavaListLoadTask : public Task
|
||||||
|
@ -379,7 +379,9 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return addJavasFromEnv(candidates);
|
candidates = addJavasFromEnv(candidates);
|
||||||
|
candidates.removeDuplicates();
|
||||||
|
return candidates;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(Q_OS_MAC)
|
#elif defined(Q_OS_MAC)
|
||||||
@ -402,7 +404,9 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java");
|
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java");
|
||||||
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Commands/java");
|
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Commands/java");
|
||||||
}
|
}
|
||||||
return addJavasFromEnv(javas);
|
javas = addJavasFromEnv(javas);
|
||||||
|
javas.removeDuplicates();
|
||||||
|
return javas;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(Q_OS_LINUX)
|
#elif defined(Q_OS_LINUX)
|
||||||
@ -448,7 +452,9 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
scanJavaDir("/opt/jdks");
|
scanJavaDir("/opt/jdks");
|
||||||
// flatpak
|
// flatpak
|
||||||
scanJavaDir("/app/jdk");
|
scanJavaDir("/app/jdk");
|
||||||
return addJavasFromEnv(javas);
|
javas = addJavasFromEnv(javas);
|
||||||
|
javas.removeDuplicates();
|
||||||
|
return javas;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
QList<QString> JavaUtils::FindJavaPaths()
|
QList<QString> JavaUtils::FindJavaPaths()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "JavaVersion.h"
|
#include "JavaVersion.h"
|
||||||
#include <MMCStrings.h>
|
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
@ -98,12 +99,12 @@ bool JavaVersion::operator<(const JavaVersion &rhs)
|
|||||||
else if(thisPre && rhsPre)
|
else if(thisPre && rhsPre)
|
||||||
{
|
{
|
||||||
// both are prereleases - use natural compare...
|
// both are prereleases - use natural compare...
|
||||||
return Strings::naturalCompare(m_prerelease, rhs.m_prerelease, Qt::CaseSensitive) < 0;
|
return StringUtils::naturalCompare(m_prerelease, rhs.m_prerelease, Qt::CaseSensitive) < 0;
|
||||||
}
|
}
|
||||||
// neither is prerelease, so they are the same -> this cannot be less than rhs
|
// neither is prerelease, so they are the same -> this cannot be less than rhs
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else return Strings::naturalCompare(m_string, rhs.m_string, Qt::CaseSensitive) < 0;
|
else return StringUtils::naturalCompare(m_string, rhs.m_string, Qt::CaseSensitive) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JavaVersion::operator==(const JavaVersion &rhs)
|
bool JavaVersion::operator==(const JavaVersion &rhs)
|
||||||
|
@ -37,7 +37,6 @@
|
|||||||
|
|
||||||
#include "launch/LaunchTask.h"
|
#include "launch/LaunchTask.h"
|
||||||
#include "MessageLevel.h"
|
#include "MessageLevel.h"
|
||||||
#include "MMCStrings.h"
|
|
||||||
#include "java/JavaChecker.h"
|
#include "java/JavaChecker.h"
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
@ -90,5 +90,7 @@ int main(int argc, char *argv[])
|
|||||||
return 1;
|
return 1;
|
||||||
case Application::Succeeded:
|
case Application::Succeeded:
|
||||||
return 0;
|
return 0;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ Index::Index(QObject *parent)
|
|||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
Index::Index(const QVector<VersionListPtr> &lists, QObject *parent)
|
Index::Index(const QVector<VersionList::Ptr> &lists, QObject *parent)
|
||||||
: QAbstractListModel(parent), m_lists(lists)
|
: QAbstractListModel(parent), m_lists(lists)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_lists.size(); ++i)
|
for (int i = 0; i < m_lists.size(); ++i)
|
||||||
@ -41,7 +41,7 @@ QVariant Index::data(const QModelIndex &index, int role) const
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
VersionListPtr list = m_lists.at(index.row());
|
VersionList::Ptr list = m_lists.at(index.row());
|
||||||
switch (role)
|
switch (role)
|
||||||
{
|
{
|
||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
@ -81,9 +81,9 @@ bool Index::hasUid(const QString &uid) const
|
|||||||
return m_uids.contains(uid);
|
return m_uids.contains(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
VersionListPtr Index::get(const QString &uid)
|
VersionList::Ptr Index::get(const QString &uid)
|
||||||
{
|
{
|
||||||
VersionListPtr out = m_uids.value(uid, nullptr);
|
VersionList::Ptr out = m_uids.value(uid, nullptr);
|
||||||
if(!out)
|
if(!out)
|
||||||
{
|
{
|
||||||
out = std::make_shared<VersionList>(uid);
|
out = std::make_shared<VersionList>(uid);
|
||||||
@ -92,7 +92,7 @@ VersionListPtr Index::get(const QString &uid)
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
VersionPtr Index::get(const QString &uid, const QString &version)
|
Version::Ptr Index::get(const QString &uid, const QString &version)
|
||||||
{
|
{
|
||||||
auto list = get(uid);
|
auto list = get(uid);
|
||||||
return list->getVersion(version);
|
return list->getVersion(version);
|
||||||
@ -105,7 +105,7 @@ void Index::parse(const QJsonObject& obj)
|
|||||||
|
|
||||||
void Index::merge(const std::shared_ptr<Index> &other)
|
void Index::merge(const std::shared_ptr<Index> &other)
|
||||||
{
|
{
|
||||||
const QVector<VersionListPtr> lists = std::dynamic_pointer_cast<Index>(other)->m_lists;
|
const QVector<VersionList::Ptr> lists = std::dynamic_pointer_cast<Index>(other)->m_lists;
|
||||||
// initial load, no need to merge
|
// initial load, no need to merge
|
||||||
if (m_lists.isEmpty())
|
if (m_lists.isEmpty())
|
||||||
{
|
{
|
||||||
@ -120,7 +120,7 @@ void Index::merge(const std::shared_ptr<Index> &other)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (const VersionListPtr &list : lists)
|
for (const VersionList::Ptr &list : lists)
|
||||||
{
|
{
|
||||||
if (m_uids.contains(list->uid()))
|
if (m_uids.contains(list->uid()))
|
||||||
{
|
{
|
||||||
@ -138,7 +138,7 @@ void Index::merge(const std::shared_ptr<Index> &other)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Index::connectVersionList(const int row, const VersionListPtr &list)
|
void Index::connectVersionList(const int row, const VersionList::Ptr &list)
|
||||||
{
|
{
|
||||||
connect(list.get(), &VersionList::nameChanged, this, [this, row]()
|
connect(list.get(), &VersionList::nameChanged, this, [this, row]()
|
||||||
{
|
{
|
||||||
|
@ -19,20 +19,19 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "BaseEntity.h"
|
#include "BaseEntity.h"
|
||||||
|
#include "meta/VersionList.h"
|
||||||
|
|
||||||
class Task;
|
class Task;
|
||||||
|
|
||||||
namespace Meta
|
namespace Meta
|
||||||
{
|
{
|
||||||
using VersionListPtr = std::shared_ptr<class VersionList>;
|
|
||||||
using VersionPtr = std::shared_ptr<class Version>;
|
|
||||||
|
|
||||||
class Index : public QAbstractListModel, public BaseEntity
|
class Index : public QAbstractListModel, public BaseEntity
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit Index(QObject *parent = nullptr);
|
explicit Index(QObject *parent = nullptr);
|
||||||
explicit Index(const QVector<VersionListPtr> &lists, QObject *parent = nullptr);
|
explicit Index(const QVector<VersionList::Ptr> &lists, QObject *parent = nullptr);
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@ -49,21 +48,21 @@ public:
|
|||||||
QString localFilename() const override { return "index.json"; }
|
QString localFilename() const override { return "index.json"; }
|
||||||
|
|
||||||
// queries
|
// queries
|
||||||
VersionListPtr get(const QString &uid);
|
VersionList::Ptr get(const QString &uid);
|
||||||
VersionPtr get(const QString &uid, const QString &version);
|
Version::Ptr get(const QString &uid, const QString &version);
|
||||||
bool hasUid(const QString &uid) const;
|
bool hasUid(const QString &uid) const;
|
||||||
|
|
||||||
QVector<VersionListPtr> lists() const { return m_lists; }
|
QVector<VersionList::Ptr> lists() const { return m_lists; }
|
||||||
|
|
||||||
public: // for usage by parsers only
|
public: // for usage by parsers only
|
||||||
void merge(const std::shared_ptr<Index> &other);
|
void merge(const std::shared_ptr<Index> &other);
|
||||||
void parse(const QJsonObject &obj) override;
|
void parse(const QJsonObject &obj) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVector<VersionListPtr> m_lists;
|
QVector<VersionList::Ptr> m_lists;
|
||||||
QHash<QString, VersionListPtr> m_uids;
|
QHash<QString, VersionList::Ptr> m_uids;
|
||||||
|
|
||||||
void connectVersionList(const int row, const VersionListPtr &list);
|
void connectVersionList(const int row, const VersionList::Ptr &list);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,11 +37,11 @@ MetadataVersion currentFormatVersion()
|
|||||||
static std::shared_ptr<Index> parseIndexInternal(const QJsonObject &obj)
|
static std::shared_ptr<Index> parseIndexInternal(const QJsonObject &obj)
|
||||||
{
|
{
|
||||||
const QVector<QJsonObject> objects = requireIsArrayOf<QJsonObject>(obj, "packages");
|
const QVector<QJsonObject> objects = requireIsArrayOf<QJsonObject>(obj, "packages");
|
||||||
QVector<VersionListPtr> lists;
|
QVector<VersionList::Ptr> lists;
|
||||||
lists.reserve(objects.size());
|
lists.reserve(objects.size());
|
||||||
std::transform(objects.begin(), objects.end(), std::back_inserter(lists), [](const QJsonObject &obj)
|
std::transform(objects.begin(), objects.end(), std::back_inserter(lists), [](const QJsonObject &obj)
|
||||||
{
|
{
|
||||||
VersionListPtr list = std::make_shared<VersionList>(requireString(obj, "uid"));
|
VersionList::Ptr list = std::make_shared<VersionList>(requireString(obj, "uid"));
|
||||||
list->setName(ensureString(obj, "name", QString()));
|
list->setName(ensureString(obj, "name", QString()));
|
||||||
return list;
|
return list;
|
||||||
});
|
});
|
||||||
@ -49,9 +49,9 @@ static std::shared_ptr<Index> parseIndexInternal(const QJsonObject &obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Version
|
// Version
|
||||||
static VersionPtr parseCommonVersion(const QString &uid, const QJsonObject &obj)
|
static Version::Ptr parseCommonVersion(const QString &uid, const QJsonObject &obj)
|
||||||
{
|
{
|
||||||
VersionPtr version = std::make_shared<Version>(uid, requireString(obj, "version"));
|
Version::Ptr version = std::make_shared<Version>(uid, requireString(obj, "version"));
|
||||||
version->setTime(QDateTime::fromString(requireString(obj, "releaseTime"), Qt::ISODate).toMSecsSinceEpoch() / 1000);
|
version->setTime(QDateTime::fromString(requireString(obj, "releaseTime"), Qt::ISODate).toMSecsSinceEpoch() / 1000);
|
||||||
version->setType(ensureString(obj, "type", QString()));
|
version->setType(ensureString(obj, "type", QString()));
|
||||||
version->setRecommended(ensureBoolean(obj, QString("recommended"), false));
|
version->setRecommended(ensureBoolean(obj, QString("recommended"), false));
|
||||||
@ -63,9 +63,9 @@ static VersionPtr parseCommonVersion(const QString &uid, const QJsonObject &obj)
|
|||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<Version> parseVersionInternal(const QJsonObject &obj)
|
static Version::Ptr parseVersionInternal(const QJsonObject &obj)
|
||||||
{
|
{
|
||||||
VersionPtr version = parseCommonVersion(requireString(obj, "uid"), obj);
|
Version::Ptr version = parseCommonVersion(requireString(obj, "uid"), obj);
|
||||||
|
|
||||||
version->setData(OneSixVersionFormat::versionFileFromJson(QJsonDocument(obj),
|
version->setData(OneSixVersionFormat::versionFileFromJson(QJsonDocument(obj),
|
||||||
QString("%1/%2.json").arg(version->uid(), version->version()),
|
QString("%1/%2.json").arg(version->uid(), version->version()),
|
||||||
@ -74,12 +74,12 @@ static std::shared_ptr<Version> parseVersionInternal(const QJsonObject &obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Version list / package
|
// Version list / package
|
||||||
static std::shared_ptr<VersionList> parseVersionListInternal(const QJsonObject &obj)
|
static VersionList::Ptr parseVersionListInternal(const QJsonObject &obj)
|
||||||
{
|
{
|
||||||
const QString uid = requireString(obj, "uid");
|
const QString uid = requireString(obj, "uid");
|
||||||
|
|
||||||
const QVector<QJsonObject> versionsRaw = requireIsArrayOf<QJsonObject>(obj, "versions");
|
const QVector<QJsonObject> versionsRaw = requireIsArrayOf<QJsonObject>(obj, "versions");
|
||||||
QVector<VersionPtr> versions;
|
QVector<Version::Ptr> versions;
|
||||||
versions.reserve(versionsRaw.size());
|
versions.reserve(versionsRaw.size());
|
||||||
std::transform(versionsRaw.begin(), versionsRaw.end(), std::back_inserter(versions), [uid](const QJsonObject &vObj)
|
std::transform(versionsRaw.begin(), versionsRaw.end(), std::back_inserter(versions), [uid](const QJsonObject &vObj)
|
||||||
{
|
{
|
||||||
@ -88,7 +88,7 @@ static std::shared_ptr<VersionList> parseVersionListInternal(const QJsonObject &
|
|||||||
return version;
|
return version;
|
||||||
});
|
});
|
||||||
|
|
||||||
VersionListPtr list = std::make_shared<VersionList>(uid);
|
VersionList::Ptr list = std::make_shared<VersionList>(uid);
|
||||||
list->setName(ensureString(obj, "name", QString()));
|
list->setName(ensureString(obj, "name", QString()));
|
||||||
list->setVersions(versions);
|
list->setVersions(versions);
|
||||||
return list;
|
return list;
|
||||||
|
@ -54,7 +54,7 @@ void Meta::Version::parse(const QJsonObject& obj)
|
|||||||
parseVersion(obj, this);
|
parseVersion(obj, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Meta::Version::mergeFromList(const Meta::VersionPtr& other)
|
void Meta::Version::mergeFromList(const Meta::Version::Ptr& other)
|
||||||
{
|
{
|
||||||
if(other->m_providesRecommendations)
|
if(other->m_providesRecommendations)
|
||||||
{
|
{
|
||||||
@ -85,7 +85,7 @@ void Meta::Version::mergeFromList(const Meta::VersionPtr& other)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Meta::Version::merge(const VersionPtr &other)
|
void Meta::Version::merge(const Version::Ptr &other)
|
||||||
{
|
{
|
||||||
mergeFromList(other);
|
mergeFromList(other);
|
||||||
if(other->m_data)
|
if(other->m_data)
|
||||||
|
@ -30,13 +30,14 @@
|
|||||||
|
|
||||||
namespace Meta
|
namespace Meta
|
||||||
{
|
{
|
||||||
using VersionPtr = std::shared_ptr<class Version>;
|
|
||||||
|
|
||||||
class Version : public QObject, public BaseVersion, public BaseEntity
|
class Version : public QObject, public BaseVersion, public BaseEntity
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public: /* con/des */
|
public:
|
||||||
|
using Ptr = std::shared_ptr<Version>;
|
||||||
|
|
||||||
explicit Version(const QString &uid, const QString &version);
|
explicit Version(const QString &uid, const QString &version);
|
||||||
virtual ~Version();
|
virtual ~Version();
|
||||||
|
|
||||||
@ -78,8 +79,8 @@ public: /* con/des */
|
|||||||
return m_data != nullptr;
|
return m_data != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void merge(const VersionPtr &other);
|
void merge(const Version::Ptr &other);
|
||||||
void mergeFromList(const VersionPtr &other);
|
void mergeFromList(const Version::Ptr &other);
|
||||||
void parse(const QJsonObject &obj) override;
|
void parse(const QJsonObject &obj) override;
|
||||||
|
|
||||||
QString localFilename() const override;
|
QString localFilename() const override;
|
||||||
@ -113,4 +114,4 @@ private:
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(Meta::VersionPtr)
|
Q_DECLARE_METATYPE(Meta::Version::Ptr)
|
||||||
|
@ -40,7 +40,7 @@ bool VersionList::isLoaded()
|
|||||||
return BaseEntity::isLoaded();
|
return BaseEntity::isLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
const BaseVersionPtr VersionList::at(int i) const
|
const BaseVersion::Ptr VersionList::at(int i) const
|
||||||
{
|
{
|
||||||
return m_versions.at(i);
|
return m_versions.at(i);
|
||||||
}
|
}
|
||||||
@ -52,7 +52,7 @@ int VersionList::count() const
|
|||||||
void VersionList::sortVersions()
|
void VersionList::sortVersions()
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
std::sort(m_versions.begin(), m_versions.end(), [](const VersionPtr &a, const VersionPtr &b)
|
std::sort(m_versions.begin(), m_versions.end(), [](const Version::Ptr &a, const Version::Ptr &b)
|
||||||
{
|
{
|
||||||
return *a.get() < *b.get();
|
return *a.get() < *b.get();
|
||||||
});
|
});
|
||||||
@ -66,7 +66,7 @@ QVariant VersionList::data(const QModelIndex &index, int role) const
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
VersionPtr version = m_versions.at(index.row());
|
Version::Ptr version = m_versions.at(index.row());
|
||||||
|
|
||||||
switch (role)
|
switch (role)
|
||||||
{
|
{
|
||||||
@ -129,9 +129,9 @@ QString VersionList::humanReadable() const
|
|||||||
return m_name.isEmpty() ? m_uid : m_name;
|
return m_name.isEmpty() ? m_uid : m_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
VersionPtr VersionList::getVersion(const QString &version)
|
Version::Ptr VersionList::getVersion(const QString &version)
|
||||||
{
|
{
|
||||||
VersionPtr out = m_lookup.value(version, nullptr);
|
Version::Ptr out = m_lookup.value(version, nullptr);
|
||||||
if(!out)
|
if(!out)
|
||||||
{
|
{
|
||||||
out = std::make_shared<Version>(m_uid, version);
|
out = std::make_shared<Version>(m_uid, version);
|
||||||
@ -143,7 +143,7 @@ VersionPtr VersionList::getVersion(const QString &version)
|
|||||||
bool VersionList::hasVersion(QString version) const
|
bool VersionList::hasVersion(QString version) const
|
||||||
{
|
{
|
||||||
auto ver = std::find_if(m_versions.constBegin(), m_versions.constEnd(),
|
auto ver = std::find_if(m_versions.constBegin(), m_versions.constEnd(),
|
||||||
[&](Meta::VersionPtr const& a){ return a->version() == version; });
|
[&](Meta::Version::Ptr const& a){ return a->version() == version; });
|
||||||
return (ver != m_versions.constEnd());
|
return (ver != m_versions.constEnd());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,11 +153,11 @@ void VersionList::setName(const QString &name)
|
|||||||
emit nameChanged(name);
|
emit nameChanged(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionList::setVersions(const QVector<VersionPtr> &versions)
|
void VersionList::setVersions(const QVector<Version::Ptr> &versions)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_versions = versions;
|
m_versions = versions;
|
||||||
std::sort(m_versions.begin(), m_versions.end(), [](const VersionPtr &a, const VersionPtr &b)
|
std::sort(m_versions.begin(), m_versions.end(), [](const Version::Ptr &a, const Version::Ptr &b)
|
||||||
{
|
{
|
||||||
return a->rawTime() > b->rawTime();
|
return a->rawTime() > b->rawTime();
|
||||||
});
|
});
|
||||||
@ -168,7 +168,7 @@ void VersionList::setVersions(const QVector<VersionPtr> &versions)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: this is dumb, we have 'recommended' as part of the metadata already...
|
// FIXME: this is dumb, we have 'recommended' as part of the metadata already...
|
||||||
auto recommendedIt = std::find_if(m_versions.constBegin(), m_versions.constEnd(), [](const VersionPtr &ptr) { return ptr->type() == "release"; });
|
auto recommendedIt = std::find_if(m_versions.constBegin(), m_versions.constEnd(), [](const Version::Ptr &ptr) { return ptr->type() == "release"; });
|
||||||
m_recommended = recommendedIt == m_versions.constEnd() ? nullptr : *recommendedIt;
|
m_recommended = recommendedIt == m_versions.constEnd() ? nullptr : *recommendedIt;
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
@ -179,7 +179,7 @@ void VersionList::parse(const QJsonObject& obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: this is dumb, we have 'recommended' as part of the metadata already...
|
// FIXME: this is dumb, we have 'recommended' as part of the metadata already...
|
||||||
static const Meta::VersionPtr &getBetterVersion(const Meta::VersionPtr &a, const Meta::VersionPtr &b)
|
static const Meta::Version::Ptr &getBetterVersion(const Meta::Version::Ptr &a, const Meta::Version::Ptr &b)
|
||||||
{
|
{
|
||||||
if(!a)
|
if(!a)
|
||||||
return b;
|
return b;
|
||||||
@ -194,7 +194,7 @@ static const Meta::VersionPtr &getBetterVersion(const Meta::VersionPtr &a, const
|
|||||||
return (a->type() == "release" ? a : b);
|
return (a->type() == "release" ? a : b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionList::mergeFromIndex(const VersionListPtr &other)
|
void VersionList::mergeFromIndex(const VersionList::Ptr &other)
|
||||||
{
|
{
|
||||||
if (m_name != other->m_name)
|
if (m_name != other->m_name)
|
||||||
{
|
{
|
||||||
@ -202,7 +202,7 @@ void VersionList::mergeFromIndex(const VersionListPtr &other)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionList::merge(const VersionListPtr &other)
|
void VersionList::merge(const VersionList::Ptr &other)
|
||||||
{
|
{
|
||||||
if (m_name != other->m_name)
|
if (m_name != other->m_name)
|
||||||
{
|
{
|
||||||
@ -216,7 +216,7 @@ void VersionList::merge(const VersionListPtr &other)
|
|||||||
{
|
{
|
||||||
qWarning() << "Empty list loaded ...";
|
qWarning() << "Empty list loaded ...";
|
||||||
}
|
}
|
||||||
for (const VersionPtr &version : other->m_versions)
|
for (const Version::Ptr &version : other->m_versions)
|
||||||
{
|
{
|
||||||
// we already have the version. merge the contents
|
// we already have the version. merge the contents
|
||||||
if (m_lookup.contains(version->version()))
|
if (m_lookup.contains(version->version()))
|
||||||
@ -235,7 +235,7 @@ void VersionList::merge(const VersionListPtr &other)
|
|||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionList::setupAddedVersion(const int row, const VersionPtr &version)
|
void VersionList::setupAddedVersion(const int row, const Version::Ptr &version)
|
||||||
{
|
{
|
||||||
// FIXME: do not disconnect from everythin, disconnect only the lambdas here
|
// FIXME: do not disconnect from everythin, disconnect only the lambdas here
|
||||||
version->disconnect();
|
version->disconnect();
|
||||||
@ -244,7 +244,7 @@ void VersionList::setupAddedVersion(const int row, const VersionPtr &version)
|
|||||||
connect(version.get(), &Version::typeChanged, this, [this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << TypeRole); });
|
connect(version.get(), &Version::typeChanged, this, [this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << TypeRole); });
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseVersionPtr VersionList::getRecommended() const
|
BaseVersion::Ptr VersionList::getRecommended() const
|
||||||
{
|
{
|
||||||
return m_recommended;
|
return m_recommended;
|
||||||
}
|
}
|
||||||
|
@ -20,10 +20,10 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "meta/Version.h"
|
||||||
|
|
||||||
namespace Meta
|
namespace Meta
|
||||||
{
|
{
|
||||||
using VersionPtr = std::shared_ptr<class Version>;
|
|
||||||
using VersionListPtr = std::shared_ptr<class VersionList>;
|
|
||||||
|
|
||||||
class VersionList : public BaseVersionList, public BaseEntity
|
class VersionList : public BaseVersionList, public BaseEntity
|
||||||
{
|
{
|
||||||
@ -33,6 +33,8 @@ class VersionList : public BaseVersionList, public BaseEntity
|
|||||||
public:
|
public:
|
||||||
explicit VersionList(const QString &uid, QObject *parent = nullptr);
|
explicit VersionList(const QString &uid, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
using Ptr = std::shared_ptr<VersionList>;
|
||||||
|
|
||||||
enum Roles
|
enum Roles
|
||||||
{
|
{
|
||||||
UidRole = Qt::UserRole + 100,
|
UidRole = Qt::UserRole + 100,
|
||||||
@ -43,11 +45,11 @@ public:
|
|||||||
|
|
||||||
Task::Ptr getLoadTask() override;
|
Task::Ptr getLoadTask() override;
|
||||||
bool isLoaded() override;
|
bool isLoaded() override;
|
||||||
const BaseVersionPtr at(int i) const override;
|
const BaseVersion::Ptr at(int i) const override;
|
||||||
int count() const override;
|
int count() const override;
|
||||||
void sortVersions() override;
|
void sortVersions() override;
|
||||||
|
|
||||||
BaseVersionPtr getRecommended() const override;
|
BaseVersion::Ptr getRecommended() const override;
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
RoleList providesRoles() const override;
|
RoleList providesRoles() const override;
|
||||||
@ -65,38 +67,38 @@ public:
|
|||||||
}
|
}
|
||||||
QString humanReadable() const;
|
QString humanReadable() const;
|
||||||
|
|
||||||
VersionPtr getVersion(const QString &version);
|
Version::Ptr getVersion(const QString &version);
|
||||||
bool hasVersion(QString version) const;
|
bool hasVersion(QString version) const;
|
||||||
|
|
||||||
QVector<VersionPtr> versions() const
|
QVector<Version::Ptr> versions() const
|
||||||
{
|
{
|
||||||
return m_versions;
|
return m_versions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public: // for usage only by parsers
|
public: // for usage only by parsers
|
||||||
void setName(const QString &name);
|
void setName(const QString &name);
|
||||||
void setVersions(const QVector<VersionPtr> &versions);
|
void setVersions(const QVector<Version::Ptr> &versions);
|
||||||
void merge(const VersionListPtr &other);
|
void merge(const VersionList::Ptr &other);
|
||||||
void mergeFromIndex(const VersionListPtr &other);
|
void mergeFromIndex(const VersionList::Ptr &other);
|
||||||
void parse(const QJsonObject &obj) override;
|
void parse(const QJsonObject &obj) override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void nameChanged(const QString &name);
|
void nameChanged(const QString &name);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void updateListData(QList<BaseVersionPtr>) override
|
void updateListData(QList<BaseVersion::Ptr>) override
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVector<VersionPtr> m_versions;
|
QVector<Version::Ptr> m_versions;
|
||||||
QHash<QString, VersionPtr> m_lookup;
|
QHash<QString, Version::Ptr> m_lookup;
|
||||||
QString m_uid;
|
QString m_uid;
|
||||||
QString m_name;
|
QString m_name;
|
||||||
|
|
||||||
VersionPtr m_recommended;
|
Version::Ptr m_recommended;
|
||||||
|
|
||||||
void setupAddedVersion(const int row, const VersionPtr &version);
|
void setupAddedVersion(const int row, const Version::Ptr &version);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Q_DECLARE_METATYPE(Meta::VersionListPtr)
|
Q_DECLARE_METATYPE(Meta::VersionList::Ptr)
|
||||||
|
@ -43,7 +43,6 @@
|
|||||||
#include "settings/SettingsObject.h"
|
#include "settings/SettingsObject.h"
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
|
||||||
#include "MMCStrings.h"
|
|
||||||
#include "pathmatcher/RegexpMatcher.h"
|
#include "pathmatcher/RegexpMatcher.h"
|
||||||
#include "pathmatcher/MultiMatcher.h"
|
#include "pathmatcher/MultiMatcher.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#include "minecraft/PackProfile.h"
|
#include "minecraft/PackProfile.h"
|
||||||
#include "settings/INISettingsObject.h"
|
#include "settings/INISettingsObject.h"
|
||||||
|
|
||||||
VanillaCreationTask::VanillaCreationTask(BaseVersionPtr version, QString loader, BaseVersionPtr loader_version)
|
VanillaCreationTask::VanillaCreationTask(BaseVersion::Ptr version, QString loader, BaseVersion::Ptr loader_version)
|
||||||
: InstanceCreationTask(), m_version(std::move(version)), m_using_loader(true), m_loader(std::move(loader)), m_loader_version(std::move(loader_version))
|
: InstanceCreationTask(), m_version(std::move(version)), m_using_loader(true), m_loader(std::move(loader)), m_loader_version(std::move(loader_version))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -7,16 +7,16 @@
|
|||||||
class VanillaCreationTask final : public InstanceCreationTask {
|
class VanillaCreationTask final : public InstanceCreationTask {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
VanillaCreationTask(BaseVersionPtr version) : InstanceCreationTask(), m_version(std::move(version)) {}
|
VanillaCreationTask(BaseVersion::Ptr version) : InstanceCreationTask(), m_version(std::move(version)) {}
|
||||||
VanillaCreationTask(BaseVersionPtr version, QString loader, BaseVersionPtr loader_version);
|
VanillaCreationTask(BaseVersion::Ptr version, QString loader, BaseVersion::Ptr loader_version);
|
||||||
|
|
||||||
bool createInstance() override;
|
bool createInstance() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Version to update to / create of the instance.
|
// Version to update to / create of the instance.
|
||||||
BaseVersionPtr m_version;
|
BaseVersion::Ptr m_version;
|
||||||
|
|
||||||
bool m_using_loader = false;
|
bool m_using_loader = false;
|
||||||
QString m_loader;
|
QString m_loader;
|
||||||
BaseVersionPtr m_loader_version;
|
BaseVersion::Ptr m_loader_version;
|
||||||
};
|
};
|
||||||
|
@ -71,5 +71,7 @@ void VerifyJavaInstall::executeTask() {
|
|||||||
{
|
{
|
||||||
emit logLine(tr("Java version %1").arg(major), MessageLevel::Error);
|
emit logLine(tr("Java version %1").arg(major), MessageLevel::Error);
|
||||||
}
|
}
|
||||||
|
emit logLine(tr("Go to instance Java settings to change your Java version or disable the Java compatibility check if you know what you're doing."), MessageLevel::Error);
|
||||||
|
|
||||||
emitFailed(QString("Incompatible Java major version"));
|
emitFailed(QString("Incompatible Java major version"));
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ LocalModUpdateTask::LocalModUpdateTask(QDir index_dir, ModPlatform::IndexedPack&
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
SetFileAttributesA(index_dir.path().toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
|
SetFileAttributesW(index_dir.path().toStdWString().c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
|
|
||||||
namespace ATLauncher {
|
namespace ATLauncher {
|
||||||
|
|
||||||
static Meta::VersionPtr getComponentVersion(const QString& uid, const QString& version);
|
static Meta::Version::Ptr getComponentVersion(const QString& uid, const QString& version);
|
||||||
|
|
||||||
PackInstallTask::PackInstallTask(UserInteractionSupport *support, QString packName, QString version, InstallMode installMode)
|
PackInstallTask::PackInstallTask(UserInteractionSupport *support, QString packName, QString version, InstallMode installMode)
|
||||||
{
|
{
|
||||||
@ -736,7 +736,12 @@ void PackInstallTask::downloadMods()
|
|||||||
QVector<QString> selectedMods;
|
QVector<QString> selectedMods;
|
||||||
if (!optionalMods.isEmpty()) {
|
if (!optionalMods.isEmpty()) {
|
||||||
setStatus(tr("Selecting optional mods..."));
|
setStatus(tr("Selecting optional mods..."));
|
||||||
selectedMods = m_support->chooseOptionalMods(m_version, optionalMods);
|
auto mods = m_support->chooseOptionalMods(m_version, optionalMods);
|
||||||
|
if (!mods.has_value()) {
|
||||||
|
emitAborted();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectedMods = mods.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
setStatus(tr("Downloading mods..."));
|
setStatus(tr("Downloading mods..."));
|
||||||
@ -1032,7 +1037,7 @@ void PackInstallTask::install()
|
|||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Meta::VersionPtr getComponentVersion(const QString& uid, const QString& version)
|
static Meta::Version::Ptr getComponentVersion(const QString& uid, const QString& version)
|
||||||
{
|
{
|
||||||
auto vlist = APPLICATION->metadataIndex()->get(uid);
|
auto vlist = APPLICATION->metadataIndex()->get(uid);
|
||||||
if (!vlist)
|
if (!vlist)
|
||||||
|
@ -62,13 +62,13 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Requests a user interaction to select which optional mods should be installed.
|
* Requests a user interaction to select which optional mods should be installed.
|
||||||
*/
|
*/
|
||||||
virtual QVector<QString> chooseOptionalMods(PackVersion version, QVector<ATLauncher::VersionMod> mods) = 0;
|
virtual std::optional<QVector<QString>> chooseOptionalMods(PackVersion version, QVector<ATLauncher::VersionMod> mods) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests a user interaction to select a component version from a given version list
|
* Requests a user interaction to select a component version from a given version list
|
||||||
* and constrained to a given Minecraft version.
|
* and constrained to a given Minecraft version.
|
||||||
*/
|
*/
|
||||||
virtual QString chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion) = 0;
|
virtual QString chooseVersion(Meta::VersionList::Ptr vlist, QString minecraftVersion) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests a user interaction to display a message.
|
* Requests a user interaction to display a message.
|
||||||
@ -137,8 +137,8 @@ private:
|
|||||||
|
|
||||||
QString archivePath;
|
QString archivePath;
|
||||||
QStringList jarmods;
|
QStringList jarmods;
|
||||||
Meta::VersionPtr minecraftVersion;
|
Meta::Version::Ptr minecraftVersion;
|
||||||
QMap<QString, Meta::VersionPtr> componentsToInstall;
|
QMap<QString, Meta::Version::Ptr> componentsToInstall;
|
||||||
|
|
||||||
QFuture<std::optional<QStringList>> m_extractFuture;
|
QFuture<std::optional<QStringList>> m_extractFuture;
|
||||||
QFutureWatcher<std::optional<QStringList>> m_extractFutureWatcher;
|
QFutureWatcher<std::optional<QStringList>> m_extractFutureWatcher;
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#include "Json.h"
|
#include "Json.h"
|
||||||
#include "net/Upload.h"
|
#include "net/Upload.h"
|
||||||
|
|
||||||
|
#include "modplatform/modrinth/ModrinthPackIndex.h"
|
||||||
|
|
||||||
Flame::FileResolvingTask::FileResolvingTask(const shared_qobject_ptr<QNetworkAccessManager>& network, Flame::Manifest& toProcess)
|
Flame::FileResolvingTask::FileResolvingTask(const shared_qobject_ptr<QNetworkAccessManager>& network, Flame::Manifest& toProcess)
|
||||||
: m_network(network), m_toProcess(toProcess)
|
: m_network(network), m_toProcess(toProcess)
|
||||||
{}
|
{}
|
||||||
@ -12,6 +14,8 @@ bool Flame::FileResolvingTask::abort()
|
|||||||
bool aborted = true;
|
bool aborted = true;
|
||||||
if (m_dljob)
|
if (m_dljob)
|
||||||
aborted &= m_dljob->abort();
|
aborted &= m_dljob->abort();
|
||||||
|
if (m_checkJob)
|
||||||
|
aborted &= m_checkJob->abort();
|
||||||
return aborted ? Task::abort() : false;
|
return aborted ? Task::abort() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +44,7 @@ void Flame::FileResolvingTask::netJobFinished()
|
|||||||
setProgress(1, 3);
|
setProgress(1, 3);
|
||||||
int index = 0;
|
int index = 0;
|
||||||
// job to check modrinth for blocked projects
|
// job to check modrinth for blocked projects
|
||||||
auto job = new NetJob("Modrinth check", m_network);
|
m_checkJob = new NetJob("Modrinth check", m_network);
|
||||||
blockedProjects = QMap<File *,QByteArray *>();
|
blockedProjects = QMap<File *,QByteArray *>();
|
||||||
auto doc = Json::requireDocument(*result);
|
auto doc = Json::requireDocument(*result);
|
||||||
auto array = Json::requireArray(doc.object()["data"]);
|
auto array = Json::requireArray(doc.object()["data"]);
|
||||||
@ -60,15 +64,15 @@ void Flame::FileResolvingTask::netJobFinished()
|
|||||||
out.resolved = true;
|
out.resolved = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
job->addNetAction(dl);
|
m_checkJob->addNetAction(dl);
|
||||||
blockedProjects.insert(&out, output);
|
blockedProjects.insert(&out, output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
connect(job, &NetJob::finished, this, &Flame::FileResolvingTask::modrinthCheckFinished);
|
connect(m_checkJob.get(), &NetJob::finished, this, &Flame::FileResolvingTask::modrinthCheckFinished);
|
||||||
|
|
||||||
job->start();
|
m_checkJob->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Flame::FileResolvingTask::modrinthCheckFinished() {
|
void Flame::FileResolvingTask::modrinthCheckFinished() {
|
||||||
@ -82,18 +86,21 @@ void Flame::FileResolvingTask::modrinthCheckFinished() {
|
|||||||
delete bytes;
|
delete bytes;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(*bytes);
|
QJsonDocument doc = QJsonDocument::fromJson(*bytes);
|
||||||
auto obj = doc.object();
|
auto obj = doc.object();
|
||||||
auto array = Json::requireArray(obj,"files");
|
auto file = Modrinth::loadIndexedPackVersion(obj);
|
||||||
for (auto file: array) {
|
|
||||||
auto fileObj = Json::requireObject(file);
|
// If there's more than one mod loader for this version, we can't know for sure
|
||||||
auto primary = Json::requireBoolean(fileObj,"primary");
|
// which file is relative to each loader, so it's best to not use any one and
|
||||||
if (primary) {
|
// let the user download it manually.
|
||||||
out->url = Json::requireUrl(fileObj,"url");
|
if (file.loaders.size() <= 1) {
|
||||||
qDebug() << "Found alternative on modrinth " << out->fileName;
|
out->url = file.downloadUrl;
|
||||||
break;
|
qDebug() << "Found alternative on modrinth " << out->fileName;
|
||||||
}
|
} else {
|
||||||
|
out->resolved = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete bytes;
|
delete bytes;
|
||||||
}
|
}
|
||||||
//copy to an output list and filter out projects found on modrinth
|
//copy to an output list and filter out projects found on modrinth
|
||||||
|
@ -30,8 +30,9 @@ protected slots:
|
|||||||
private: /* data */
|
private: /* data */
|
||||||
shared_qobject_ptr<QNetworkAccessManager> m_network;
|
shared_qobject_ptr<QNetworkAccessManager> m_network;
|
||||||
Flame::Manifest m_toProcess;
|
Flame::Manifest m_toProcess;
|
||||||
std::shared_ptr<QByteArray> result;
|
std::shared_ptr<QByteArray> result;
|
||||||
NetJob::Ptr m_dljob;
|
NetJob::Ptr m_dljob;
|
||||||
|
NetJob::Ptr m_checkJob;
|
||||||
|
|
||||||
void modrinthCheckFinished();
|
void modrinthCheckFinished();
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
#include <MurmurHash2.h>
|
#include <MurmurHash2.h>
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ void FlameHasher::executeTask()
|
|||||||
// CF-specific
|
// CF-specific
|
||||||
auto should_filter_out = [](char c) { return (c == 9 || c == 10 || c == 13 || c == 32); };
|
auto should_filter_out = [](char c) { return (c == 9 || c == 10 || c == 13 || c == 32); };
|
||||||
|
|
||||||
std::ifstream file_stream(m_path.toStdString(), std::ifstream::binary);
|
std::ifstream file_stream(StringUtils::toStdString(m_path), std::ifstream::binary);
|
||||||
// TODO: This is very heavy work, but apparently QtConcurrent can't use move semantics, so we can't boop this to another thread.
|
// TODO: This is very heavy work, but apparently QtConcurrent can't use move semantics, so we can't boop this to another thread.
|
||||||
// How do we make this non-blocking then?
|
// How do we make this non-blocking then?
|
||||||
m_hash = QString::number(MurmurHash2(std::move(file_stream), 4 * MiB, should_filter_out));
|
m_hash = QString::number(MurmurHash2(std::move(file_stream), 4 * MiB, should_filter_out));
|
||||||
|
@ -15,6 +15,7 @@ void NetworkModAPI::searchMods(CallerType* caller, SearchArgs&& args) const
|
|||||||
|
|
||||||
QObject::connect(netJob, &NetJob::started, caller, [caller, netJob] { caller->setActiveJob(netJob); });
|
QObject::connect(netJob, &NetJob::started, caller, [caller, netJob] { caller->setActiveJob(netJob); });
|
||||||
QObject::connect(netJob, &NetJob::failed, caller, &CallerType::searchRequestFailed);
|
QObject::connect(netJob, &NetJob::failed, caller, &CallerType::searchRequestFailed);
|
||||||
|
QObject::connect(netJob, &NetJob::aborted, caller, &CallerType::searchRequestAborted);
|
||||||
QObject::connect(netJob, &NetJob::succeeded, caller, [caller, response] {
|
QObject::connect(netJob, &NetJob::succeeded, caller, [caller, response] {
|
||||||
QJsonParseError parse_error{};
|
QJsonParseError parse_error{};
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
/*
|
/*
|
||||||
* PolyMC - Minecraft Launcher
|
* PolyMC - Minecraft Launcher
|
||||||
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, version 3.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public 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/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ModrinthPackIndex.h"
|
#include "ModrinthPackIndex.h"
|
||||||
#include "ModrinthAPI.h"
|
#include "ModrinthAPI.h"
|
||||||
@ -35,7 +35,7 @@ void Modrinth::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj)
|
|||||||
|
|
||||||
pack.provider = ModPlatform::Provider::MODRINTH;
|
pack.provider = ModPlatform::Provider::MODRINTH;
|
||||||
pack.name = Json::requireString(obj, "title");
|
pack.name = Json::requireString(obj, "title");
|
||||||
|
|
||||||
pack.slug = Json::ensureString(obj, "slug", "");
|
pack.slug = Json::ensureString(obj, "slug", "");
|
||||||
if (!pack.slug.isEmpty())
|
if (!pack.slug.isEmpty())
|
||||||
pack.websiteUrl = "https://modrinth.com/mod/" + pack.slug;
|
pack.websiteUrl = "https://modrinth.com/mod/" + pack.slug;
|
||||||
@ -59,23 +59,23 @@ void Modrinth::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj)
|
|||||||
void Modrinth::loadExtraPackData(ModPlatform::IndexedPack& pack, QJsonObject& obj)
|
void Modrinth::loadExtraPackData(ModPlatform::IndexedPack& pack, QJsonObject& obj)
|
||||||
{
|
{
|
||||||
pack.extraData.issuesUrl = Json::ensureString(obj, "issues_url");
|
pack.extraData.issuesUrl = Json::ensureString(obj, "issues_url");
|
||||||
if(pack.extraData.issuesUrl.endsWith('/'))
|
if (pack.extraData.issuesUrl.endsWith('/'))
|
||||||
pack.extraData.issuesUrl.chop(1);
|
pack.extraData.issuesUrl.chop(1);
|
||||||
|
|
||||||
pack.extraData.sourceUrl = Json::ensureString(obj, "source_url");
|
pack.extraData.sourceUrl = Json::ensureString(obj, "source_url");
|
||||||
if(pack.extraData.sourceUrl.endsWith('/'))
|
if (pack.extraData.sourceUrl.endsWith('/'))
|
||||||
pack.extraData.sourceUrl.chop(1);
|
pack.extraData.sourceUrl.chop(1);
|
||||||
|
|
||||||
pack.extraData.wikiUrl = Json::ensureString(obj, "wiki_url");
|
pack.extraData.wikiUrl = Json::ensureString(obj, "wiki_url");
|
||||||
if(pack.extraData.wikiUrl.endsWith('/'))
|
if (pack.extraData.wikiUrl.endsWith('/'))
|
||||||
pack.extraData.wikiUrl.chop(1);
|
pack.extraData.wikiUrl.chop(1);
|
||||||
|
|
||||||
pack.extraData.discordUrl = Json::ensureString(obj, "discord_url");
|
pack.extraData.discordUrl = Json::ensureString(obj, "discord_url");
|
||||||
if(pack.extraData.discordUrl.endsWith('/'))
|
if (pack.extraData.discordUrl.endsWith('/'))
|
||||||
pack.extraData.discordUrl.chop(1);
|
pack.extraData.discordUrl.chop(1);
|
||||||
|
|
||||||
auto donate_arr = Json::ensureArray(obj, "donation_urls");
|
auto donate_arr = Json::ensureArray(obj, "donation_urls");
|
||||||
for(auto d : donate_arr){
|
for (auto d : donate_arr) {
|
||||||
auto d_obj = Json::requireObject(d);
|
auto d_obj = Json::requireObject(d);
|
||||||
|
|
||||||
ModPlatform::DonationData donate;
|
ModPlatform::DonationData donate;
|
||||||
@ -104,7 +104,7 @@ void Modrinth::loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
|
|||||||
auto obj = versionIter.toObject();
|
auto obj = versionIter.toObject();
|
||||||
auto file = loadIndexedPackVersion(obj);
|
auto file = loadIndexedPackVersion(obj);
|
||||||
|
|
||||||
if(file.fileId.isValid()) // Heuristic to check if the returned value is valid
|
if (file.fileId.isValid()) // Heuristic to check if the returned value is valid
|
||||||
unsortedVersions.append(file);
|
unsortedVersions.append(file);
|
||||||
}
|
}
|
||||||
auto orderSortPredicate = [](const ModPlatform::IndexedVersion& a, const ModPlatform::IndexedVersion& b) -> bool {
|
auto orderSortPredicate = [](const ModPlatform::IndexedVersion& a, const ModPlatform::IndexedVersion& b) -> bool {
|
||||||
@ -116,7 +116,8 @@ void Modrinth::loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
|
|||||||
pack.versionsLoaded = true;
|
pack.versionsLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Modrinth::loadIndexedPackVersion(QJsonObject &obj, QString preferred_hash_type, QString preferred_file_name) -> ModPlatform::IndexedVersion
|
auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_type, QString preferred_file_name)
|
||||||
|
-> ModPlatform::IndexedVersion
|
||||||
{
|
{
|
||||||
ModPlatform::IndexedVersion file;
|
ModPlatform::IndexedVersion file;
|
||||||
|
|
||||||
@ -141,6 +142,12 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject &obj, QString preferred_hash_t
|
|||||||
auto files = Json::requireArray(obj, "files");
|
auto files = Json::requireArray(obj, "files");
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
|
if (files.empty()) {
|
||||||
|
// This should not happen normally, but check just in case
|
||||||
|
qWarning() << "Modrinth returned an unexpected empty list of files:" << obj;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
// Find correct file (needed in cases where one version may have multiple files)
|
// Find correct file (needed in cases where one version may have multiple files)
|
||||||
// Will default to the last one if there's no primary (though I think Modrinth requires that
|
// Will default to the last one if there's no primary (though I think Modrinth requires that
|
||||||
// at least one file is primary, idk)
|
// at least one file is primary, idk)
|
||||||
@ -167,7 +174,7 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject &obj, QString preferred_hash_t
|
|||||||
file.fileName = Json::requireString(parent, "filename");
|
file.fileName = Json::requireString(parent, "filename");
|
||||||
file.is_preferred = Json::requireBoolean(parent, "primary") || (files.count() == 1);
|
file.is_preferred = Json::requireBoolean(parent, "primary") || (files.count() == 1);
|
||||||
auto hash_list = Json::requireObject(parent, "hashes");
|
auto hash_list = Json::requireObject(parent, "hashes");
|
||||||
|
|
||||||
if (hash_list.contains(preferred_hash_type)) {
|
if (hash_list.contains(preferred_hash_type)) {
|
||||||
file.hash = Json::requireString(hash_list, preferred_hash_type);
|
file.hash = Json::requireString(hash_list, preferred_hash_type);
|
||||||
file.hash_type = preferred_hash_type;
|
file.hash_type = preferred_hash_type;
|
||||||
|
@ -22,10 +22,14 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include <toml++/toml.h>
|
#include "FileSystem.h"
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
#include "minecraft/mod/Mod.h"
|
#include "minecraft/mod/Mod.h"
|
||||||
#include "modplatform/ModIndex.h"
|
#include "modplatform/ModIndex.h"
|
||||||
|
|
||||||
|
#include <toml++/toml.h>
|
||||||
|
|
||||||
namespace Packwiz {
|
namespace Packwiz {
|
||||||
|
|
||||||
auto getRealIndexName(QDir& index_dir, QString normalized_fname, bool should_find_match) -> QString
|
auto getRealIndexName(QDir& index_dir, QString normalized_fname, bool should_find_match) -> QString
|
||||||
@ -63,22 +67,22 @@ static inline auto indexFileName(QString const& mod_slug) -> QString
|
|||||||
static ModPlatform::ProviderCapabilities ProviderCaps;
|
static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||||
|
|
||||||
// Helper functions for extracting data from the TOML file
|
// Helper functions for extracting data from the TOML file
|
||||||
auto stringEntry(toml::table table, const std::string entry_name) -> QString
|
auto stringEntry(toml::table table, QString entry_name) -> QString
|
||||||
{
|
{
|
||||||
auto node = table[entry_name];
|
auto node = table[StringUtils::toStdString(entry_name)];
|
||||||
if (!node) {
|
if (!node) {
|
||||||
qCritical() << QString::fromStdString("Failed to read str property '" + entry_name + "' in mod metadata.");
|
qCritical() << "Failed to read str property '" + entry_name + "' in mod metadata.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return QString::fromStdString(node.value_or(""));
|
return node.value_or("");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto intEntry(toml::table table, const std::string entry_name) -> int
|
auto intEntry(toml::table table, QString entry_name) -> int
|
||||||
{
|
{
|
||||||
auto node = table[entry_name];
|
auto node = table[StringUtils::toStdString(entry_name)];
|
||||||
if (!node) {
|
if (!node) {
|
||||||
qCritical() << QString::fromStdString("Failed to read int property '" + entry_name + "' in mod metadata.");
|
qCritical() << "Failed to read int property '" + entry_name + "' in mod metadata.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,6 +149,8 @@ void V1::updateModIndex(QDir& index_dir, Mod& mod)
|
|||||||
// they want to do!
|
// they want to do!
|
||||||
if (index_file.exists()) {
|
if (index_file.exists()) {
|
||||||
index_file.remove();
|
index_file.remove();
|
||||||
|
} else {
|
||||||
|
FS::ensureFilePathExists(index_file.fileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!index_file.open(QIODevice::ReadWrite)) {
|
if (!index_file.open(QIODevice::ReadWrite)) {
|
||||||
@ -228,14 +234,14 @@ auto V1::getIndexForMod(QDir& index_dir, QString slug) -> Mod
|
|||||||
toml::table table;
|
toml::table table;
|
||||||
#if TOML_EXCEPTIONS
|
#if TOML_EXCEPTIONS
|
||||||
try {
|
try {
|
||||||
table = toml::parse_file(index_dir.absoluteFilePath(real_fname).toStdString());
|
table = toml::parse_file(StringUtils::toStdString(index_dir.absoluteFilePath(real_fname)));
|
||||||
} catch (const toml::parse_error& err) {
|
} catch (const toml::parse_error& err) {
|
||||||
qWarning() << QString("Could not open file %1!").arg(normalized_fname);
|
qWarning() << QString("Could not open file %1!").arg(normalized_fname);
|
||||||
qWarning() << "Reason: " << QString(err.what());
|
qWarning() << "Reason: " << QString(err.what());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
table = toml::parse_file(index_dir.absoluteFilePath(real_fname).toStdString());
|
table = toml::parse_file(StringUtils::toStdString(index_dir.absoluteFilePath(real_fname)));
|
||||||
if (!table) {
|
if (!table) {
|
||||||
qWarning() << QString("Could not open file %1!").arg(normalized_fname);
|
qWarning() << QString("Could not open file %1!").arg(normalized_fname);
|
||||||
qWarning() << "Reason: " << QString(table.error().what());
|
qWarning() << "Reason: " << QString(table.error().what());
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
struct toml_table_t;
|
|
||||||
class QDir;
|
class QDir;
|
||||||
|
|
||||||
// Mod from launcher/minecraft/mod/Mod.h
|
// Mod from launcher/minecraft/mod/Mod.h
|
||||||
@ -34,9 +33,6 @@ namespace Packwiz {
|
|||||||
|
|
||||||
auto getRealIndexName(QDir& index_dir, QString normalized_index_name, bool should_match = false) -> QString;
|
auto getRealIndexName(QDir& index_dir, QString normalized_index_name, bool should_match = false) -> QString;
|
||||||
|
|
||||||
auto stringEntry(toml_table_t* parent, const char* entry_name) -> QString;
|
|
||||||
auto intEntry(toml_table_t* parent, const char* entry_name) -> int;
|
|
||||||
|
|
||||||
class V1 {
|
class V1 {
|
||||||
public:
|
public:
|
||||||
struct Mod {
|
struct Mod {
|
||||||
|
@ -37,17 +37,21 @@
|
|||||||
</cc:Agent>
|
</cc:Agent>
|
||||||
</dc:contributor>
|
</dc:contributor>
|
||||||
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
|
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
|
||||||
<dc:rights>
|
|
||||||
<cc:Agent>
|
|
||||||
<dc:title>CC BY-SA 4.0</dc:title>
|
|
||||||
</cc:Agent>
|
|
||||||
</dc:rights>
|
|
||||||
<dc:publisher>
|
<dc:publisher>
|
||||||
<cc:Agent>
|
<cc:Agent>
|
||||||
<dc:title>Prism Launcher</dc:title>
|
<dc:title>Prism Launcher</dc:title>
|
||||||
</cc:Agent>
|
</cc:Agent>
|
||||||
</dc:publisher>
|
</dc:publisher>
|
||||||
|
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
|
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
|
||||||
|
</cc:License>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
</metadata>
|
</metadata>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.4 KiB |
@ -37,17 +37,21 @@
|
|||||||
</cc:Agent>
|
</cc:Agent>
|
||||||
</dc:contributor>
|
</dc:contributor>
|
||||||
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
|
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
|
||||||
<dc:rights>
|
|
||||||
<cc:Agent>
|
|
||||||
<dc:title>CC BY-SA 4.0</dc:title>
|
|
||||||
</cc:Agent>
|
|
||||||
</dc:rights>
|
|
||||||
<dc:publisher>
|
<dc:publisher>
|
||||||
<cc:Agent>
|
<cc:Agent>
|
||||||
<dc:title>Prism Launcher</dc:title>
|
<dc:title>Prism Launcher</dc:title>
|
||||||
</cc:Agent>
|
</cc:Agent>
|
||||||
</dc:publisher>
|
</dc:publisher>
|
||||||
|
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
|
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
|
||||||
|
</cc:License>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
</metadata>
|
</metadata>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.4 KiB |
@ -37,17 +37,21 @@
|
|||||||
</cc:Agent>
|
</cc:Agent>
|
||||||
</dc:contributor>
|
</dc:contributor>
|
||||||
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
|
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
|
||||||
<dc:rights>
|
|
||||||
<cc:Agent>
|
|
||||||
<dc:title>CC BY-SA 4.0</dc:title>
|
|
||||||
</cc:Agent>
|
|
||||||
</dc:rights>
|
|
||||||
<dc:publisher>
|
<dc:publisher>
|
||||||
<cc:Agent>
|
<cc:Agent>
|
||||||
<dc:title>Prism Launcher</dc:title>
|
<dc:title>Prism Launcher</dc:title>
|
||||||
</cc:Agent>
|
</cc:Agent>
|
||||||
</dc:publisher>
|
</dc:publisher>
|
||||||
|
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
|
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
|
||||||
|
</cc:License>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
</metadata>
|
</metadata>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.4 KiB |
@ -37,17 +37,21 @@
|
|||||||
</cc:Agent>
|
</cc:Agent>
|
||||||
</dc:contributor>
|
</dc:contributor>
|
||||||
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
|
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
|
||||||
<dc:rights>
|
|
||||||
<cc:Agent>
|
|
||||||
<dc:title>CC BY-SA 4.0</dc:title>
|
|
||||||
</cc:Agent>
|
|
||||||
</dc:rights>
|
|
||||||
<dc:publisher>
|
<dc:publisher>
|
||||||
<cc:Agent>
|
<cc:Agent>
|
||||||
<dc:title>Prism Launcher</dc:title>
|
<dc:title>Prism Launcher</dc:title>
|
||||||
</cc:Agent>
|
</cc:Agent>
|
||||||
</dc:publisher>
|
</dc:publisher>
|
||||||
|
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
|
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
|
||||||
|
</cc:License>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
</metadata>
|
</metadata>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.4 KiB |
@ -37,17 +37,21 @@
|
|||||||
</cc:Agent>
|
</cc:Agent>
|
||||||
</dc:contributor>
|
</dc:contributor>
|
||||||
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
|
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
|
||||||
<dc:rights>
|
|
||||||
<cc:Agent>
|
|
||||||
<dc:title>CC BY-SA 4.0</dc:title>
|
|
||||||
</cc:Agent>
|
|
||||||
</dc:rights>
|
|
||||||
<dc:publisher>
|
<dc:publisher>
|
||||||
<cc:Agent>
|
<cc:Agent>
|
||||||
<dc:title>Prism Launcher</dc:title>
|
<dc:title>Prism Launcher</dc:title>
|
||||||
</cc:Agent>
|
</cc:Agent>
|
||||||
</dc:publisher>
|
</dc:publisher>
|
||||||
|
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
|
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
|
||||||
|
</cc:License>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
</metadata>
|
</metadata>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.4 KiB |
@ -37,17 +37,21 @@
|
|||||||
</cc:Agent>
|
</cc:Agent>
|
||||||
</dc:contributor>
|
</dc:contributor>
|
||||||
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
|
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
|
||||||
<dc:rights>
|
|
||||||
<cc:Agent>
|
|
||||||
<dc:title>CC BY-SA 4.0</dc:title>
|
|
||||||
</cc:Agent>
|
|
||||||
</dc:rights>
|
|
||||||
<dc:publisher>
|
<dc:publisher>
|
||||||
<cc:Agent>
|
<cc:Agent>
|
||||||
<dc:title>Prism Launcher</dc:title>
|
<dc:title>Prism Launcher</dc:title>
|
||||||
</cc:Agent>
|
</cc:Agent>
|
||||||
</dc:publisher>
|
</dc:publisher>
|
||||||
|
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
|
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
|
||||||
|
</cc:License>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
</metadata>
|
</metadata>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.4 KiB |
@ -37,17 +37,21 @@
|
|||||||
</cc:Agent>
|
</cc:Agent>
|
||||||
</dc:contributor>
|
</dc:contributor>
|
||||||
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
|
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
|
||||||
<dc:rights>
|
|
||||||
<cc:Agent>
|
|
||||||
<dc:title>CC BY-SA 4.0</dc:title>
|
|
||||||
</cc:Agent>
|
|
||||||
</dc:rights>
|
|
||||||
<dc:publisher>
|
<dc:publisher>
|
||||||
<cc:Agent>
|
<cc:Agent>
|
||||||
<dc:title>Prism Launcher</dc:title>
|
<dc:title>Prism Launcher</dc:title>
|
||||||
</cc:Agent>
|
</cc:Agent>
|
||||||
</dc:publisher>
|
</dc:publisher>
|
||||||
|
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
|
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
|
||||||
|
</cc:License>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
</metadata>
|
</metadata>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.4 KiB |
@ -37,17 +37,21 @@
|
|||||||
</cc:Agent>
|
</cc:Agent>
|
||||||
</dc:contributor>
|
</dc:contributor>
|
||||||
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
|
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
|
||||||
<dc:rights>
|
|
||||||
<cc:Agent>
|
|
||||||
<dc:title>CC BY-SA 4.0</dc:title>
|
|
||||||
</cc:Agent>
|
|
||||||
</dc:rights>
|
|
||||||
<dc:publisher>
|
<dc:publisher>
|
||||||
<cc:Agent>
|
<cc:Agent>
|
||||||
<dc:title>Prism Launcher</dc:title>
|
<dc:title>Prism Launcher</dc:title>
|
||||||
</cc:Agent>
|
</cc:Agent>
|
||||||
</dc:publisher>
|
</dc:publisher>
|
||||||
|
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
|
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
|
||||||
|
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
|
||||||
|
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
|
||||||
|
</cc:License>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
</metadata>
|
</metadata>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.4 KiB |
@ -153,7 +153,7 @@ QString Task::describe()
|
|||||||
auto name = objectName();
|
auto name = objectName();
|
||||||
if(name.isEmpty())
|
if(name.isEmpty())
|
||||||
{
|
{
|
||||||
out << QString("0x%1").arg((quintptr)this, 0, 16);
|
out << QString("0x%1").arg(reinterpret_cast<quintptr>(this), 0, 16);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -83,6 +83,12 @@ struct Language
|
|||||||
else if(key == "es_UY") {
|
else if(key == "es_UY") {
|
||||||
result = u8"español de Latinoamérica";
|
result = u8"español de Latinoamérica";
|
||||||
}
|
}
|
||||||
|
else if(key == "en@pirate") {
|
||||||
|
result = u8"Tongue of the High Seas";
|
||||||
|
}
|
||||||
|
else if(key == "en@uwu") {
|
||||||
|
result = u8"Cute Engwish";
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
result = locale.nativeLanguageName();
|
result = locale.nativeLanguageName();
|
||||||
}
|
}
|
||||||
|
@ -335,11 +335,10 @@ public:
|
|||||||
all_actions.append(&actionSettings);
|
all_actions.append(&actionSettings);
|
||||||
|
|
||||||
actionUndoTrashInstance = TranslatedAction(MainWindow);
|
actionUndoTrashInstance = TranslatedAction(MainWindow);
|
||||||
connect(actionUndoTrashInstance, SIGNAL(triggered(bool)), MainWindow, SLOT(undoTrashInstance()));
|
|
||||||
actionUndoTrashInstance->setObjectName(QStringLiteral("actionUndoTrashInstance"));
|
actionUndoTrashInstance->setObjectName(QStringLiteral("actionUndoTrashInstance"));
|
||||||
actionUndoTrashInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Undo Last Instance Deletion"));
|
actionUndoTrashInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Undo Last Instance Deletion"));
|
||||||
actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething());
|
actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething());
|
||||||
actionUndoTrashInstance->setShortcut(QKeySequence("Ctrl+Z"));
|
actionUndoTrashInstance->setShortcut(QKeySequence::Undo);
|
||||||
all_actions.append(&actionUndoTrashInstance);
|
all_actions.append(&actionUndoTrashInstance);
|
||||||
|
|
||||||
actionClearMetadata = TranslatedAction(MainWindow);
|
actionClearMetadata = TranslatedAction(MainWindow);
|
||||||
@ -527,7 +526,7 @@ public:
|
|||||||
|
|
||||||
menuBar->addMenu(foldersMenu);
|
menuBar->addMenu(foldersMenu);
|
||||||
|
|
||||||
profileMenu = menuBar->addMenu(tr("&Profiles"));
|
profileMenu = menuBar->addMenu(tr("&Accounts"));
|
||||||
profileMenu->setSeparatorsCollapsible(false);
|
profileMenu->setSeparatorsCollapsible(false);
|
||||||
profileMenu->addAction(actionManageAccounts);
|
profileMenu->addAction(actionManageAccounts);
|
||||||
|
|
||||||
@ -1003,6 +1002,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connect(ui->actionUndoTrashInstance.operator->(), &QAction::triggered, this, &MainWindow::undoTrashInstance);
|
||||||
|
|
||||||
setSelectedInstanceById(APPLICATION->settings()->get("SelectedInstance").toString());
|
setSelectedInstanceById(APPLICATION->settings()->get("SelectedInstance").toString());
|
||||||
|
|
||||||
// removing this looks stupid
|
// removing this looks stupid
|
||||||
@ -1032,7 +1033,7 @@ void MainWindow::retranslateUi()
|
|||||||
accountMenuButton->setText(profileLabel);
|
accountMenuButton->setText(profileLabel);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
accountMenuButton->setText(tr("Profiles"));
|
accountMenuButton->setText(tr("Accounts"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_selectedInstance) {
|
if (m_selectedInstance) {
|
||||||
@ -1114,11 +1115,6 @@ void MainWindow::showInstanceContextMenu(const QPoint &pos)
|
|||||||
connect(actionDeleteGroup, SIGNAL(triggered(bool)), SLOT(deleteGroup()));
|
connect(actionDeleteGroup, SIGNAL(triggered(bool)), SLOT(deleteGroup()));
|
||||||
actions.append(actionDeleteGroup);
|
actions.append(actionDeleteGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
QAction *actionUndoTrashInstance = new QAction("Undo last trash instance", this);
|
|
||||||
connect(actionUndoTrashInstance, SIGNAL(triggered(bool)), SLOT(undoTrashInstance()));
|
|
||||||
actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething());
|
|
||||||
actions.append(actionUndoTrashInstance);
|
|
||||||
}
|
}
|
||||||
QMenu myMenu;
|
QMenu myMenu;
|
||||||
myMenu.addActions(actions);
|
myMenu.addActions(actions);
|
||||||
@ -1375,7 +1371,7 @@ void MainWindow::defaultAccountChanged()
|
|||||||
|
|
||||||
// Set the icon to the "no account" icon.
|
// Set the icon to the "no account" icon.
|
||||||
accountMenuButton->setIcon(APPLICATION->getThemedIcon("noaccount"));
|
accountMenuButton->setIcon(APPLICATION->getThemedIcon("noaccount"));
|
||||||
accountMenuButton->setText(tr("Profiles"));
|
accountMenuButton->setText(tr("Accounts"));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWindow::eventFilter(QObject *obj, QEvent *ev)
|
bool MainWindow::eventFilter(QObject *obj, QEvent *ev)
|
||||||
@ -1814,6 +1810,7 @@ void MainWindow::deleteGroup()
|
|||||||
void MainWindow::undoTrashInstance()
|
void MainWindow::undoTrashInstance()
|
||||||
{
|
{
|
||||||
APPLICATION->instances()->undoTrashInstance();
|
APPLICATION->instances()->undoTrashInstance();
|
||||||
|
ui->actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionViewInstanceFolder_triggered()
|
void MainWindow::on_actionViewInstanceFolder_triggered()
|
||||||
@ -1883,6 +1880,7 @@ void MainWindow::on_actionReportBug_triggered()
|
|||||||
void MainWindow::on_actionClearMetadata_triggered()
|
void MainWindow::on_actionClearMetadata_triggered()
|
||||||
{
|
{
|
||||||
APPLICATION->metacache()->evictAll();
|
APPLICATION->metacache()->evictAll();
|
||||||
|
APPLICATION->metacache()->SaveNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionOpenWiki_triggered()
|
void MainWindow::on_actionOpenWiki_triggered()
|
||||||
@ -1920,6 +1918,7 @@ void MainWindow::on_actionDeleteInstance_triggered()
|
|||||||
|
|
||||||
auto id = m_selectedInstance->id();
|
auto id = m_selectedInstance->id();
|
||||||
if (APPLICATION->instances()->trashInstance(id)) {
|
if (APPLICATION->instances()->trashInstance(id)) {
|
||||||
|
ui->actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,17 +73,12 @@ QString getCreditsHtml()
|
|||||||
stream << "<h3>" << QObject::tr("%1 Developers", "About Credits").arg(BuildConfig.LAUNCHER_DISPLAYNAME) << "</h3>\n";
|
stream << "<h3>" << QObject::tr("%1 Developers", "About Credits").arg(BuildConfig.LAUNCHER_DISPLAYNAME) << "</h3>\n";
|
||||||
stream << QString("<p>Sefa Eyeoglu (Scrumplex) %1</p>\n") .arg(getWebsite("https://scrumplex.net"));
|
stream << QString("<p>Sefa Eyeoglu (Scrumplex) %1</p>\n") .arg(getWebsite("https://scrumplex.net"));
|
||||||
stream << QString("<p>dada513 %1</p>\n") .arg(getGitHub("dada513"));
|
stream << QString("<p>dada513 %1</p>\n") .arg(getGitHub("dada513"));
|
||||||
stream << QString("<p>txtsd %1</p>\n") .arg(getGitHub("txtsd"));
|
stream << QString("<p>txtsd %1</p>\n") .arg(getWebsite("https://ihavea.quest"));
|
||||||
stream << QString("<p>timoreo %1</p>\n") .arg(getGitHub("timoreo22"));
|
stream << QString("<p>timoreo %1</p>\n") .arg(getGitHub("timoreo22"));
|
||||||
stream << QString("<p>Ezekiel Smith (ZekeSmith) %1</p>\n") .arg(getGitHub("ZekeSmith"));
|
stream << QString("<p>Ezekiel Smith (ZekeSmith) %1</p>\n") .arg(getGitHub("ZekeSmith"));
|
||||||
stream << QString("<p>cozyGalvinism %1</p>\n") .arg(getGitHub("cozyGalvinism"));
|
stream << QString("<p>cozyGalvinism %1</p>\n") .arg(getGitHub("cozyGalvinism"));
|
||||||
stream << "<br />\n";
|
|
||||||
|
|
||||||
//: %1 is the name of the launcher, determined at build time, e.g. "Prism Launcher Contributors"
|
|
||||||
stream << "<h3>" << QObject::tr("%1 Contributors", "About Credits").arg(BuildConfig.LAUNCHER_DISPLAYNAME) << "</h3>\n";
|
|
||||||
stream << QString("<p>DioEgizio %1</p>\n") .arg(getGitHub("DioEgizio"));
|
stream << QString("<p>DioEgizio %1</p>\n") .arg(getGitHub("DioEgizio"));
|
||||||
stream << QString("<p>flowln %1</p>\n") .arg(getGitHub("flowln"));
|
stream << QString("<p>flowln %1</p>\n") .arg(getGitHub("flowln"));
|
||||||
stream << QString("<p>swirl %1</p>\n") .arg(getWebsite("https://swurl.xyz/"));
|
|
||||||
stream << "<br />\n";
|
stream << "<br />\n";
|
||||||
|
|
||||||
// TODO: possibly retrieve from git history at build time?
|
// TODO: possibly retrieve from git history at build time?
|
||||||
@ -97,7 +92,7 @@ QString getCreditsHtml()
|
|||||||
stream << "<br />\n";
|
stream << "<br />\n";
|
||||||
|
|
||||||
stream << "<h3>" << QObject::tr("With thanks to", "About Credits") << "</h3>\n";
|
stream << "<h3>" << QObject::tr("With thanks to", "About Credits") << "</h3>\n";
|
||||||
stream << QString("<p>Boba %1</p>\n") .arg(getWebsite("https://cmdplusv.neocities.org/"));
|
stream << QString("<p>Boba %1</p>\n") .arg(getWebsite("https://bobaonline.neocities.org/"));
|
||||||
stream << QString("<p>Davi Rafael %1</p>\n") .arg(getWebsite("https://auti.one/"));
|
stream << QString("<p>Davi Rafael %1</p>\n") .arg(getWebsite("https://auti.one/"));
|
||||||
stream << QString("<p>Fulmine %1</p>\n") .arg(getWebsite("https://www.fulmine.xyz/"));
|
stream << QString("<p>Fulmine %1</p>\n") .arg(getWebsite("https://www.fulmine.xyz/"));
|
||||||
stream << QString("<p>ely %1</p>\n") .arg(getGitHub("elyrodso"));
|
stream << QString("<p>ely %1</p>\n") .arg(getGitHub("elyrodso"));
|
||||||
@ -172,7 +167,7 @@ AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDia
|
|||||||
QString urlText("<html><head/><body><p><a href=\"%1\">%1</a></p></body></html>");
|
QString urlText("<html><head/><body><p><a href=\"%1\">%1</a></p></body></html>");
|
||||||
ui->urlLabel->setText(urlText.arg(BuildConfig.LAUNCHER_GIT));
|
ui->urlLabel->setText(urlText.arg(BuildConfig.LAUNCHER_GIT));
|
||||||
|
|
||||||
QString copyText("© 2021-2022 %1");
|
QString copyText("© 2022 %1");
|
||||||
ui->copyLabel->setText(copyText.arg(BuildConfig.LAUNCHER_COPYRIGHT));
|
ui->copyLabel->setText(copyText.arg(BuildConfig.LAUNCHER_COPYRIGHT));
|
||||||
|
|
||||||
connect(ui->closeButton, SIGNAL(clicked()), SLOT(close()));
|
connect(ui->closeButton, SIGNAL(clicked()), SLOT(close()));
|
||||||
|
@ -87,14 +87,11 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item alignment="Qt::AlignHCenter">
|
||||||
<widget class="QLabel" name="versionLabel">
|
<widget class="QLabel" name="versionLabel">
|
||||||
<property name="cursor">
|
<property name="cursor">
|
||||||
<cursorShape>IBeamCursor</cursorShape>
|
<cursorShape>IBeamCursor</cursorShape>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignCenter</set>
|
|
||||||
</property>
|
|
||||||
<property name="textInteractionFlags">
|
<property name="textInteractionFlags">
|
||||||
<set>Qt::TextSelectableByMouse</set>
|
<set>Qt::TextSelectableByMouse</set>
|
||||||
</property>
|
</property>
|
||||||
@ -167,7 +164,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item alignment="Qt::AlignHCenter">
|
||||||
<widget class="QLabel" name="platformLabel">
|
<widget class="QLabel" name="platformLabel">
|
||||||
<property name="cursor">
|
<property name="cursor">
|
||||||
<cursorShape>IBeamCursor</cursorShape>
|
<cursorShape>IBeamCursor</cursorShape>
|
||||||
@ -183,7 +180,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item alignment="Qt::AlignHCenter">
|
||||||
<widget class="QLabel" name="buildDateLabel">
|
<widget class="QLabel" name="buildDateLabel">
|
||||||
<property name="cursor">
|
<property name="cursor">
|
||||||
<cursorShape>IBeamCursor</cursorShape>
|
<cursorShape>IBeamCursor</cursorShape>
|
||||||
@ -199,7 +196,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item alignment="Qt::AlignHCenter">
|
||||||
<widget class="QLabel" name="commitLabel">
|
<widget class="QLabel" name="commitLabel">
|
||||||
<property name="cursor">
|
<property name="cursor">
|
||||||
<cursorShape>IBeamCursor</cursorShape>
|
<cursorShape>IBeamCursor</cursorShape>
|
||||||
@ -215,7 +212,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item alignment="Qt::AlignHCenter">
|
||||||
<widget class="QLabel" name="channelLabel">
|
<widget class="QLabel" name="channelLabel">
|
||||||
<property name="cursor">
|
<property name="cursor">
|
||||||
<cursorShape>IBeamCursor</cursorShape>
|
<cursorShape>IBeamCursor</cursorShape>
|
||||||
|
@ -39,13 +39,12 @@
|
|||||||
#include <MMCZip.h>
|
#include <MMCZip.h>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <qfilesystemmodel.h>
|
#include <QFileSystemModel>
|
||||||
|
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <qstack.h>
|
|
||||||
#include <QSaveFile>
|
#include <QSaveFile>
|
||||||
#include "MMCStrings.h"
|
#include "StringUtils.h"
|
||||||
#include "SeparatorPrefixTree.h"
|
#include "SeparatorPrefixTree.h"
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include <icons/IconList.h>
|
#include <icons/IconList.h>
|
||||||
@ -85,7 +84,7 @@ public:
|
|||||||
// sort and proxy model breaks the original model...
|
// sort and proxy model breaks the original model...
|
||||||
if (sortColumn() == 0)
|
if (sortColumn() == 0)
|
||||||
{
|
{
|
||||||
return Strings::naturalCompare(leftFileInfo.fileName(), rightFileInfo.fileName(),
|
return StringUtils::naturalCompare(leftFileInfo.fileName(), rightFileInfo.fileName(),
|
||||||
Qt::CaseInsensitive) < 0;
|
Qt::CaseInsensitive) < 0;
|
||||||
}
|
}
|
||||||
if (sortColumn() == 1)
|
if (sortColumn() == 1)
|
||||||
@ -94,7 +93,7 @@ public:
|
|||||||
auto rightSize = rightFileInfo.size();
|
auto rightSize = rightFileInfo.size();
|
||||||
if ((leftSize == rightSize) || (leftFileInfo.isDir() && rightFileInfo.isDir()))
|
if ((leftSize == rightSize) || (leftFileInfo.isDir() && rightFileInfo.isDir()))
|
||||||
{
|
{
|
||||||
return Strings::naturalCompare(leftFileInfo.fileName(),
|
return StringUtils::naturalCompare(leftFileInfo.fileName(),
|
||||||
rightFileInfo.fileName(),
|
rightFileInfo.fileName(),
|
||||||
Qt::CaseInsensitive) < 0
|
Qt::CaseInsensitive) < 0
|
||||||
? asc
|
? asc
|
||||||
|
@ -366,33 +366,28 @@ void ModUpdateDialog::appendMod(CheckUpdateTask::UpdatableMod const& info)
|
|||||||
auto changelog = new QTreeWidgetItem(changelog_item);
|
auto changelog = new QTreeWidgetItem(changelog_item);
|
||||||
auto changelog_area = new QTextBrowser();
|
auto changelog_area = new QTextBrowser();
|
||||||
|
|
||||||
|
QString text = info.changelog;
|
||||||
switch (info.provider) {
|
switch (info.provider) {
|
||||||
case ModPlatform::Provider::MODRINTH: {
|
case ModPlatform::Provider::MODRINTH: {
|
||||||
HoeDown h;
|
HoeDown h;
|
||||||
// HoeDown bug?: \n aren't converted to <br>
|
// HoeDown bug?: \n aren't converted to <br>
|
||||||
auto text = h.process(info.changelog.toUtf8());
|
text = h.process(info.changelog.toUtf8());
|
||||||
|
|
||||||
// Don't convert if there's an HTML tag right after (Qt rendering weirdness)
|
// Don't convert if there's an HTML tag right after (Qt rendering weirdness)
|
||||||
text.remove(QRegularExpression("(\n+)(?=<)"));
|
text.remove(QRegularExpression("(\n+)(?=<)"));
|
||||||
text.replace('\n', "<br>");
|
text.replace('\n', "<br>");
|
||||||
|
|
||||||
changelog_area->setHtml(text);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ModPlatform::Provider::FLAME: {
|
default:
|
||||||
changelog_area->setHtml(info.changelog);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changelog_area->setHtml(text);
|
||||||
changelog_area->setOpenExternalLinks(true);
|
changelog_area->setOpenExternalLinks(true);
|
||||||
changelog_area->setLineWrapMode(QTextBrowser::LineWrapMode::NoWrap);
|
changelog_area->setLineWrapMode(QTextBrowser::LineWrapMode::WidgetWidth);
|
||||||
changelog_area->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded);
|
changelog_area->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded);
|
||||||
|
|
||||||
// HACK: Is there a better way of achieving this?
|
|
||||||
auto font_height = QFontMetrics(changelog_area->font()).height();
|
|
||||||
changelog_area->setMaximumHeight((changelog_area->toPlainText().count(QRegularExpression("\n|<br>")) + 2) * font_height);
|
|
||||||
|
|
||||||
ui->modTreeWidget->setItemWidget(changelog, 0, changelog_area);
|
ui->modTreeWidget->setItemWidget(changelog, 0, changelog_area);
|
||||||
|
|
||||||
ui->modTreeWidget->addTopLevelItem(item_top);
|
ui->modTreeWidget->addTopLevelItem(item_top);
|
||||||
|
@ -136,11 +136,13 @@ void ProgressDialog::onTaskStarted() {}
|
|||||||
void ProgressDialog::onTaskFailed(QString failure)
|
void ProgressDialog::onTaskFailed(QString failure)
|
||||||
{
|
{
|
||||||
reject();
|
reject();
|
||||||
|
hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgressDialog::onTaskSucceeded()
|
void ProgressDialog::onTaskSucceeded()
|
||||||
{
|
{
|
||||||
accept();
|
accept();
|
||||||
|
hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgressDialog::changeStatus(const QString& status)
|
void ProgressDialog::changeStatus(const QString& status)
|
||||||
|
@ -120,7 +120,7 @@ void VersionSelectDialog::selectRecommended()
|
|||||||
m_versionWidget->selectRecommended();
|
m_versionWidget->selectRecommended();
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseVersionPtr VersionSelectDialog::selectedVersion() const
|
BaseVersion::Ptr VersionSelectDialog::selectedVersion() const
|
||||||
{
|
{
|
||||||
return m_versionWidget->selectedVersion();
|
return m_versionWidget->selectedVersion();
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ public:
|
|||||||
|
|
||||||
int exec() override;
|
int exec() override;
|
||||||
|
|
||||||
BaseVersionPtr selectedVersion() const;
|
BaseVersion::Ptr selectedVersion() const;
|
||||||
|
|
||||||
void setCurrentVersion(const QString & version);
|
void setCurrentVersion(const QString & version);
|
||||||
void setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter);
|
void setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter);
|
||||||
|
@ -179,7 +179,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_4">
|
<widget class="QLabel" name="label_4">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Enter a custom client ID for Microsoft Authentication here. </string>
|
<string>Enter a custom client ID for Microsoft Authentication here.</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="textFormat">
|
<property name="textFormat">
|
||||||
<enum>Qt::RichText</enum>
|
<enum>Qt::RichText</enum>
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
|
#include "DesktopServices.h"
|
||||||
#include "ui/themes/ITheme.h"
|
#include "ui/themes/ITheme.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@ -143,11 +144,11 @@ void LauncherPage::on_instDirBrowseBtn_clicked()
|
|||||||
ui->instDirTextBox->setText(cooked_dir);
|
ui->instDirTextBox->setText(cooked_dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(APPLICATION->isFlatpak() && raw_dir.startsWith("/run/user"))
|
else if(DesktopServices::isFlatpak() && raw_dir.startsWith("/run/user"))
|
||||||
{
|
{
|
||||||
QMessageBox warning;
|
QMessageBox warning;
|
||||||
warning.setText(tr("You're trying to specify an instance folder "
|
warning.setText(tr("You're trying to specify an instance folder "
|
||||||
"which was granted temporaily via Flatpak.\n"
|
"which was granted temporarily via Flatpak.\n"
|
||||||
"This is known to cause problems. "
|
"This is known to cause problems. "
|
||||||
"After a restart the launcher might break, "
|
"After a restart the launcher might break, "
|
||||||
"because it will no longer have access to that directory.\n\n"
|
"because it will no longer have access to that directory.\n\n"
|
||||||
|
@ -27,11 +27,7 @@
|
|||||||
<item row="4" column="1" colspan="3">
|
<item row="4" column="1" colspan="3">
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QLineEdit" name="filterEdit">
|
<widget class="QLineEdit" name="filterEdit"/>
|
||||||
<property name="clearButtonEnabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="filterLabel">
|
<widget class="QLabel" name="filterLabel">
|
||||||
|
@ -48,11 +48,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QLineEdit" name="filterEdit">
|
<widget class="QLineEdit" name="filterEdit"/>
|
||||||
<property name="clearButtonEnabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="filterLabel">
|
<widget class="QLabel" name="filterLabel">
|
||||||
|
@ -267,18 +267,25 @@ void ListModel::searchRequestFailed(QString reason)
|
|||||||
.arg(m_parent->displayName())
|
.arg(m_parent->displayName())
|
||||||
.arg(tr("API version too old!\nPlease update %1!").arg(BuildConfig.LAUNCHER_DISPLAYNAME)));
|
.arg(tr("API version too old!\nPlease update %1!").arg(BuildConfig.LAUNCHER_DISPLAYNAME)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jobPtr.reset();
|
||||||
|
searchState = Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListModel::searchRequestAborted()
|
||||||
|
{
|
||||||
|
if (searchState != ResetRequested)
|
||||||
|
qCritical() << "Search task in ModModel aborted by an unknown reason!";
|
||||||
|
|
||||||
|
// Retry fetching
|
||||||
jobPtr.reset();
|
jobPtr.reset();
|
||||||
|
|
||||||
if (searchState == ResetRequested) {
|
beginResetModel();
|
||||||
beginResetModel();
|
modpacks.clear();
|
||||||
modpacks.clear();
|
endResetModel();
|
||||||
endResetModel();
|
|
||||||
|
|
||||||
nextSearchOffset = 0;
|
nextSearchOffset = 0;
|
||||||
performPaginatedSearch();
|
performPaginatedSearch();
|
||||||
} else {
|
|
||||||
searchState = Finished;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListModel::infoRequestFinished(QJsonDocument& doc, ModPlatform::IndexedPack& pack, const QModelIndex& index)
|
void ListModel::infoRequestFinished(QJsonDocument& doc, ModPlatform::IndexedPack& pack, const QModelIndex& index)
|
||||||
|
@ -51,6 +51,7 @@ class ListModel : public QAbstractListModel {
|
|||||||
public slots:
|
public slots:
|
||||||
void searchRequestFinished(QJsonDocument& doc);
|
void searchRequestFinished(QJsonDocument& doc);
|
||||||
void searchRequestFailed(QString reason);
|
void searchRequestFailed(QString reason);
|
||||||
|
void searchRequestAborted();
|
||||||
|
|
||||||
void infoRequestFinished(QJsonDocument& doc, ModPlatform::IndexedPack& pack, const QModelIndex& index);
|
void infoRequestFinished(QJsonDocument& doc, ModPlatform::IndexedPack& pack, const QModelIndex& index);
|
||||||
|
|
||||||
|
@ -187,12 +187,12 @@ void VanillaPage::retranslate()
|
|||||||
ui->retranslateUi(this);
|
ui->retranslateUi(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseVersionPtr VanillaPage::selectedVersion() const
|
BaseVersion::Ptr VanillaPage::selectedVersion() const
|
||||||
{
|
{
|
||||||
return m_selectedVersion;
|
return m_selectedVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseVersionPtr VanillaPage::selectedLoaderVersion() const
|
BaseVersion::Ptr VanillaPage::selectedLoaderVersion() const
|
||||||
{
|
{
|
||||||
return m_selectedLoaderVersion;
|
return m_selectedLoaderVersion;
|
||||||
}
|
}
|
||||||
@ -227,14 +227,14 @@ void VanillaPage::suggestCurrent()
|
|||||||
dialog->setSuggestedIcon("default");
|
dialog->setSuggestedIcon("default");
|
||||||
}
|
}
|
||||||
|
|
||||||
void VanillaPage::setSelectedVersion(BaseVersionPtr version)
|
void VanillaPage::setSelectedVersion(BaseVersion::Ptr version)
|
||||||
{
|
{
|
||||||
m_selectedVersion = version;
|
m_selectedVersion = version;
|
||||||
suggestCurrent();
|
suggestCurrent();
|
||||||
loaderFilterChanged();
|
loaderFilterChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VanillaPage::setSelectedLoaderVersion(BaseVersionPtr version)
|
void VanillaPage::setSelectedLoaderVersion(BaseVersion::Ptr version)
|
||||||
{
|
{
|
||||||
m_selectedLoaderVersion = version;
|
m_selectedLoaderVersion = version;
|
||||||
suggestCurrent();
|
suggestCurrent();
|
||||||
|
@ -76,13 +76,13 @@ public:
|
|||||||
|
|
||||||
void openedImpl() override;
|
void openedImpl() override;
|
||||||
|
|
||||||
BaseVersionPtr selectedVersion() const;
|
BaseVersion::Ptr selectedVersion() const;
|
||||||
BaseVersionPtr selectedLoaderVersion() const;
|
BaseVersion::Ptr selectedLoaderVersion() const;
|
||||||
QString selectedLoader() const;
|
QString selectedLoader() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setSelectedVersion(BaseVersionPtr version);
|
void setSelectedVersion(BaseVersion::Ptr version);
|
||||||
void setSelectedLoaderVersion(BaseVersionPtr version);
|
void setSelectedLoaderVersion(BaseVersion::Ptr version);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void filterChanged();
|
void filterChanged();
|
||||||
@ -98,7 +98,7 @@ private:
|
|||||||
NewInstanceDialog *dialog = nullptr;
|
NewInstanceDialog *dialog = nullptr;
|
||||||
Ui::VanillaPage *ui = nullptr;
|
Ui::VanillaPage *ui = nullptr;
|
||||||
bool m_versionSetByUser = false;
|
bool m_versionSetByUser = false;
|
||||||
BaseVersionPtr m_selectedVersion;
|
BaseVersion::Ptr m_selectedVersion;
|
||||||
BaseVersionPtr m_selectedLoaderVersion;
|
BaseVersion::Ptr m_selectedLoaderVersion;
|
||||||
QString m_selectedLoader;
|
QString m_selectedLoader;
|
||||||
};
|
};
|
||||||
|
@ -20,7 +20,8 @@
|
|||||||
|
|
||||||
#include <modplatform/atlauncher/ATLPackIndex.h>
|
#include <modplatform/atlauncher/ATLPackIndex.h>
|
||||||
#include <Version.h>
|
#include <Version.h>
|
||||||
#include <MMCStrings.h>
|
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
namespace Atl {
|
namespace Atl {
|
||||||
|
|
||||||
@ -86,7 +87,7 @@ bool FilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) co
|
|||||||
return lv < rv;
|
return lv < rv;
|
||||||
}
|
}
|
||||||
else if (currentSorting == ByName) {
|
else if (currentSorting == ByName) {
|
||||||
return Strings::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
|
return StringUtils::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalid sorting set, somehow...
|
// Invalid sorting set, somehow...
|
||||||
|
@ -331,7 +331,7 @@ AtlOptionalModDialog::AtlOptionalModDialog(QWidget* parent, ATLauncher::PackVers
|
|||||||
connect(ui->clearAllButton, &QPushButton::clicked,
|
connect(ui->clearAllButton, &QPushButton::clicked,
|
||||||
listModel, &AtlOptionalModListModel::clearAll);
|
listModel, &AtlOptionalModListModel::clearAll);
|
||||||
connect(ui->installButton, &QPushButton::clicked,
|
connect(ui->installButton, &QPushButton::clicked,
|
||||||
this, &QDialog::close);
|
this, &QDialog::accept);
|
||||||
}
|
}
|
||||||
|
|
||||||
AtlOptionalModDialog::~AtlOptionalModDialog() {
|
AtlOptionalModDialog::~AtlOptionalModDialog() {
|
||||||
|
@ -43,14 +43,17 @@ AtlUserInteractionSupportImpl::AtlUserInteractionSupportImpl(QWidget *parent) :
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<QString> AtlUserInteractionSupportImpl::chooseOptionalMods(ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods)
|
std::optional<QVector<QString>> AtlUserInteractionSupportImpl::chooseOptionalMods(ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods)
|
||||||
{
|
{
|
||||||
AtlOptionalModDialog optionalModDialog(m_parent, version, mods);
|
AtlOptionalModDialog optionalModDialog(m_parent, version, mods);
|
||||||
optionalModDialog.exec();
|
auto result = optionalModDialog.exec();
|
||||||
|
if (result == QDialog::Rejected) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
return optionalModDialog.getResult();
|
return optionalModDialog.getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AtlUserInteractionSupportImpl::chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion)
|
QString AtlUserInteractionSupportImpl::chooseVersion(Meta::VersionList::Ptr vlist, QString minecraftVersion)
|
||||||
{
|
{
|
||||||
VersionSelectDialog vselect(vlist.get(), "Choose Version", m_parent, false);
|
VersionSelectDialog vselect(vlist.get(), "Choose Version", m_parent, false);
|
||||||
if (minecraftVersion != nullptr) {
|
if (minecraftVersion != nullptr) {
|
||||||
|
@ -46,8 +46,8 @@ public:
|
|||||||
AtlUserInteractionSupportImpl(QWidget* parent);
|
AtlUserInteractionSupportImpl(QWidget* parent);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion) override;
|
QString chooseVersion(Meta::VersionList::Ptr vlist, QString minecraftVersion) override;
|
||||||
QVector<QString> chooseOptionalMods(ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods) override;
|
std::optional<QVector<QString>> chooseOptionalMods(ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods) override;
|
||||||
void displayMessage(QString message) override;
|
void displayMessage(QString message) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include <Json.h>
|
#include <Json.h>
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
|
||||||
#include <MMCStrings.h>
|
|
||||||
#include <Version.h>
|
#include <Version.h>
|
||||||
|
|
||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
|
@ -19,7 +19,8 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "modplatform/modpacksch/FTBPackManifest.h"
|
#include "modplatform/modpacksch/FTBPackManifest.h"
|
||||||
#include <MMCStrings.h>
|
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
namespace Ftb {
|
namespace Ftb {
|
||||||
|
|
||||||
@ -81,7 +82,7 @@ bool FilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) co
|
|||||||
return leftPack.installs < rightPack.installs;
|
return leftPack.installs < rightPack.installs;
|
||||||
}
|
}
|
||||||
else if (currentSorting == ByName) {
|
else if (currentSorting == ByName) {
|
||||||
return Strings::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
|
return StringUtils::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalid sorting set, somehow...
|
// Invalid sorting set, somehow...
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
#include "ListModel.h"
|
#include "ListModel.h"
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
|
||||||
#include <MMCStrings.h>
|
#include "StringUtils.h"
|
||||||
#include <Version.h>
|
#include <Version.h>
|
||||||
|
|
||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
@ -66,7 +66,7 @@ bool FilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) co
|
|||||||
return lv < rv;
|
return lv < rv;
|
||||||
|
|
||||||
} else if(currentSorting == Sorting::ByName) {
|
} else if(currentSorting == Sorting::ByName) {
|
||||||
return Strings::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
|
return StringUtils::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//UHM, some inavlid value set?!
|
//UHM, some inavlid value set?!
|
||||||
|
@ -31,7 +31,7 @@ QPalette DarkTheme::colorScheme()
|
|||||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||||
darkPalette.setColor(QPalette::BrightText, Qt::red);
|
darkPalette.setColor(QPalette::BrightText, Qt::red);
|
||||||
darkPalette.setColor(QPalette::Link, QColor(47,163,198));
|
darkPalette.setColor(QPalette::Link, QColor(47,163,198));
|
||||||
darkPalette.setColor(QPalette::Highlight, QColor(145,205,92));
|
darkPalette.setColor(QPalette::Highlight, QColor(150,219,89));
|
||||||
darkPalette.setColor(QPalette::HighlightedText, Qt::black);
|
darkPalette.setColor(QPalette::HighlightedText, Qt::black);
|
||||||
darkPalette.setColor(QPalette::PlaceholderText, Qt::darkGray);
|
darkPalette.setColor(QPalette::PlaceholderText, Qt::darkGray);
|
||||||
return fadeInactive(darkPalette, fadeAmount(), fadeColor());
|
return fadeInactive(darkPalette, fadeAmount(), fadeColor());
|
||||||
|
@ -245,7 +245,7 @@ void JavaSettingsWidget::memoryValueChanged(int)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaSettingsWidget::javaVersionSelected(BaseVersionPtr version)
|
void JavaSettingsWidget::javaVersionSelected(BaseVersion::Ptr version)
|
||||||
{
|
{
|
||||||
auto java = std::dynamic_pointer_cast<JavaInstall>(version);
|
auto java = std::dynamic_pointer_cast<JavaInstall>(version);
|
||||||
if(!java)
|
if(!java)
|
||||||
|
@ -60,7 +60,7 @@ public:
|
|||||||
protected slots:
|
protected slots:
|
||||||
void memoryValueChanged(int);
|
void memoryValueChanged(int);
|
||||||
void javaPathEdited(const QString &path);
|
void javaPathEdited(const QString &path);
|
||||||
void javaVersionSelected(BaseVersionPtr version);
|
void javaVersionSelected(BaseVersion::Ptr version);
|
||||||
void on_javaBrowseBtn_clicked();
|
void on_javaBrowseBtn_clicked();
|
||||||
void on_javaStatusBtn_clicked();
|
void on_javaStatusBtn_clicked();
|
||||||
void checkFinished(JavaCheckResult result);
|
void checkFinished(JavaCheckResult result);
|
||||||
|
@ -49,7 +49,7 @@ public:
|
|||||||
auto getFilter() -> std::shared_ptr<Filter>;
|
auto getFilter() -> std::shared_ptr<Filter>;
|
||||||
auto changed() const -> bool { return m_last_version_id != m_version_id; }
|
auto changed() const -> bool { return m_last_version_id != m_version_id; }
|
||||||
|
|
||||||
Meta::VersionListPtr versionList() { return m_version_list; }
|
Meta::VersionList::Ptr versionList() { return m_version_list; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ModFilterWidget(Version def, QWidget* parent = nullptr);
|
ModFilterWidget(Version def, QWidget* parent = nullptr);
|
||||||
@ -73,7 +73,7 @@ private:
|
|||||||
/* Version stuff */
|
/* Version stuff */
|
||||||
QButtonGroup m_mcVersion_buttons;
|
QButtonGroup m_mcVersion_buttons;
|
||||||
|
|
||||||
Meta::VersionListPtr m_version_list;
|
Meta::VersionList::Ptr m_version_list;
|
||||||
|
|
||||||
/* Used to tell if the filter was changed since the last getFilter() call */
|
/* Used to tell if the filter was changed since the last getFilter() call */
|
||||||
VersionButtonID m_last_version_id = VersionButtonID::Strict;
|
VersionButtonID m_last_version_id = VersionButtonID::Strict;
|
||||||
|
@ -51,6 +51,8 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o
|
|||||||
auto remaining_width = rect.width() - icon_width - 2 * icon_x_margin;
|
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());
|
rect.setRect(rect.x() + icon_width + 2 * icon_x_margin, rect.y(), remaining_width, rect.height());
|
||||||
|
|
||||||
|
int title_height = 0;
|
||||||
|
|
||||||
{ // Title painting
|
{ // Title painting
|
||||||
auto title = index.data(UserDataTypes::TITLE).toString();
|
auto title = index.data(UserDataTypes::TITLE).toString();
|
||||||
|
|
||||||
@ -66,8 +68,10 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o
|
|||||||
font.setPointSize(font.pointSize() + 2);
|
font.setPointSize(font.pointSize() + 2);
|
||||||
painter->setFont(font);
|
painter->setFont(font);
|
||||||
|
|
||||||
|
title_height = QFontMetrics(font).height();
|
||||||
|
|
||||||
// On the top, aligned to the left after the icon
|
// On the top, aligned to the left after the icon
|
||||||
painter->drawText(rect.x(), rect.y() + QFontMetrics(font).height(), title);
|
painter->drawText(rect.x(), rect.y() + title_height, title);
|
||||||
|
|
||||||
painter->restore();
|
painter->restore();
|
||||||
}
|
}
|
||||||
@ -82,17 +86,38 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o
|
|||||||
|
|
||||||
// Get first line unconditionally
|
// Get first line unconditionally
|
||||||
description = cut_text.first().second;
|
description = cut_text.first().second;
|
||||||
|
auto num_lines = 1;
|
||||||
|
|
||||||
// Get second line, elided if needed
|
// Get second line, elided if needed
|
||||||
if (cut_text.size() > 1) {
|
if (cut_text.size() > 1) {
|
||||||
if (cut_text.size() > 2)
|
// 2.5x so because there should be some margin left from the 2x so things don't get too squishy.
|
||||||
description += opt.fontMetrics.elidedText(cut_text.at(1).second, opt.textElideMode, cut_text.at(1).first);
|
if (rect.height() - title_height <= 2.5 * opt.fontMetrics.height()) {
|
||||||
else
|
// If there's not enough space, show only a single line, elided.
|
||||||
description += cut_text.at(1).second;
|
description = opt.fontMetrics.elidedText(description, opt.textElideMode, cut_text.at(0).first);
|
||||||
|
} else {
|
||||||
|
if (cut_text.size() > 2) {
|
||||||
|
description += opt.fontMetrics.elidedText(cut_text.at(1).second, opt.textElideMode, cut_text.at(1).first);
|
||||||
|
} else {
|
||||||
|
description += cut_text.at(1).second;
|
||||||
|
}
|
||||||
|
num_lines += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int description_x = rect.x();
|
||||||
|
|
||||||
|
|
||||||
|
// Have the y-value be set based on the number of lines in the description, to centralize the
|
||||||
|
// description text with the space between the base and the title.
|
||||||
|
int description_y = rect.y() + title_height + (rect.height() - title_height) / 2;
|
||||||
|
if (num_lines == 1)
|
||||||
|
description_y -= opt.fontMetrics.height() / 2;
|
||||||
|
else
|
||||||
|
description_y -= opt.fontMetrics.height();
|
||||||
|
|
||||||
// On the bottom, aligned to the left after the icon, and featuring at most two lines of text (with some margin space to spare)
|
// 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(), rect.y() + rect.height() - 2.2 * opt.fontMetrics.height(), remaining_width,
|
painter->drawText(description_x, description_y, remaining_width,
|
||||||
2 * opt.fontMetrics.height(), Qt::TextWordWrap, description);
|
cut_text.size() * opt.fontMetrics.height(), Qt::TextWordWrap, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
painter->restore();
|
painter->restore();
|
||||||
|
@ -142,7 +142,7 @@ void VersionSelectWidget::changeProgress(qint64 current, qint64 total)
|
|||||||
void VersionSelectWidget::currentRowChanged(const QModelIndex& current, const QModelIndex&)
|
void VersionSelectWidget::currentRowChanged(const QModelIndex& current, const QModelIndex&)
|
||||||
{
|
{
|
||||||
auto variant = m_proxyModel->data(current, BaseVersionList::VersionPointerRole);
|
auto variant = m_proxyModel->data(current, BaseVersionList::VersionPointerRole);
|
||||||
emit selectedVersionChanged(variant.value<BaseVersionPtr>());
|
emit selectedVersionChanged(variant.value<BaseVersion::Ptr>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionSelectWidget::preselect()
|
void VersionSelectWidget::preselect()
|
||||||
@ -186,11 +186,11 @@ bool VersionSelectWidget::hasVersions() const
|
|||||||
return m_proxyModel->rowCount(QModelIndex()) != 0;
|
return m_proxyModel->rowCount(QModelIndex()) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseVersionPtr VersionSelectWidget::selectedVersion() const
|
BaseVersion::Ptr VersionSelectWidget::selectedVersion() const
|
||||||
{
|
{
|
||||||
auto currentIndex = listView->selectionModel()->currentIndex();
|
auto currentIndex = listView->selectionModel()->currentIndex();
|
||||||
auto variant = m_proxyModel->data(currentIndex, BaseVersionList::VersionPointerRole);
|
auto variant = m_proxyModel->data(currentIndex, BaseVersionList::VersionPointerRole);
|
||||||
return variant.value<BaseVersionPtr>();
|
return variant.value<BaseVersion::Ptr>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionSelectWidget::setExactFilter(BaseVersionList::ModelRoles role, QString filter)
|
void VersionSelectWidget::setExactFilter(BaseVersionList::ModelRoles role, QString filter)
|
||||||
|
@ -40,7 +40,7 @@ public:
|
|||||||
void loadList();
|
void loadList();
|
||||||
|
|
||||||
bool hasVersions() const;
|
bool hasVersions() const;
|
||||||
BaseVersionPtr selectedVersion() const;
|
BaseVersion::Ptr selectedVersion() const;
|
||||||
void selectRecommended();
|
void selectRecommended();
|
||||||
void selectCurrent();
|
void selectCurrent();
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ public:
|
|||||||
void setResizeOn(int column);
|
void setResizeOn(int column);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void selectedVersionChanged(BaseVersionPtr version);
|
void selectedVersionChanged(BaseVersion::Ptr version);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void closeEvent ( QCloseEvent* );
|
virtual void closeEvent ( QCloseEvent* );
|
||||||
|
@ -210,7 +210,7 @@ void LocalPeer::receiveConnection()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (socket->bytesAvailable() < (int)sizeof(quint32))
|
while (socket->bytesAvailable() < static_cast<int>(sizeof(quint32)))
|
||||||
{
|
{
|
||||||
socket->waitForReadyRead();
|
socket->waitForReadyRead();
|
||||||
}
|
}
|
||||||
|
@ -445,7 +445,7 @@ void DeviceFlow::onRefreshError(QNetworkReply::NetworkError error, QNetworkReply
|
|||||||
if(refreshReply) {
|
if(refreshReply) {
|
||||||
refreshReply->deleteLater();
|
refreshReply->deleteLater();
|
||||||
}
|
}
|
||||||
qDebug() << "DeviceFlow::onRefreshFinished: Error" << (int)error << " - " << errorString;
|
qDebug() << "DeviceFlow::onRefreshFinished: Error" << static_cast<int>(error) << " - " << errorString;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -55,12 +55,12 @@ uint32_t MurmurHash2(std::ifstream&& file_stream, std::size_t buffer_size, std::
|
|||||||
|
|
||||||
// Mix 4 bytes at a time into the hash
|
// Mix 4 bytes at a time into the hash
|
||||||
if (index == 0)
|
if (index == 0)
|
||||||
FourBytes_MurmurHash2((unsigned char*)&data, info);
|
FourBytes_MurmurHash2(reinterpret_cast<unsigned char*>(&data), info);
|
||||||
}
|
}
|
||||||
} while (!file_stream.eof());
|
} while (!file_stream.eof());
|
||||||
|
|
||||||
// Do one last bit shuffle in the hash
|
// Do one last bit shuffle in the hash
|
||||||
FourBytes_MurmurHash2((unsigned char*)&data, info);
|
FourBytes_MurmurHash2(reinterpret_cast<unsigned char*>(&data), info);
|
||||||
|
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ void FourBytes_MurmurHash2(const unsigned char* data, IncrementalHashInfo& prev)
|
|||||||
{
|
{
|
||||||
if (prev.len >= 4) {
|
if (prev.len >= 4) {
|
||||||
// Not the final mix
|
// Not the final mix
|
||||||
uint32_t k = *(uint32_t*)data;
|
uint32_t k = *reinterpret_cast<const uint32_t*>(data);
|
||||||
|
|
||||||
k *= m;
|
k *= m;
|
||||||
k ^= k >> r;
|
k ^= k >> r;
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 4b166b69f28e70a416a1a04a98f365d2aeb90de8
|
Subproject commit cc741c9f5f2a62856a2a2e9e275f61eb0591c09c
|
65
nix/NIX.md
@ -1,21 +1,59 @@
|
|||||||
# How to import
|
# Running on Nix
|
||||||
|
|
||||||
To import with flakes use
|
## Putting it in your system configuration
|
||||||
|
|
||||||
|
### On flakes-enabled nix
|
||||||
|
|
||||||
|
#### Directly installing
|
||||||
|
|
||||||
|
The `prismlauncher` flake provides a package which you can install along with
|
||||||
|
the rest of your packages
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
|
# In your flake.nix:
|
||||||
{
|
{
|
||||||
inputs = {
|
inputs = {
|
||||||
prismlauncher.url = "github:PrismLauncher/PrismLauncher";
|
prismlauncher.url = "github:PrismLauncher/PrismLauncher";
|
||||||
};
|
};
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
nixpkgs.overlays = [ inputs.prismlauncher.overlay ]; ## Within configuration.nix
|
|
||||||
environment.systemPackages = with pkgs; [ prismlauncher ]; ##
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
To import without flakes use channels:
|
```nix
|
||||||
|
# And in your system configuration:
|
||||||
|
environment.systemPackages = [ prismlauncher.packages.${pkgs.system}.prismlauncher ];
|
||||||
|
|
||||||
|
# Or in your home-manager configuration:
|
||||||
|
home.packages = [ prismlauncher.packages.${pkgs.system}.prismlauncher ];
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Using the overlay
|
||||||
|
|
||||||
|
Alternatively, you can overlay the prismlauncher version in nixpkgs which will
|
||||||
|
allow you to install using `pkgs` as you normally would while also using the
|
||||||
|
latest version
|
||||||
|
|
||||||
|
```nix
|
||||||
|
# In your flake.nix:
|
||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
prismlauncher.url = "github:PrismLauncher/PrismLauncher";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```nix
|
||||||
|
# And in your system configuration:
|
||||||
|
nixpkgs.overlays = [ inputs.prismlauncher.overlay ];
|
||||||
|
environment.systemPackages = [ pkgs.prismlauncher ];
|
||||||
|
|
||||||
|
# Or in your home-manager configuration:
|
||||||
|
config.nixpkgs.overlays = [ inputs.prismlauncher.overlay ];
|
||||||
|
home.packages = [ pkgs.prismlauncher ];
|
||||||
|
```
|
||||||
|
|
||||||
|
### Without flakes-enabled nix
|
||||||
|
|
||||||
|
#### Using channels
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
nix-channel --add https://github.com/PrismLauncher/PrismLauncher/archive/master.tar.gz prismlauncher
|
nix-channel --add https://github.com/PrismLauncher/PrismLauncher/archive/master.tar.gz prismlauncher
|
||||||
@ -23,9 +61,10 @@ nix-channel --update prismlauncher
|
|||||||
nix-env -iA prismlauncher
|
nix-env -iA prismlauncher
|
||||||
```
|
```
|
||||||
|
|
||||||
or alternatively you can use
|
#### Using the overlay
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
|
# In your configuration.nix:
|
||||||
{
|
{
|
||||||
nixpkgs.overlays = [
|
nixpkgs.overlays = [
|
||||||
(import (builtins.fetchTarball "https://github.com/PrismLauncher/PrismLauncher/archive/develop.tar.gz")).overlay
|
(import (builtins.fetchTarball "https://github.com/PrismLauncher/PrismLauncher/archive/develop.tar.gz")).overlay
|
||||||
@ -34,3 +73,11 @@ or alternatively you can use
|
|||||||
environment.systemPackages = with pkgs; [ prismlauncher ];
|
environment.systemPackages = with pkgs; [ prismlauncher ];
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Running ad-hoc
|
||||||
|
|
||||||
|
If you're on a flakes-enabled nix you can run the launcher in one-line
|
||||||
|
|
||||||
|
```sh
|
||||||
|
nix run github:PrismLauncher/PrismLauncher
|
||||||
|
```
|
||||||
|
@ -59,20 +59,20 @@ stdenv.mkDerivation rec {
|
|||||||
# Copy libnbtplusplus
|
# Copy libnbtplusplus
|
||||||
rm -rf source/libraries/libnbtplusplus
|
rm -rf source/libraries/libnbtplusplus
|
||||||
mkdir source/libraries/libnbtplusplus
|
mkdir source/libraries/libnbtplusplus
|
||||||
cp -a ${libnbtplusplus}/* source/libraries/libnbtplusplus
|
ln -s ${libnbtplusplus}/* source/libraries/libnbtplusplus
|
||||||
chmod a+r+w source/libraries/libnbtplusplus/*
|
chmod -R +r+w source/libraries/libnbtplusplus
|
||||||
# Copy tomlplusplus
|
# Copy tomlplusplus
|
||||||
rm -rf source/libraries/tomlplusplus
|
rm -rf source/libraries/tomlplusplus
|
||||||
mkdir source/libraries/tomlplusplus
|
mkdir source/libraries/tomlplusplus
|
||||||
cp -a ${tomlplusplus}/* source/libraries/tomlplusplus
|
ln -s ${tomlplusplus}/* source/libraries/tomlplusplus
|
||||||
chmod a+r+w source/libraries/tomlplusplus/*
|
chmod -R +r+w source/libraries/tomlplusplus
|
||||||
'';
|
'';
|
||||||
|
|
||||||
cmakeFlags = [
|
cmakeFlags = [
|
||||||
"-GNinja"
|
"-GNinja"
|
||||||
"-DLauncher_QT_VERSION_MAJOR=${lib.versions.major qtbase.version}"
|
"-DLauncher_QT_VERSION_MAJOR=${lib.versions.major qtbase.version}"
|
||||||
] ++ lib.optionals enableLTO [ "-DENABLE_LTO=on" ]
|
] ++ lib.optionals enableLTO [ "-DENABLE_LTO=on" ]
|
||||||
++ lib.optionals (msaClientID != "") [ "-DLauncher_MSA_CLIENT_ID=${msaClientID}" ];
|
++ lib.optionals (msaClientID != "") [ "-DLauncher_MSA_CLIENT_ID=${msaClientID}" ];
|
||||||
|
|
||||||
# we have to check if the system is NixOS before adding stdenv.cc.cc.lib (#923)
|
# we have to check if the system is NixOS before adding stdenv.cc.cc.lib (#923)
|
||||||
postInstall = ''
|
postInstall = ''
|
||||||
@ -96,6 +96,6 @@ stdenv.mkDerivation rec {
|
|||||||
'';
|
'';
|
||||||
platforms = platforms.unix;
|
platforms = platforms.unix;
|
||||||
license = licenses.gpl3Only;
|
license = licenses.gpl3Only;
|
||||||
maintainers = with maintainers; [ starcraft66 kloenk ];
|
maintainers = with maintainers; [ minion3665 Scrumplex ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,15 @@ set(Launcher_DisplayName "Prism Launcher")
|
|||||||
set(Launcher_Name "${Launcher_CommonName}" PARENT_SCOPE)
|
set(Launcher_Name "${Launcher_CommonName}" PARENT_SCOPE)
|
||||||
set(Launcher_DisplayName "${Launcher_DisplayName}" PARENT_SCOPE)
|
set(Launcher_DisplayName "${Launcher_DisplayName}" PARENT_SCOPE)
|
||||||
|
|
||||||
set(Launcher_Copyright "Prism Launcher Contributors\\n© 2012-2021 MultiMC Contributors")
|
set(Launcher_Copyright "Prism Launcher Contributors\\n© 2021-2022 PolyMC Contributors \\n© 2012-2021 MultiMC Contributors")
|
||||||
|
set(Launcher_Copyright_Mac "Prism Launcher Contributors, © 2021-2022 PolyMC Contributors and © 2012-2021 MultiMC Contributors" PARENT_SCOPE)
|
||||||
set(Launcher_Copyright "${Launcher_Copyright}" PARENT_SCOPE)
|
set(Launcher_Copyright "${Launcher_Copyright}" PARENT_SCOPE)
|
||||||
set(Launcher_Domain "prismlauncher.org" PARENT_SCOPE)
|
set(Launcher_Domain "prismlauncher.org" PARENT_SCOPE)
|
||||||
set(Launcher_UserAgent "${Launcher_CommonName}/${Launcher_VERSION_NAME}" PARENT_SCOPE)
|
set(Launcher_UserAgent "${Launcher_CommonName}/${Launcher_VERSION_NAME}" PARENT_SCOPE)
|
||||||
set(Launcher_ConfigFile "prismlauncher.cfg" PARENT_SCOPE)
|
set(Launcher_ConfigFile "prismlauncher.cfg" PARENT_SCOPE)
|
||||||
set(Launcher_Git "https://github.com/PrismLauncher/PrismLauncher" PARENT_SCOPE)
|
set(Launcher_Git "https://github.com/PrismLauncher/PrismLauncher" PARENT_SCOPE)
|
||||||
set(Launcher_DesktopFileName "org.prismlauncher.PrismLauncher.desktop" PARENT_SCOPE)
|
set(Launcher_DesktopFileName "org.prismlauncher.PrismLauncher.desktop" PARENT_SCOPE)
|
||||||
|
set(Launcher_SVGFileName "org.prismlauncher.PrismLauncher.svg" PARENT_SCOPE)
|
||||||
|
|
||||||
set(Launcher_Desktop "program_info/org.prismlauncher.PrismLauncher.desktop" PARENT_SCOPE)
|
set(Launcher_Desktop "program_info/org.prismlauncher.PrismLauncher.desktop" PARENT_SCOPE)
|
||||||
set(Launcher_MetaInfo "program_info/org.prismlauncher.PrismLauncher.metainfo.xml" PARENT_SCOPE)
|
set(Launcher_MetaInfo "program_info/org.prismlauncher.PrismLauncher.metainfo.xml" PARENT_SCOPE)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# PrismLauncher Program Info
|
# Prism Launcher Program Info
|
||||||
|
|
||||||
This is PrismLauncher's program info which contains information about:
|
This is Prism Launcher's program info which contains information about:
|
||||||
|
|
||||||
- Application name and logo (and branding in general)
|
- Application name and logo (and branding in general)
|
||||||
- Various URLs and API endpoints
|
- Various URLs and API endpoints
|
||||||
|
@ -1,39 +1,73 @@
|
|||||||
#/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# ICO
|
svg2png() {
|
||||||
|
input_file="$1"
|
||||||
|
output_file="$2"
|
||||||
|
width="$3"
|
||||||
|
height="$4"
|
||||||
|
|
||||||
inkscape -w 16 -h 16 -o prismlauncher_16.png org.prismlauncher.PrismLauncher.svg
|
inkscape -w "$width" -h "$height" -o "$output_file" "$input_file"
|
||||||
inkscape -w 24 -h 24 -o prismlauncher_24.png org.prismlauncher.PrismLauncher.svg
|
}
|
||||||
inkscape -w 32 -h 32 -o prismlauncher_32.png org.prismlauncher.PrismLauncher.svg
|
|
||||||
inkscape -w 48 -h 48 -o prismlauncher_48.png org.prismlauncher.PrismLauncher.svg
|
|
||||||
inkscape -w 64 -h 64 -o prismlauncher_64.png org.prismlauncher.PrismLauncher.svg
|
|
||||||
inkscape -w 128 -h 128 -o prismlauncher_128.png org.prismlauncher.PrismLauncher.svg
|
|
||||||
|
|
||||||
convert prismlauncher_128.png prismlauncher_64.png prismlauncher_48.png prismlauncher_32.png prismlauncher_24.png prismlauncher_16.png prismlauncher.ico
|
sipsresize() {
|
||||||
|
input_file="$1"
|
||||||
|
output_file="$2"
|
||||||
|
width="$3"
|
||||||
|
height="$4"
|
||||||
|
|
||||||
rm -f prismlauncher_*.png
|
sips -z "$width" "$height" "$input_file" --out "$output_file"
|
||||||
|
}
|
||||||
|
|
||||||
inkscape -w 1024 -h 1024 -o prismlauncher_1024.png org.prismlauncher.PrismLauncher.bigsur.svg
|
if command -v "inkscape" && command -v "icotool"; then
|
||||||
|
# Windows ICO
|
||||||
|
d=$(mktemp -d)
|
||||||
|
|
||||||
mkdir prismlauncher.iconset
|
svg2png org.prismlauncher.PrismLauncher.svg "$d/prismlauncher_16.png" 16 16
|
||||||
|
svg2png org.prismlauncher.PrismLauncher.svg "$d/prismlauncher_24.png" 24 24
|
||||||
|
svg2png org.prismlauncher.PrismLauncher.svg "$d/prismlauncher_32.png" 32 32
|
||||||
|
svg2png org.prismlauncher.PrismLauncher.svg "$d/prismlauncher_48.png" 48 48
|
||||||
|
svg2png org.prismlauncher.PrismLauncher.svg "$d/prismlauncher_64.png" 64 64
|
||||||
|
svg2png org.prismlauncher.PrismLauncher.svg "$d/prismlauncher_128.png" 128 128
|
||||||
|
svg2png org.prismlauncher.PrismLauncher.svg "$d/prismlauncher_256.png" 256 256
|
||||||
|
|
||||||
sips -z 16 16 prismlauncher_1024.png --out prismlauncher.iconset/icon_16x16.png
|
rm prismlauncher.ico && icotool -o prismlauncher.ico -c \
|
||||||
sips -z 32 32 prismlauncher_1024.png --out prismlauncher.iconset/icon_16x16@2x.png
|
"$d/prismlauncher_256.png" \
|
||||||
sips -z 32 32 prismlauncher_1024.png --out prismlauncher.iconset/icon_32x32.png
|
"$d/prismlauncher_128.png" \
|
||||||
sips -z 64 64 prismlauncher_1024.png --out prismlauncher.iconset/icon_32x32@2x.png
|
"$d/prismlauncher_64.png" \
|
||||||
sips -z 128 128 prismlauncher_1024.png --out prismlauncher.iconset/icon_128x128.png
|
"$d/prismlauncher_48.png" \
|
||||||
sips -z 256 256 prismlauncher_1024.png --out prismlauncher.iconset/icon_128x128@2x.png
|
"$d/prismlauncher_32.png" \
|
||||||
sips -z 256 256 prismlauncher_1024.png --out prismlauncher.iconset/icon_256x256.png
|
"$d/prismlauncher_24.png" \
|
||||||
sips -z 512 512 prismlauncher_1024.png --out prismlauncher.iconset/icon_256x256@2x.png
|
"$d/prismlauncher_16.png"
|
||||||
sips -z 512 512 prismlauncher_1024.png --out prismlauncher.iconset/icon_512x512.png
|
else
|
||||||
cp prismlauncher_1024.png prismlauncher.iconset/icon_512x512@2x.png
|
echo "ERROR: Windows icons were NOT generated!" >&2
|
||||||
|
echo "ERROR: requires inkscape and icotool in PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
iconutil -c icns prismlauncher.iconset
|
if command -v "inkscape" && command -v "sips" && command -v "iconutil"; then
|
||||||
|
# macOS ICNS
|
||||||
|
d=$(mktemp -d)
|
||||||
|
|
||||||
rm -f prismlauncher_*.png
|
d="$d/prismlauncher.iconset"
|
||||||
rm -rf prismlauncher.iconset
|
|
||||||
|
|
||||||
|
mkdir -p "$d"
|
||||||
|
|
||||||
|
svg2png org.prismlauncher.PrismLauncher.bigsur.svg "$d/icon_512x512@2x.png" 1024 1024
|
||||||
|
sipsresize "$d/icon_512x512@2.png" "$d/icon_16x16.png" 16 16
|
||||||
|
sipsresize "$d/icon_512x512@2.png" "$d/icon_16x16@2.png" 32 32
|
||||||
|
sipsresize "$d/icon_512x512@2.png" "$d/icon_32x32.png" 32 32
|
||||||
|
sipsresize "$d/icon_512x512@2.png" "$d/icon_32x32@2.png" 64 64
|
||||||
|
sipsresize "$d/icon_512x512@2.png" "$d/icon_128x128.png" 128 128
|
||||||
|
sipsresize "$d/icon_512x512@2.png" "$d/icon_128x128@2.png" 256 256
|
||||||
|
sipsresize "$d/icon_512x512@2.png" "$d/icon_256x256.png" 256 256
|
||||||
|
sipsresize "$d/icon_512x512@2.png" "$d/icon_256x256@2.png" 512 512
|
||||||
|
iconutil -c icns "$d"
|
||||||
|
else
|
||||||
|
echo "ERROR: macOS icons were NOT generated!" >&2
|
||||||
|
echo "ERROR: requires inkscape, sips and iconutil in PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# replace icon in themes
|
||||||
for dir in ../launcher/resources/*/scalable
|
for dir in ../launcher/resources/*/scalable
|
||||||
do
|
do
|
||||||
cp -v org.prismlauncher.PrismLauncher.svg $dir/launcher.svg
|
cp -v org.prismlauncher.PrismLauncher.svg "$dir/launcher.svg"
|
||||||
done
|
done
|
||||||
|
@ -7,6 +7,6 @@ Terminal=false
|
|||||||
Exec=@Launcher_APP_BINARY_NAME@
|
Exec=@Launcher_APP_BINARY_NAME@
|
||||||
StartupNotify=true
|
StartupNotify=true
|
||||||
Icon=org.prismlauncher.PrismLauncher
|
Icon=org.prismlauncher.PrismLauncher
|
||||||
Categories=Game;
|
Categories=Game;ActionGame;AdventureGame;Simulation;
|
||||||
Keywords=game;minecraft;launcher;mc;
|
Keywords=game;minecraft;launcher;mc;multimc;polymc;
|
||||||
StartupWMClass=PrismLauncher
|
StartupWMClass=PrismLauncher
|
||||||
|
@ -1,33 +1,35 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<component type="desktop">
|
<component type="desktop">
|
||||||
<id>org.prismlauncher.PrismLauncher</id>
|
<id>org.prismlauncher.PrismLauncher</id>
|
||||||
<provides>
|
|
||||||
<id>org.prismlauncher.PrismLauncher</id>
|
|
||||||
</provides>
|
|
||||||
<launchable type="desktop-id">org.prismlauncher.PrismLauncher.desktop</launchable>
|
<launchable type="desktop-id">org.prismlauncher.PrismLauncher.desktop</launchable>
|
||||||
<name>PrismLauncher</name>
|
<name>Prism Launcher</name>
|
||||||
<developer_name>PrismLauncher</developer_name>
|
<developer_name>Prism Launcher Contributors</developer_name>
|
||||||
<summary>A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once</summary>
|
<summary>A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once</summary>
|
||||||
<metadata_license>CC0-1.0</metadata_license>
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
<project_license>GPL-3.0-only</project_license>
|
<project_license>GPL-3.0-only</project_license>
|
||||||
<url type="homepage">https://prismlauncher.org/</url>
|
<url type="homepage">https://prismlauncher.org/</url>
|
||||||
<url type="help">https://prismlauncher.org/wiki/</url>
|
<url type="help">https://prismlauncher.org/wiki/</url>
|
||||||
|
<url type="bugtracker">https://github.com/PrismLauncher/PrismLauncher/issues</url>
|
||||||
|
<url type="contact">https://discord.gg/prismlauncher</url>
|
||||||
|
<url type="vcs-browser">https://github.com/PrismLauncher/PrismLauncher</url>
|
||||||
|
<url type="contribute">https://github.com/PrismLauncher/PrismLauncher/blob/develop/CONTRIBUTING.md</url>
|
||||||
|
<url type="translate">https://hosted.weblate.org/projects/prismlauncher/launcher</url>
|
||||||
<description>
|
<description>
|
||||||
<p>PrismLauncher is a custom launcher for Minecraft that focuses on predictability, long term stability and simplicity.</p>
|
<p>Prism Launcher is a custom launcher for Minecraft that focuses on predictability, long term stability and simplicity.</p>
|
||||||
<p>Features:</p>
|
<p>Features:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Easily install game modifications, such as Fabric, Forge and Quilt</li>
|
<li>Easily install game modifications, such as Fabric, Forge and Quilt</li>
|
||||||
<li>Control your java settings</li>
|
<li>Control your Java settings</li>
|
||||||
<li>Manage worlds and resource packs from the launcher</li>
|
<li>Manage worlds and resource packs from the launcher</li>
|
||||||
<li>See logs and other details easily</li>
|
<li>See logs and other details easily</li>
|
||||||
<li>Kill Minecraft in case of a crash/freeze</li>
|
<li>Kill Minecraft in case of a crash/freeze</li>
|
||||||
<li>Isolate minecraft instances to keep everything clean</li>
|
<li>Isolate Minecraft instances to keep everything clean</li>
|
||||||
<li>Install and update mods directly from the launcher</li>
|
<li>Install and update mods directly from the launcher</li>
|
||||||
</ul>
|
</ul>
|
||||||
</description>
|
</description>
|
||||||
<screenshots>
|
<screenshots>
|
||||||
<screenshot type="default">
|
<screenshot type="default">
|
||||||
<caption>The main PrismLauncher window</caption>
|
<caption>The main Prism Launcher window</caption>
|
||||||
<image type="source" width="976" height="764">https://prismlauncher.org/img/screenshots/LauncherDark.png</image>
|
<image type="source" width="976" height="764">https://prismlauncher.org/img/screenshots/LauncherDark.png</image>
|
||||||
</screenshot>
|
</screenshot>
|
||||||
<screenshot>
|
<screenshot>
|
||||||
|