mirror of
https://github.com/PrismLauncher/PrismLauncher
synced 2026-04-24 01:24:06 +00:00
Compare commits
19 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a71b8d8fe3 | ||
|
|
6d38b34c00 | ||
|
|
85f19da603 | ||
|
|
239be1ec43 | ||
|
|
34349a6810 | ||
|
|
fb7e4da4e6 | ||
|
|
f766cdd847 | ||
|
|
789c656463 | ||
|
|
2d01dfa4f2 | ||
|
|
9231fe8592 | ||
|
|
25fee30f95 | ||
|
|
ec6a173608 | ||
|
|
b7d70dc1c1 | ||
|
|
09f0467e81 | ||
|
|
fe02ad8524 | ||
|
|
f66796e806 | ||
|
|
4cd8c343fe | ||
|
|
960e1bac87 | ||
|
|
838e7fb8d2 |
2
.github/workflows/nix.yml
vendored
2
.github/workflows/nix.yml
vendored
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -735,6 +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);
|
||||
m_settings->registerSetting("LowMemWarning", true);
|
||||
|
||||
// Java Settings
|
||||
m_settings->registerSetting("JavaPath", "");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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<PatchProblem> getProblems() const override;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -30,21 +30,26 @@ void EnsureAvailableMemory::executeTask()
|
|||
const uint64_t max = m_instance->settings()->get("MaxMemAlloc").toUInt();
|
||||
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();
|
||||
if (static_cast<double>(required) * 0.9 > static_cast<double>(available)) {
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -202,23 +202,24 @@ bool ManagedPackPage::runUpdateTask(InstanceTask* task)
|
|||
|
||||
unique_qobject_ptr<Task> 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()
|
||||
|
|
@ -260,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<QVector<ModPlatform::IndexedVersion>> 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) {
|
||||
|
|
@ -284,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);
|
||||
}
|
||||
|
|
@ -294,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<ModPlatform::IndexedPack>(m_pack), {}, {}, ModPlatform::ResourceType::Modpack }, std::move(callbacks));
|
||||
m_fetch_job = m_api.getProjectVersions({ .pack = std::make_shared<ModPlatform::IndexedPack>(m_pack),
|
||||
.mcVersions = {},
|
||||
.loaders = {},
|
||||
.resourceType = ModPlatform::ResourceType::Modpack,
|
||||
.includeChangelog = true },
|
||||
std::move(callbacks));
|
||||
|
||||
ui->changelogTextBrowser->setText(tr("Fetching changelogs..."));
|
||||
|
||||
|
|
@ -406,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<QVector<ModPlatform::IndexedVersion>> callbacks{};
|
||||
|
||||
|
|
@ -430,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));
|
||||
}
|
||||
|
|
@ -440,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<ModPlatform::IndexedPack>(m_pack), {}, {}, ModPlatform::ResourceType::Modpack }, std::move(callbacks));
|
||||
m_fetch_job = m_api.getProjectVersions({ .pack = std::make_shared<ModPlatform::IndexedPack>(m_pack),
|
||||
.mcVersions = {},
|
||||
.loaders = {},
|
||||
.resourceType = ModPlatform::ResourceType::Modpack,
|
||||
.includeChangelog = true },
|
||||
std::move(callbacks));
|
||||
|
||||
m_fetch_job->start();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
#include "McClient.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QObject>
|
||||
#include <QTcpSocket>
|
||||
#include <utility>
|
||||
|
||||
#include <Exception.h>
|
||||
#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<uint8_t>((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<uint8_t>(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<int32_t>(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<int32_t>(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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,53 +1,54 @@
|
|||
#pragma once
|
||||
|
||||
#include <QFuture>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QObject>
|
||||
#include <QTcpSocket>
|
||||
|
||||
#include <Exception.h>
|
||||
|
||||
// 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;
|
||||
unsigned 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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@
|
|||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
@ -86,7 +86,7 @@
|
|||
<item>
|
||||
<spacer name="horizontalSpacer_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
@ -101,10 +101,10 @@
|
|||
<item row="9" column="0">
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
@ -160,10 +160,10 @@
|
|||
<item row="3" column="0">
|
||||
<spacer name="verticalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
@ -190,156 +190,166 @@
|
|||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelMinMem">
|
||||
<property name="text">
|
||||
<string>M&inimum Memory Usage:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>minMemSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="minMemSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The amount of memory Minecraft is started with.</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true"> MiB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1048576</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>256</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>(-Xms)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelMaxMem">
|
||||
<property name="text">
|
||||
<string>Ma&ximum Memory Usage:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>maxMemSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="maxMemSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The maximum amount of memory Minecraft is allowed to use.</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true"> MiB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1048576</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1024</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>(-Xmx)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>&PermGen Size:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>permGenSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="permGenSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The amount of memory available to store loaded Java classes.</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true"> MiB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1048576</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>64</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>(-XX:PermSize)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="lowMemWarningCheckBox">
|
||||
<property name="text">
|
||||
<string>(-XX:PermSize)</string>
|
||||
<string>Warn when there is not enough memory available</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="permGenSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The amount of memory available to store loaded Java classes.</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true"> MiB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1048576</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>64</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="maxMemSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The maximum amount of memory Minecraft is allowed to use.</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true"> MiB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1048576</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1024</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>(-Xmx)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="minMemSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The amount of memory Minecraft is started with.</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true"> MiB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1048576</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>256</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>&PermGen Size:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>permGenSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>(-Xms)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelMaxMem">
|
||||
<property name="text">
|
||||
<string>Ma&ximum Memory Usage:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>maxMemSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelMinMem">
|
||||
<property name="text">
|
||||
<string>M&inimum Memory Usage:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>minMemSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="4">
|
||||
<item>
|
||||
<widget class="QLabel" name="labelMaxMemNotice">
|
||||
<property name="text">
|
||||
<string>Memory Notice</string>
|
||||
|
|
@ -382,9 +392,7 @@
|
|||
<tabstop>autodownloadJavaCheckBox</tabstop>
|
||||
<tabstop>javaTestBtn</tabstop>
|
||||
<tabstop>javaDownloadBtn</tabstop>
|
||||
<tabstop>minMemSpinBox</tabstop>
|
||||
<tabstop>maxMemSpinBox</tabstop>
|
||||
<tabstop>permGenSpinBox</tabstop>
|
||||
<tabstop>jvmArgsTextBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue