From 838e7fb8d2075f517a81301484e8f19ee7f95bf4 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 9 Apr 2026 23:33:42 +0300 Subject: [PATCH 01/11] chore: bump to 11.0.1 Signed-off-by: Trial97 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 80977e06e..6e5fe090b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -181,7 +181,7 @@ set(Launcher_LEGACY_FMLLIBS_BASE_URL "https://files.prismlauncher.org/fmllibs/" ######## Set version numbers ######## set(Launcher_VERSION_MAJOR 11) set(Launcher_VERSION_MINOR 0) -set(Launcher_VERSION_PATCH 0) +set(Launcher_VERSION_PATCH 1) set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_PATCH}") set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_PATCH}.0") From 960e1bac877c9d37f61c3ccd6c5fa5061c9ba1b0 Mon Sep 17 00:00:00 2001 From: Octol1ttle Date: Thu, 9 Apr 2026 20:53:42 +0500 Subject: [PATCH 02/11] fix(PrintInstanceInfo): add break before OS info Signed-off-by: Octol1ttle (cherry picked from commit 4cf8cf7d18d63b113a0c25e096074679e61f99f9) --- launcher/minecraft/launch/PrintInstanceInfo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/launcher/minecraft/launch/PrintInstanceInfo.cpp b/launcher/minecraft/launch/PrintInstanceInfo.cpp index d837f5faf..7bfe73746 100644 --- a/launcher/minecraft/launch/PrintInstanceInfo.cpp +++ b/launcher/minecraft/launch/PrintInstanceInfo.cpp @@ -61,6 +61,7 @@ void PrintInstanceInfo::executeTask() auto instance = m_parent->instance(); QStringList log; + log << ""; log << "OS: " + QString("%1 | %2 | %3").arg(QSysInfo::prettyProductName(), QSysInfo::kernelType(), QSysInfo::kernelVersion()); #ifdef Q_OS_FREEBSD ::runSysctlHwModel(log); From 4cd8c343feb2cd9cbe74ac34ab1545533dd0d141 Mon Sep 17 00:00:00 2001 From: Octol1ttle Date: Thu, 9 Apr 2026 20:40:22 +0500 Subject: [PATCH 03/11] fix(CI/nix): bump macOS Signed-off-by: Octol1ttle (cherry picked from commit 724c9a4a2c07d54b188fa6a9f8185442208cf08c) --- .github/workflows/nix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index a2398642f..0fea44f08 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -88,7 +88,7 @@ jobs: - os: ubuntu-22.04-arm system: aarch64-linux - - os: macos-14 + - os: macos-26 system: aarch64-darwin runs-on: ${{ matrix.os }} From f66796e8063692ebfd8f3a3846512f5abfda6905 Mon Sep 17 00:00:00 2001 From: Octol1ttle Date: Thu, 9 Apr 2026 20:11:27 +0500 Subject: [PATCH 04/11] fix: don't count JAR mods when checking offline libraries Signed-off-by: Octol1ttle (cherry picked from commit ec4484282c8af4b3744fdf9ad018b188fc2f0ba8) --- launcher/minecraft/LaunchProfile.cpp | 5 ++-- launcher/minecraft/LaunchProfile.h | 3 ++- .../launch/EnsureOfflineLibraries.cpp | 25 +++++++++++++------ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/launcher/minecraft/LaunchProfile.cpp b/launcher/minecraft/LaunchProfile.cpp index 577b8581c..fb74d4a9a 100644 --- a/launcher/minecraft/LaunchProfile.cpp +++ b/launcher/minecraft/LaunchProfile.cpp @@ -349,7 +349,8 @@ void LaunchProfile::getLibraryFiles(const RuntimeContext& runtimeContext, QStringList& jars, QStringList& nativeJars, const QString& overridePath, - const QString& tempPath) const + const QString& tempPath, + bool addJarMods) const { QStringList native32, native64; jars.clear(); @@ -360,7 +361,7 @@ void LaunchProfile::getLibraryFiles(const RuntimeContext& runtimeContext, // NOTE: order is important here, add main jar last to the lists if (m_mainJar) { // FIXME: HACK!! jar modding is weird and unsystematic! - if (m_jarMods.size()) { + if (m_jarMods.size() && addJarMods) { QDir tempDir(tempPath); jars.append(tempDir.absoluteFilePath("minecraft.jar")); } else { diff --git a/launcher/minecraft/LaunchProfile.h b/launcher/minecraft/LaunchProfile.h index 0d2d97c45..6dc3d9aeb 100644 --- a/launcher/minecraft/LaunchProfile.h +++ b/launcher/minecraft/LaunchProfile.h @@ -87,7 +87,8 @@ class LaunchProfile : public ProblemProvider { QStringList& jars, QStringList& nativeJars, const QString& overridePath, - const QString& tempPath) const; + const QString& tempPath, + bool addJarMods = true) const; bool hasTrait(const QString& trait) const; ProblemSeverity getProblemSeverity() const override; const QList getProblems() const override; diff --git a/launcher/minecraft/launch/EnsureOfflineLibraries.cpp b/launcher/minecraft/launch/EnsureOfflineLibraries.cpp index 59801a1d0..0165fbdf9 100644 --- a/launcher/minecraft/launch/EnsureOfflineLibraries.cpp +++ b/launcher/minecraft/launch/EnsureOfflineLibraries.cpp @@ -27,16 +27,27 @@ void EnsureOfflineLibraries::executeTask() { const auto profile = m_instance->getPackProfile()->getProfile(); QStringList allJars; - profile->getLibraryFiles(m_instance->runtimeContext(), allJars, allJars, m_instance->getLocalLibraryPath(), m_instance->binRoot()); + profile->getLibraryFiles(m_instance->runtimeContext(), allJars, allJars, m_instance->getLocalLibraryPath(), m_instance->binRoot(), + false); + + QStringList missing; for (const auto& jar : allJars) { if (!QFileInfo::exists(jar)) { - emit logLine(tr("This instance cannot be launched because some libraries are missing or have not been downloaded yet. Please " - "try again in online mode with a working Internet connection"), - MessageLevel::Fatal); - emitFailed("Required libraries are missing"); - return; + missing.append(jar); } } - emitSucceeded(); + if (missing.isEmpty()) { + emitSucceeded(); + return; + } + + emit logLine("Missing libraries:", MessageLevel::Error); + for (const auto& jar : missing) { + emit logLine(" " + jar, MessageLevel::Error); + } + emit logLine(tr("\nThis instance cannot be launched because some libraries are missing or have not been downloaded yet. Please " + "try again in online mode with a working Internet connection"), + MessageLevel::Fatal); + emitFailed("Required libraries are missing"); } From fe02ad8524b0d9b573e8eab24da7853275f5d768 Mon Sep 17 00:00:00 2001 From: Octol1ttle Date: Thu, 9 Apr 2026 17:41:25 +0500 Subject: [PATCH 05/11] fix(McClient): do not use unsigned type for response length Signed-off-by: Octol1ttle (cherry picked from commit 2fe0569bd6213205949bf5a1f49600958dfe0e24) --- launcher/ui/pages/instance/McClient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/pages/instance/McClient.h b/launcher/ui/pages/instance/McClient.h index 633e7aaed..f0a6808fa 100644 --- a/launcher/ui/pages/instance/McClient.h +++ b/launcher/ui/pages/instance/McClient.h @@ -20,7 +20,7 @@ class McClient : public QObject { // 1: read the response length, still reading the response // 2: finished reading the response unsigned m_responseReadState = 0; - unsigned m_wantedRespLength = 0; + int32_t m_wantedRespLength = 0; QByteArray m_resp; public: From 09f0467e814dae28e09414a801321a3dc6abac21 Mon Sep 17 00:00:00 2001 From: Octol1ttle Date: Thu, 9 Apr 2026 18:57:33 +0500 Subject: [PATCH 06/11] refactor: McClient Signed-off-by: Octol1ttle (cherry picked from commit 91616ae9b6379d18dec5131870554bfacc5f7543) --- launcher/ui/pages/instance/McClient.cpp | 90 +++++++++++++------------ launcher/ui/pages/instance/McClient.h | 59 ++++++++-------- 2 files changed, 78 insertions(+), 71 deletions(-) diff --git a/launcher/ui/pages/instance/McClient.cpp b/launcher/ui/pages/instance/McClient.cpp index f110e1fe8..0a719431d 100644 --- a/launcher/ui/pages/instance/McClient.cpp +++ b/launcher/ui/pages/instance/McClient.cpp @@ -1,18 +1,17 @@ +#include "McClient.h" + #include #include #include #include +#include -#include +#include "Exception.h" #include "Json.h" -#include "McClient.h" -// 7 first bits -#define SEGMENT_BITS 0x7F -// last bit -#define CONTINUE_BIT 0x80 - -McClient::McClient(QObject* parent, QString domain, QString ip, short port) : QObject(parent), m_domain(domain), m_ip(ip), m_port(port) {} +McClient::McClient(QObject* parent, QString domain, QString ip, const uint16_t port) + : QObject(parent), m_domain(std::move(domain)), m_ip(std::move(ip)), m_port(port) +{} void McClient::getStatusData() { @@ -33,13 +32,12 @@ void McClient::getStatusData() void McClient::sendRequest() { QByteArray data; - writeVarInt(data, 0x00); // packet ID - writeVarInt(data, 763); // hardcoded protocol version (763 = 1.20.1) - writeVarInt(data, m_domain.size()); // server address length - writeString(data, m_domain.toStdString()); // server address - writeFixedInt(data, m_port, 2); // server port - writeVarInt(data, 0x01); // next state - writePacketToSocket(data); // send handshake packet + writeVarInt(data, 0x00); // packet ID + writeVarInt(data, 763); // hardcoded protocol version (763 = 1.20.1) + writeString(data, m_domain); // server address + writeUInt16(data, m_port); // server port + writeVarInt(data, 0x01); // next state + writePacketToSocket(data); // send handshake packet writeVarInt(data, 0x00); // packet ID writePacketToSocket(data); // send status packet @@ -47,17 +45,17 @@ void McClient::sendRequest() void McClient::readRawResponse() { - if (m_responseReadState == 2) { + if (m_responseReadState == ResponseReadState::Finished) { return; } m_resp.append(m_socket.readAll()); - if (m_responseReadState == 0 && m_resp.size() >= 5) { + if (m_responseReadState == ResponseReadState::Waiting && m_resp.size() >= 5) { m_wantedRespLength = readVarInt(m_resp); - m_responseReadState = 1; + m_responseReadState = ResponseReadState::GotLength; } - if (m_responseReadState == 1 && m_resp.size() >= m_wantedRespLength) { + if (m_responseReadState == ResponseReadState::GotLength && m_resp.size() >= m_wantedRespLength) { if (m_resp.size() > m_wantedRespLength) { qDebug().nospace() << "Warning: Packet length doesn't match actual packet size (" << m_wantedRespLength << " expected vs " << m_resp.size() << " received)"; @@ -67,7 +65,7 @@ void McClient::readRawResponse() } catch (const Exception& e) { emitFail(e.cause()); } - m_responseReadState = 2; + m_responseReadState = ResponseReadState::Finished; } } @@ -75,7 +73,7 @@ void McClient::parseResponse() { qDebug() << "Received response successfully"; - int packetID = readVarInt(m_resp); + const int packetID = readVarInt(m_resp); if (packetID != 0x00) { throw Exception(QString("Packet ID doesn't match expected value (0x00 vs 0x%1)").arg(packetID, 0, 16)); } @@ -84,7 +82,7 @@ void McClient::parseResponse() // 'resp' should now be the JSON string QJsonParseError parseError; - QJsonDocument doc = Json::parseUntilGarbage(m_resp, &parseError); + const QJsonDocument doc = Json::parseUntilGarbage(m_resp, &parseError); if (parseError.error != QJsonParseError::NoError) { qDebug() << "Failed to parse JSON:" << parseError.errorString(); emitFail(parseError.errorString()); @@ -93,18 +91,23 @@ void McClient::parseResponse() emitSucceed(doc.object()); } +// NOLINTBEGIN(*-signed-bitwise) + // From https://wiki.vg/Protocol#VarInt_and_VarLong +constexpr uint8_t g_varIntValueMask = 0x7F; +constexpr uint8_t g_varIntContinue = 0x80; + void McClient::writeVarInt(QByteArray& data, int value) { - while ((value & ~SEGMENT_BITS)) { // check if the value is too big to fit in 7 bits + while ((value & ~g_varIntValueMask) != 0) { // check if the value is too big to fit in 7 bits // Write 7 bits - data.append((value & SEGMENT_BITS) | CONTINUE_BIT); + data.append(static_cast((value & ~g_varIntValueMask) | g_varIntContinue)); // NOLINT(*-narrowing-conversions) // Erase theses 7 bits from the value to write // Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone value >>= 7; } - data.append(value); + data.append(static_cast(value)); // NOLINT(*-narrowing-conversions) } // From https://wiki.vg/Protocol#VarInt_and_VarLong @@ -112,53 +115,56 @@ int McClient::readVarInt(QByteArray& data) { int value = 0; int position = 0; - char currentByte; while (position < 32) { - currentByte = readByte(data); - value |= (currentByte & SEGMENT_BITS) << position; + const uint8_t currentByte = readByte(data); + value |= (currentByte & g_varIntValueMask) << position; - if ((currentByte & CONTINUE_BIT) == 0) + if ((currentByte & g_varIntContinue) == 0) { break; + } position += 7; } - if (position >= 32) + if (position >= 32) { throw Exception("VarInt is too big"); + } return value; } -char McClient::readByte(QByteArray& data) +// NOLINTEND(*-signed-bitwise) + +uint8_t McClient::readByte(QByteArray& data) { if (data.isEmpty()) { throw Exception("No more bytes to read"); } - char byte = data.at(0); + const uint8_t byte = data.at(0); data.remove(0, 1); return byte; } -// write number with specified size in big endian format -void McClient::writeFixedInt(QByteArray& data, int value, int size) +void McClient::writeUInt16(QByteArray& data, const uint16_t value) { - for (int i = size - 1; i >= 0; i--) { - data.append((value >> (i * 8)) & 0xFF); - } + QDataStream stream(&data, QIODeviceBase::Append); + stream.setByteOrder(QDataStream::BigEndian); + stream << value; } -void McClient::writeString(QByteArray& data, const std::string& value) +void McClient::writeString(QByteArray& data, const QString& value) { - data.append(value.c_str()); + writeVarInt(data, static_cast(value.size())); + data.append(value.toUtf8()); } void McClient::writePacketToSocket(QByteArray& data) { // we prefix the packet with its length QByteArray dataWithSize; - writeVarInt(dataWithSize, data.size()); + writeVarInt(dataWithSize, static_cast(data.size())); dataWithSize.append(data); // write it to the socket @@ -168,7 +174,7 @@ void McClient::writePacketToSocket(QByteArray& data) data.clear(); } -void McClient::emitFail(QString error) +void McClient::emitFail(const QString& error) { qDebug() << "Minecraft server ping for status error:" << error; emit failed(error); @@ -177,6 +183,6 @@ void McClient::emitFail(QString error) void McClient::emitSucceed(QJsonObject data) { - emit succeeded(data); + emit succeeded(std::move(data)); emit finished(); } diff --git a/launcher/ui/pages/instance/McClient.h b/launcher/ui/pages/instance/McClient.h index f0a6808fa..c1cb3d748 100644 --- a/launcher/ui/pages/instance/McClient.h +++ b/launcher/ui/pages/instance/McClient.h @@ -1,53 +1,54 @@ #pragma once + #include -#include #include #include #include -#include - // Client for the Minecraft protocol class McClient : public QObject { Q_OBJECT - QString m_domain; - QString m_ip; - short m_port; - QTcpSocket m_socket; - - // 0: did not start reading the response yet - // 1: read the response length, still reading the response - // 2: finished reading the response - unsigned m_responseReadState = 0; - int32_t m_wantedRespLength = 0; - QByteArray m_resp; - public: - explicit McClient(QObject* parent, QString domain, QString ip, short port); + explicit McClient(QObject* parent, QString domain, QString ip, uint16_t port); //! Read status data of the server, and calls the succeeded() signal with the parsed JSON data void getStatusData(); + signals: + void succeeded(QJsonObject data); + void failed(QString error); + void finished(); + + private: + static uint8_t readByte(QByteArray& data); + static int readVarInt(QByteArray& data); + static void writeUInt16(QByteArray& data, uint16_t value); + static void writeString(QByteArray& data, const QString& value); + static void writeVarInt(QByteArray& data, int value); + private: void sendRequest(); //! Accumulate data until we have a full response, then call parseResponse() once void readRawResponse(); void parseResponse(); - - void writeVarInt(QByteArray& data, int value); - int readVarInt(QByteArray& data); - char readByte(QByteArray& data); - //! write number with specified size in big endian format - void writeFixedInt(QByteArray& data, int value, int size); - void writeString(QByteArray& data, const std::string& value); - void writePacketToSocket(QByteArray& data); - void emitFail(QString error); + void emitFail(const QString& error); void emitSucceed(QJsonObject data); - signals: - void succeeded(QJsonObject data); - void failed(QString error); - void finished(); + private: + enum class ResponseReadState : uint8_t { + Waiting, + GotLength, + Finished + }; + + QString m_domain; + QString m_ip; + uint16_t m_port; + QTcpSocket m_socket; + + ResponseReadState m_responseReadState = ResponseReadState::Waiting; + int32_t m_wantedRespLength = 0; + QByteArray m_resp; }; From 789c65646328ccf7748ef039b29844d4b708685f Mon Sep 17 00:00:00 2001 From: Octol1ttle Date: Thu, 9 Apr 2026 19:34:11 +0500 Subject: [PATCH 07/11] feat: allow disabling low RAM warning Signed-off-by: Octol1ttle (cherry picked from commit c044ed36af1ebb969b1b8d4a3ef80895ec681921) --- launcher/Application.cpp | 6 + launcher/minecraft/MinecraftInstance.cpp | 1 + .../launch/EnsureAvailableMemory.cpp | 29 +- launcher/ui/widgets/JavaSettingsWidget.cpp | 3 + launcher/ui/widgets/JavaSettingsWidget.ui | 316 +++++++++--------- 5 files changed, 189 insertions(+), 166 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 7af39b55e..e7acc9038 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -736,6 +736,12 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) m_settings->registerSetting({ "MaxMemAlloc", "MaxMemoryAlloc" }, SysInfo::defaultMaxJvmMem()); m_settings->registerSetting("PermGen", 128); + // https://github.com/PrismLauncher/PrismLauncher/issues/5305 + // arm64 Macs have configurations with very little physical memory, but the OS can compensate by compressing and swapping + // According to user reports, this is not noticeable under normal usage due to fast storage speeds + const bool lowMemWarningDefault = !(SysInfo::currentSystem() == "osx" && SysInfo::useQTForArch() == "arm64"); + m_settings->registerSetting("LowMemWarning", lowMemWarningDefault); + // Java Settings m_settings->registerSetting("JavaPath", ""); m_settings->registerSetting("JavaSignature", ""); diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 2848f1e99..e8fc642fa 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -209,6 +209,7 @@ void MinecraftInstance::loadSpecificSettings() m_settings->registerOverride(global_settings->getSetting("MinMemAlloc"), memorySetting); m_settings->registerOverride(global_settings->getSetting("MaxMemAlloc"), memorySetting); m_settings->registerOverride(global_settings->getSetting("PermGen"), memorySetting); + m_settings->registerOverride(global_settings->getSetting("LowMemWarning"), memorySetting); // Native library workarounds auto nativeLibraryWorkaroundsOverride = m_settings->registerSetting("OverrideNativeWorkarounds", false); diff --git a/launcher/minecraft/launch/EnsureAvailableMemory.cpp b/launcher/minecraft/launch/EnsureAvailableMemory.cpp index 8a436a6f6..ae0ffe1ef 100644 --- a/launcher/minecraft/launch/EnsureAvailableMemory.cpp +++ b/launcher/minecraft/launch/EnsureAvailableMemory.cpp @@ -31,20 +31,25 @@ void EnsureAvailableMemory::executeTask() const uint64_t required = std::max(min, max); if (required > available) { - auto* dialog = CustomMessageBox::selectable( - nullptr, tr("Not enough RAM"), - tr("There is not enough RAM available to launch this instance with the current memory settings.\n\n" - "Required: %1 MiB\nAvailable: %2 MiB\n\n" - "Continue anyway? This may cause slowdowns in the game and your system.") - .arg(required) - .arg(available), - QMessageBox::Icon::Warning, QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, - QMessageBox::StandardButton::No); - const auto response = dialog->exec(); - dialog->deleteLater(); + bool shouldAbort = false; + + if (m_instance->settings()->get("LowMemWarning").toBool()) { + auto* dialog = CustomMessageBox::selectable( + nullptr, tr("Not enough RAM"), + tr("There is not enough RAM available to launch this instance with the current memory settings.\n\n" + "Required: %1 MiB\nAvailable: %2 MiB\n\n" + "Continue anyway? This may cause slowdowns in the game and your system.") + .arg(required) + .arg(available), + QMessageBox::Icon::Warning, QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, + QMessageBox::StandardButton::No); + + shouldAbort = dialog->exec() == QMessageBox::No; + dialog->deleteLater(); + } const auto message = tr("Not enough RAM available to launch this instance"); - if (response == QMessageBox::No) { + if (shouldAbort) { emit logLine(message, MessageLevel::Fatal); emitFailed(message); return; diff --git a/launcher/ui/widgets/JavaSettingsWidget.cpp b/launcher/ui/widgets/JavaSettingsWidget.cpp index 4e74c610f..e13c847d0 100644 --- a/launcher/ui/widgets/JavaSettingsWidget.cpp +++ b/launcher/ui/widgets/JavaSettingsWidget.cpp @@ -151,6 +151,7 @@ void JavaSettingsWidget::loadSettings() m_ui->maxMemSpinBox->setValue(min); } m_ui->permGenSpinBox->setValue(settings->get("PermGen").toInt()); + m_ui->lowMemWarningCheckBox->setChecked(settings->get("LowMemWarning").toBool()); // Java arguments m_ui->javaArgumentsGroupBox->setChecked(m_instance == nullptr || settings->get("OverrideJavaArgs").toBool()); @@ -205,10 +206,12 @@ void JavaSettingsWidget::saveSettings() settings->set("MaxMemAlloc", min); } settings->set("PermGen", m_ui->permGenSpinBox->value()); + settings->set("LowMemWarning", m_ui->lowMemWarningCheckBox->isChecked()); } else { settings->reset("MinMemAlloc"); settings->reset("MaxMemAlloc"); settings->reset("PermGen"); + settings->reset("LowMemWarning"); } // Java arguments diff --git a/launcher/ui/widgets/JavaSettingsWidget.ui b/launcher/ui/widgets/JavaSettingsWidget.ui index 46f714b76..14638cf4e 100644 --- a/launcher/ui/widgets/JavaSettingsWidget.ui +++ b/launcher/ui/widgets/JavaSettingsWidget.ui @@ -55,7 +55,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -86,7 +86,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -101,10 +101,10 @@ - Qt::Vertical + Qt::Orientation::Vertical - QSizePolicy::Fixed + QSizePolicy::Policy::Fixed @@ -160,10 +160,10 @@ - Qt::Vertical + Qt::Orientation::Vertical - QSizePolicy::Fixed + QSizePolicy::Policy::Fixed @@ -190,156 +190,166 @@ false - - - + + + + + + + M&inimum Memory Usage: + + + minMemSpinBox + + + + + + + + + + 0 + 0 + + + + The amount of memory Minecraft is started with. + + + MiB + + + 8 + + + 1048576 + + + 128 + + + 256 + + + + + + + (-Xms) + + + + + + + + + Ma&ximum Memory Usage: + + + maxMemSpinBox + + + + + + + + + + 0 + 0 + + + + The maximum amount of memory Minecraft is allowed to use. + + + MiB + + + 8 + + + 1048576 + + + 128 + + + 1024 + + + + + + + (-Xmx) + + + + + + + + + &PermGen Size: + + + permGenSpinBox + + + + + + + + + + 0 + 0 + + + + The amount of memory available to store loaded Java classes. + + + MiB + + + 4 + + + 1048576 + + + 8 + + + 64 + + + + + + + (-XX:PermSize) + + + + + + + + + - (-XX:PermSize) + Warn when there is not enough memory available - - - - - 0 - 0 - - - - The amount of memory available to store loaded Java classes. - - - MiB - - - 4 - - - 1048576 - - - 8 - - - 64 - - - - - - - - 0 - 0 - - - - The maximum amount of memory Minecraft is allowed to use. - - - MiB - - - 8 - - - 1048576 - - - 128 - - - 1024 - - - - - - - (-Xmx) - - - - - - - - 0 - 0 - - - - The amount of memory Minecraft is started with. - - - MiB - - - 8 - - - 1048576 - - - 128 - - - 256 - - - - - - - &PermGen Size: - - - permGenSpinBox - - - - - - - (-Xms) - - - - - - - Ma&ximum Memory Usage: - - - maxMemSpinBox - - - - - - - M&inimum Memory Usage: - - - minMemSpinBox - - - - - - - Qt::Horizontal - - - - 0 - 0 - - - - - + Memory Notice @@ -382,9 +392,7 @@ autodownloadJavaCheckBox javaTestBtn javaDownloadBtn - minMemSpinBox maxMemSpinBox - permGenSpinBox jvmArgsTextBox From f766cdd847e6943d77386dd6da00f7681cfd2492 Mon Sep 17 00:00:00 2001 From: Octol1ttle Date: Thu, 9 Apr 2026 22:35:32 +0500 Subject: [PATCH 08/11] change(EnsureAvailableMemory): add lenience Signed-off-by: Octol1ttle (cherry picked from commit 658a1391f8fbcf7b51ffc741d393728768b4a5b1) --- launcher/minecraft/launch/EnsureAvailableMemory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/minecraft/launch/EnsureAvailableMemory.cpp b/launcher/minecraft/launch/EnsureAvailableMemory.cpp index ae0ffe1ef..a0e156770 100644 --- a/launcher/minecraft/launch/EnsureAvailableMemory.cpp +++ b/launcher/minecraft/launch/EnsureAvailableMemory.cpp @@ -30,7 +30,7 @@ void EnsureAvailableMemory::executeTask() const uint64_t max = m_instance->settings()->get("MaxMemAlloc").toUInt(); const uint64_t required = std::max(min, max); - if (required > available) { + if (static_cast(required) * 0.9 > static_cast(available)) { bool shouldAbort = false; if (m_instance->settings()->get("LowMemWarning").toBool()) { From fb7e4da4e62a4928d87bb0bca18418534c52059c Mon Sep 17 00:00:00 2001 From: Octol1ttle Date: Fri, 10 Apr 2026 11:53:37 +0500 Subject: [PATCH 09/11] Change LowMemWarning default to always enabled Signed-off-by: Octol1ttle (cherry picked from commit 4b3aedd5d0567b57856453c96250637cf1495f67) --- launcher/Application.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index e7acc9038..115b6489c 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -735,12 +735,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) m_settings->registerSetting({ "MinMemAlloc", "MinMemoryAlloc" }, 512); m_settings->registerSetting({ "MaxMemAlloc", "MaxMemoryAlloc" }, SysInfo::defaultMaxJvmMem()); m_settings->registerSetting("PermGen", 128); - - // https://github.com/PrismLauncher/PrismLauncher/issues/5305 - // arm64 Macs have configurations with very little physical memory, but the OS can compensate by compressing and swapping - // According to user reports, this is not noticeable under normal usage due to fast storage speeds - const bool lowMemWarningDefault = !(SysInfo::currentSystem() == "osx" && SysInfo::useQTForArch() == "arm64"); - m_settings->registerSetting("LowMemWarning", lowMemWarningDefault); + m_settings->registerSetting("LowMemWarning", true); // Java Settings m_settings->registerSetting("JavaPath", ""); From 239be1ec433bb480b8fcce99e29c52345f794a3d Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 10 Apr 2026 00:36:05 +0300 Subject: [PATCH 10/11] fix pack upgrade Signed-off-by: Trial97 (cherry picked from commit b7344af313397c00a80fc823ecfa46229eec1ff0) --- launcher/InstanceList.cpp | 12 +++++------- launcher/ui/pages/instance/ManagedPackPage.cpp | 15 ++++++++------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp index 1fe96144d..1339499c7 100644 --- a/launcher/InstanceList.cpp +++ b/launcher/InstanceList.cpp @@ -924,23 +924,23 @@ class InstanceStaging : public Task { connect(child, &Task::progress, this, &InstanceStaging::setProgress); connect(child, &Task::stepProgress, this, &InstanceStaging::propagateStepProgress); connect(&m_backoffTimer, &QTimer::timeout, this, &InstanceStaging::childSucceeded); - m_backoffTimer.setSingleShot(true); } - virtual ~InstanceStaging() {} + ~InstanceStaging() override = default; // FIXME/TODO: add ability to abort during instance commit retries bool abort() override { - if (!canAbort()) + if (!canAbort()) { return false; + } return m_child->abort(); } bool canAbort() const override { return (m_child && m_child->canAbort()); } protected: - virtual void executeTask() override + void executeTask() override { if (m_stagingPath.isNull()) { emitFailed(tr("Could not create staging folder")); @@ -954,10 +954,8 @@ class InstanceStaging : public Task { private slots: void childSucceeded() { - if (!isRunning()) - return; unsigned sleepTime = backoff(); - if (m_parent->commitStagedInstance(m_stagingPath, *m_child.get(), m_child->group(), *m_child.get())) { + if (m_parent->commitStagedInstance(m_stagingPath, *m_child, m_child->group(), *m_child)) { m_backoffTimer.stop(); emitSucceeded(); return; diff --git a/launcher/ui/pages/instance/ManagedPackPage.cpp b/launcher/ui/pages/instance/ManagedPackPage.cpp index ad6b39723..508bfeba0 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.cpp +++ b/launcher/ui/pages/instance/ManagedPackPage.cpp @@ -202,23 +202,24 @@ bool ManagedPackPage::runUpdateTask(InstanceTask* task) unique_qobject_ptr wrapped_task(APPLICATION->instances()->wrapInstanceTask(task)); - connect(task, &Task::failed, - [this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); }); - connect(task, &Task::succeeded, [this, task]() { + connect(wrapped_task.get(), &Task::failed, + [this](const QString& reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); }); + connect(wrapped_task.get(), &Task::succeeded, [this, task]() { QStringList warnings = task->warnings(); - if (warnings.count()) + if (warnings.count()) { CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show(); + } }); - connect(task, &Task::aborted, [this] { + connect(wrapped_task.get(), &Task::aborted, [this] { CustomMessageBox::selectable(this, tr("Task aborted"), tr("The task has been aborted by the user."), QMessageBox::Information) ->show(); }); ProgressDialog loadDialog(this); loadDialog.setSkipButton(true, tr("Abort")); - loadDialog.execWithTask(task); + loadDialog.execWithTask(wrapped_task.get()); - return task->wasSuccessful(); + return wrapped_task->wasSuccessful(); } void ManagedPackPage::suggestVersion() From 6d38b34c004acb4faf777cf2f5ae86aa58e9c267 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 10 Apr 2026 19:29:56 +0300 Subject: [PATCH 11/11] enable modpack changelog for modrinth page Signed-off-by: Trial97 (cherry picked from commit f3ff0a730a3cc220240405c6518e0fda2dd9cf3b) --- .../ui/pages/instance/ManagedPackPage.cpp | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/launcher/ui/pages/instance/ManagedPackPage.cpp b/launcher/ui/pages/instance/ManagedPackPage.cpp index 508bfeba0..777dfbaa1 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.cpp +++ b/launcher/ui/pages/instance/ManagedPackPage.cpp @@ -261,14 +261,16 @@ void ModrinthManagedPackPage::parseManagedPack() qDebug() << "Parsing Modrinth pack"; // No need for the extra work because we already have everything we need. - if (m_loaded) + if (m_loaded) { return; + } - if (m_fetch_job && m_fetch_job->isRunning()) + if (m_fetch_job && m_fetch_job->isRunning()) { m_fetch_job->abort(); + } ResourceAPI::Callback> callbacks{}; - m_pack = { m_inst->getManagedPackID() }; + m_pack = { .addonId = m_inst->getManagedPackID() }; // Use default if no callbacks are set callbacks.on_succeed = [this](auto& doc) { @@ -285,8 +287,9 @@ void ModrinthManagedPackPage::parseManagedPack() // NOTE: the id from version isn't the same id in the modpack format spec... // e.g. HexMC's 4.4.0 has versionId 4.0.0 in the modpack index.............. - if (version.version == m_inst->getManagedPackVersionName()) + if (version.version == m_inst->getManagedPackVersionName()) { name = tr("%1 (Current)").arg(name); + } ui->versionsComboBox->addItem(name, version.fileId); } @@ -295,10 +298,14 @@ void ModrinthManagedPackPage::parseManagedPack() m_loaded = true; }; - callbacks.on_fail = [this](QString reason, int) { setFailState(); }; + callbacks.on_fail = [this](const QString& /*reason*/, int) { setFailState(); }; callbacks.on_abort = [this]() { setFailState(); }; - m_fetch_job = m_api.getProjectVersions( - { std::make_shared(m_pack), {}, {}, ModPlatform::ResourceType::Modpack }, std::move(callbacks)); + m_fetch_job = m_api.getProjectVersions({ .pack = std::make_shared(m_pack), + .mcVersions = {}, + .loaders = {}, + .resourceType = ModPlatform::ResourceType::Modpack, + .includeChangelog = true }, + std::move(callbacks)); ui->changelogTextBrowser->setText(tr("Fetching changelogs...")); @@ -407,14 +414,16 @@ void FlameManagedPackPage::parseManagedPack() } // No need for the extra work because we already have everything we need. - if (m_loaded) + if (m_loaded) { return; + } - if (m_fetch_job && m_fetch_job->isRunning()) + if (m_fetch_job && m_fetch_job->isRunning()) { m_fetch_job->abort(); + } QString id = m_inst->getManagedPackID(); - m_pack = { id }; + m_pack = { .addonId = id }; ResourceAPI::Callback> callbacks{}; @@ -431,8 +440,9 @@ void FlameManagedPackPage::parseManagedPack() for (const auto& version : m_pack.versions) { QString name = version.getVersionDisplayString(); - if (version.fileId == m_inst->getManagedPackVersionID().toInt()) + if (version.fileId == m_inst->getManagedPackVersionID().toInt()) { name = tr("%1 (Current)").arg(name); + } ui->versionsComboBox->addItem(name, QVariant(version.fileId)); } @@ -441,10 +451,14 @@ void FlameManagedPackPage::parseManagedPack() m_loaded = true; }; - callbacks.on_fail = [this](QString reason, int) { setFailState(); }; + callbacks.on_fail = [this](const QString& /*reason*/, int) { setFailState(); }; callbacks.on_abort = [this]() { setFailState(); }; - m_fetch_job = m_api.getProjectVersions( - { std::make_shared(m_pack), {}, {}, ModPlatform::ResourceType::Modpack }, std::move(callbacks)); + m_fetch_job = m_api.getProjectVersions({ .pack = std::make_shared(m_pack), + .mcVersions = {}, + .loaders = {}, + .resourceType = ModPlatform::ResourceType::Modpack, + .includeChangelog = true }, + std::move(callbacks)); m_fetch_job->start(); }