From dc6340bf384d6f54f9f2793c55235b1bdd879b00 Mon Sep 17 00:00:00 2001 From: Una Date: Tue, 5 Apr 2022 23:22:24 -0700 Subject: [PATCH] Allow components to specify Java agents and JVM arguments (#175) --- launcher/CMakeLists.txt | 2 +- launcher/minecraft/Agent.h | 36 +++++++++++++++++++++ launcher/minecraft/LaunchProfile.cpp | 33 +++++++++++++++++++ launcher/minecraft/LaunchProfile.h | 14 ++++++++ launcher/minecraft/MinecraftInstance.cpp | 11 +++++++ launcher/minecraft/OneSixVersionFormat.cpp | 24 ++++++++++++++ launcher/minecraft/VersionFile.cpp | 5 +++ launcher/minecraft/VersionFile.h | 7 ++++ launcher/minecraft/update/LibrariesTask.cpp | 4 +++ launcher/ui/widgets/CustomCommands.ui | 2 +- 10 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 launcher/minecraft/Agent.h diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 692aebe5d..13085c4c0 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -348,7 +348,7 @@ set(MINECRAFT_SOURCES mojang/PackageManifest.h mojang/PackageManifest.cpp - ) + minecraft/Agent.h) add_unit_test(GradleSpecifier SOURCES minecraft/GradleSpecifier_test.cpp diff --git a/launcher/minecraft/Agent.h b/launcher/minecraft/Agent.h new file mode 100644 index 000000000..01109dafa --- /dev/null +++ b/launcher/minecraft/Agent.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include "Library.h" + +class Agent; + +typedef std::shared_ptr AgentPtr; + +class Agent { +public: + Agent(LibraryPtr library, QString &argument) + { + m_library = library; + m_argument = argument; + } + +public: /* methods */ + + LibraryPtr library() { + return m_library; + } + QString argument() { + return m_argument; + } + +protected: /* data */ + + /// The library pointing to the jar this Java agent is contained within + LibraryPtr m_library; + + /// The argument to the Java agent, passed after an = if present + QString m_argument; + +}; diff --git a/launcher/minecraft/LaunchProfile.cpp b/launcher/minecraft/LaunchProfile.cpp index cd77aa4a7..39a342ca9 100644 --- a/launcher/minecraft/LaunchProfile.cpp +++ b/launcher/minecraft/LaunchProfile.cpp @@ -42,11 +42,13 @@ void LaunchProfile::clear() m_minecraftVersionType.clear(); m_minecraftAssets.reset(); m_minecraftArguments.clear(); + m_addnJvmArguments.clear(); m_tweakers.clear(); m_mainClass.clear(); m_appletClass.clear(); m_libraries.clear(); m_mavenFiles.clear(); + m_agents.clear(); m_traits.clear(); m_jarMods.clear(); m_mainJar.reset(); @@ -80,6 +82,11 @@ void LaunchProfile::applyMinecraftArguments(const QString& minecraftArguments) applyString(minecraftArguments, this->m_minecraftArguments); } +void LaunchProfile::applyAddnJvmArguments(const QStringList& addnJvmArguments) +{ + this->m_addnJvmArguments.append(addnJvmArguments); +} + void LaunchProfile::applyMinecraftVersionType(const QString& type) { applyString(type, this->m_minecraftVersionType); @@ -214,6 +221,22 @@ void LaunchProfile::applyMavenFile(LibraryPtr mavenFile) m_mavenFiles.append(Library::limitedCopy(mavenFile)); } +void LaunchProfile::applyAgent(AgentPtr agent) +{ + auto lib = agent->library(); + if(!lib->isActive()) + { + return; + } + + if(lib->isNative()) + { + return; + } + + m_agents.append(agent); +} + const LibraryPtr LaunchProfile::getMainJar() const { return m_mainJar; @@ -295,6 +318,11 @@ QString LaunchProfile::getMinecraftArguments() const return m_minecraftArguments; } +const QStringList & LaunchProfile::getAddnJvmArguments() const +{ + return m_addnJvmArguments; +} + const QList & LaunchProfile::getJarMods() const { return m_jarMods; @@ -315,6 +343,11 @@ const QList & LaunchProfile::getMavenFiles() const return m_mavenFiles; } +const QList & LaunchProfile::getAgents() const +{ + return m_agents; +} + const QList & LaunchProfile::getCompatibleJavaMajors() const { return m_compatibleJavaMajors; diff --git a/launcher/minecraft/LaunchProfile.h b/launcher/minecraft/LaunchProfile.h index 366ed8056..b55cf6615 100644 --- a/launcher/minecraft/LaunchProfile.h +++ b/launcher/minecraft/LaunchProfile.h @@ -36,6 +36,7 @@ #pragma once #include #include "Library.h" +#include "Agent.h" #include class LaunchProfile: public ProblemProvider @@ -48,6 +49,7 @@ public: /* application of profile variables from patches */ void applyMainClass(const QString& mainClass); void applyAppletClass(const QString& appletClass); void applyMinecraftArguments(const QString& minecraftArguments); + void applyAddnJvmArguments(const QStringList& minecraftArguments); void applyMinecraftVersionType(const QString& type); void applyMinecraftAssets(MojangAssetIndexInfo::Ptr assets); void applyTraits(const QSet &traits); @@ -56,6 +58,7 @@ public: /* application of profile variables from patches */ void applyMods(const QList &jarMods); void applyLibrary(LibraryPtr library); void applyMavenFile(LibraryPtr library); + void applyAgent(AgentPtr agent); void applyCompatibleJavaMajors(QList& javaMajor); void applyMainJar(LibraryPtr jar); void applyProblemSeverity(ProblemSeverity severity); @@ -69,12 +72,14 @@ public: /* getters for profile variables */ QString getMinecraftVersionType() const; MojangAssetIndexInfo::Ptr getMinecraftAssets() const; QString getMinecraftArguments() const; + const QStringList & getAddnJvmArguments() const; const QSet & getTraits() const; const QStringList & getTweakers() const; const QList & getJarMods() const; const QList & getLibraries() const; const QList & getNativeLibraries() const; const QList & getMavenFiles() const; + const QList & getAgents() const; const QList & getCompatibleJavaMajors() const; const LibraryPtr getMainJar() const; void getLibraryFiles( @@ -106,6 +111,12 @@ private: */ QString m_minecraftArguments; + /** + * Additional arguments to pass to the JVM in addition to those the user has configured, + * memory settings, etc. + */ + QStringList m_addnJvmArguments; + /// A list of all tweaker classes QStringList m_tweakers; @@ -121,6 +132,9 @@ private: /// the list of maven files to be placed in the libraries folder, but not acted upon QList m_mavenFiles; + /// the list of java agents to add to JVM arguments + QList m_agents; + /// the main jar LibraryPtr m_mainJar; diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index fd933df73..3ba79178c 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -330,6 +330,17 @@ QStringList MinecraftInstance::extraArguments() const list.append({"-Dfml.ignoreInvalidMinecraftCertificates=true", "-Dfml.ignorePatchDiscrepancies=true"}); } + auto addn = m_components->getProfile()->getAddnJvmArguments(); + if (!addn.isEmpty()) { + list.append(addn); + } + auto agents = m_components->getProfile()->getAgents(); + for (auto agent : agents) + { + QStringList jar, temp1, temp2, temp3; + agent->library()->getApplicableFiles(currentSystem, jar, temp1, temp2, temp3, getLocalLibraryPath()); + list.append("-javaagent:"+jar[0]+(agent->argument().isEmpty() ? "" : "="+agent->argument())); + } return list; } diff --git a/launcher/minecraft/OneSixVersionFormat.cpp b/launcher/minecraft/OneSixVersionFormat.cpp index 0329d70ef..879f18c1d 100644 --- a/launcher/minecraft/OneSixVersionFormat.cpp +++ b/launcher/minecraft/OneSixVersionFormat.cpp @@ -1,5 +1,6 @@ #include "OneSixVersionFormat.h" #include +#include "minecraft/Agent.h" #include "minecraft/ParseUtils.h" #include @@ -108,6 +109,14 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc } } + if (root.contains("+jvmArgs")) + { + for (auto arg : requireArray(root.value("+jvmArgs"))) + { + out->addnJvmArguments.append(requireString(arg)); + } + } + if (root.contains("jarMods")) { @@ -176,6 +185,21 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc readLibs("mavenFiles", out->mavenFiles); } + if(root.contains("+agents")) { + for (auto agentVal : requireArray(root.value("+agents"))) + { + QJsonObject agentObj = requireObject(agentVal); + auto lib = libraryFromJson(*out, agentObj, filename); + QString arg = ""; + if (agentObj.contains("argument")) + { + readString(agentObj, "argument", arg); + } + AgentPtr agent(new Agent(lib, arg)); + out->agents.append(agent); + } + } + // if we have mainJar, just use it if(root.contains("mainJar")) { diff --git a/launcher/minecraft/VersionFile.cpp b/launcher/minecraft/VersionFile.cpp index 94fb6db72..9db30ba2f 100644 --- a/launcher/minecraft/VersionFile.cpp +++ b/launcher/minecraft/VersionFile.cpp @@ -67,6 +67,7 @@ void VersionFile::applyTo(LaunchProfile *profile) profile->applyMainClass(mainClass); profile->applyAppletClass(appletClass); profile->applyMinecraftArguments(minecraftArguments); + profile->applyAddnJvmArguments(addnJvmArguments); profile->applyTweakers(addTweakers); profile->applyJarMods(jarMods); profile->applyMods(mods); @@ -81,6 +82,10 @@ void VersionFile::applyTo(LaunchProfile *profile) { profile->applyMavenFile(mavenFile); } + for (auto agent : agents) + { + profile->applyAgent(agent); + } profile->applyProblemSeverity(getProblemSeverity()); } diff --git a/launcher/minecraft/VersionFile.h b/launcher/minecraft/VersionFile.h index a7a19c4e4..d4b29719a 100644 --- a/launcher/minecraft/VersionFile.h +++ b/launcher/minecraft/VersionFile.h @@ -45,6 +45,7 @@ #include "minecraft/Rule.h" #include "ProblemProvider.h" #include "Library.h" +#include "Agent.h" #include class PackProfile; @@ -92,6 +93,9 @@ public: /* data */ /// Mojang: Minecraft launch arguments (may contain placeholders for variable substitution) QString minecraftArguments; + /// PolyMC: Additional JVM launch arguments + QStringList addnJvmArguments; + /// Mojang: list of compatible java majors QList compatibleJavaMajors; @@ -116,6 +120,9 @@ public: /* data */ /// PolyMC: list of maven files to put in the libraries folder, but not in classpath QList mavenFiles; + /// PolyMC: list of agents to add to JVM arguments + QList agents; + /// The main jar (Minecraft version library, normally) LibraryPtr mainJar; diff --git a/launcher/minecraft/update/LibrariesTask.cpp b/launcher/minecraft/update/LibrariesTask.cpp index 667dd5d97..26679110b 100644 --- a/launcher/minecraft/update/LibrariesTask.cpp +++ b/launcher/minecraft/update/LibrariesTask.cpp @@ -48,6 +48,10 @@ void LibrariesTask::executeTask() libArtifactPool.append(profile->getLibraries()); libArtifactPool.append(profile->getNativeLibraries()); libArtifactPool.append(profile->getMavenFiles()); + for (auto agent : profile->getAgents()) + { + libArtifactPool.append(agent->library()); + } libArtifactPool.append(profile->getMainJar()); processArtifactPool(libArtifactPool, failedLocalLibraries, inst->getLocalLibraryPath()); diff --git a/launcher/ui/widgets/CustomCommands.ui b/launcher/ui/widgets/CustomCommands.ui index dbd544318..650a9cc15 100644 --- a/launcher/ui/widgets/CustomCommands.ui +++ b/launcher/ui/widgets/CustomCommands.ui @@ -74,7 +74,7 @@ - <html><head/><body><p>Pre-launch command runs before the instance launches and post-exit command runs after it exits.</p><p>Both will be run in the launcher's working folder with extra environment variables:</p><ul><li>$INST_NAME - Name of the instance</li><li>$INST_ID - ID of the instance (its folder name)</li><li>$INST_DIR - absolute path of the instance</li><li>$INST_MC_DIR - absolute path of Minecraft</li><li>$INST_JAVA - Java binary used for launch</li><li>$INST_JAVA_ARGS - command-line parameters used for launch</li></ul><p>Wrapper command allows launching using an extra wrapper program (like 'optirun' on Linux)</p></body></html> + <html><head/><body><p>Pre-launch command runs before the instance launches and post-exit command runs after it exits.</p><p>Both will be run in the launcher's working folder with extra environment variables:</p><ul><li>$INST_NAME - Name of the instance</li><li>$INST_ID - ID of the instance (its folder name)</li><li>$INST_DIR - absolute path of the instance</li><li>$INST_MC_DIR - absolute path of Minecraft</li><li>$INST_JAVA - Java binary used for launch</li><li>$INST_JAVA_ARGS - command-line parameters used for launch (warning: will not work correctly if arguments contain spaces)</li></ul><p>Wrapper command allows launching using an extra wrapper program (like 'optirun' on Linux)</p></body></html> Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop