#include "MinecraftInstance.h" #include #include "settings/SettingsObject.h" #include #include "Env.h" #include "minecraft/MinecraftVersionList.h" #include #define IBUS "@im=ibus" // all of this because keeping things compatible with deprecated old settings // if either of the settings {a, b} is true, this also resolves to true class OrSetting : public Setting { Q_OBJECT public: OrSetting(QString id, std::shared_ptr a, std::shared_ptr b) :Setting({id}, false), m_a(a), m_b(b) { } virtual QVariant get() const { bool a = m_a->get().toBool(); bool b = m_b->get().toBool(); return a || b; } virtual void reset() {} virtual void set(QVariant value) {} private: std::shared_ptr m_a; std::shared_ptr m_b; }; MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir) : BaseInstance(globalSettings, settings, rootDir) { // Java Settings auto javaOverride = m_settings->registerSetting("OverrideJava", false); auto locationOverride = m_settings->registerSetting("OverrideJavaLocation", false); auto javaOrLocation = std::make_shared("JavaOrLocationOverride", javaOverride, locationOverride); m_settings->registerSetting("OverrideJavaArgs", false); m_settings->registerOverride(globalSettings->getSetting("JavaPath")); m_settings->registerOverride(globalSettings->getSetting("JvmArgs")); // special! m_settings->registerPassthrough(globalSettings->getSetting("JavaTimestamp"), javaOrLocation); m_settings->registerPassthrough(globalSettings->getSetting("JavaVersion"), javaOrLocation); // Window Size m_settings->registerSetting("OverrideWindow", false); m_settings->registerOverride(globalSettings->getSetting("LaunchMaximized")); m_settings->registerOverride(globalSettings->getSetting("MinecraftWinWidth")); m_settings->registerOverride(globalSettings->getSetting("MinecraftWinHeight")); // Memory m_settings->registerSetting("OverrideMemory", false); m_settings->registerOverride(globalSettings->getSetting("MinMemAlloc")); m_settings->registerOverride(globalSettings->getSetting("MaxMemAlloc")); m_settings->registerOverride(globalSettings->getSetting("PermGen")); } QString MinecraftInstance::minecraftRoot() const { QFileInfo mcDir(PathCombine(instanceRoot(), "minecraft")); QFileInfo dotMCDir(PathCombine(instanceRoot(), ".minecraft")); if (dotMCDir.exists() && !mcDir.exists()) return dotMCDir.filePath(); else return mcDir.filePath(); } std::shared_ptr< BaseVersionList > MinecraftInstance::versionList() const { return ENV.getVersionList("net.minecraft"); } QStringList MinecraftInstance::javaArguments() const { QStringList args; // custom args go first. we want to override them if we have our own here. args.append(extraArguments()); // OSX dock icon and name #ifdef Q_OS_MAC args << "-Xdock:icon=icon.png"; args << QString("-Xdock:name=\"%1\"").arg(windowTitle()); #endif // HACK: Stupid hack for Intel drivers. See: https://mojang.atlassian.net/browse/MCL-767 #ifdef Q_OS_WIN32 args << QString("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_" "minecraft.exe.heapdump"); #endif args << QString("-Xms%1m").arg(settings()->get("MinMemAlloc").toInt()); args << QString("-Xmx%1m").arg(settings()->get("MaxMemAlloc").toInt()); // No PermGen in newer java. auto javaVersion = settings()->get("JavaVersion"); if(Strings::naturalCompare(javaVersion.toString(), "1.8.0", Qt::CaseInsensitive) < 0) { auto permgen = settings()->get("PermGen").toInt(); if (permgen != 64) { args << QString("-XX:PermSize=%1m").arg(permgen); } } args << "-Duser.language=en"; args << "-jar" << PathCombine(QCoreApplication::applicationDirPath(), "jars", "NewLaunch.jar"); return args; } QMap MinecraftInstance::getVariables() const { QMap out; out.insert("INST_NAME", name()); out.insert("INST_ID", id()); out.insert("INST_DIR", QDir(instanceRoot()).absolutePath()); out.insert("INST_MC_DIR", QDir(minecraftRoot()).absolutePath()); out.insert("INST_JAVA", settings()->get("JavaPath").toString()); out.insert("INST_JAVA_ARGS", javaArguments().join(' ')); return out; } QProcessEnvironment MinecraftInstance::createEnvironment() { // prepare the process environment QProcessEnvironment rawenv = QProcessEnvironment::systemEnvironment(); QProcessEnvironment env; QStringList ignored = { "JAVA_ARGS", "CLASSPATH", "CONFIGPATH", "JAVA_HOME", "JRE_HOME", "_JAVA_OPTIONS", "JAVA_OPTIONS", "JAVA_TOOL_OPTIONS" }; for(auto key: rawenv.keys()) { auto value = rawenv.value(key); // filter out dangerous java crap if(ignored.contains(key)) { qDebug() << "Env: ignoring" << key << value; continue; } // filter MultiMC-related things if(key.startsWith("QT_")) { qDebug() << "Env: ignoring" << key << value; continue; } #ifdef Q_OS_LINUX // Do not pass LD_* variables to java. They were intended for MultiMC if(key.startsWith("LD_")) { qDebug() << "Env: ignoring" << key << value; continue; } // Strip IBus // IBus is a Linux IME framework. For some reason, it breaks MC? if (key == "XMODIFIERS" && value.contains(IBUS)) { QString save = value; value.replace(IBUS, ""); qDebug() << "Env: stripped" << IBUS << "from" << save << ":" << value; } if(key == "GAME_PRELOAD") { env.insert("LD_PRELOAD", value); continue; } if(key == "GAME_LIBRARY_PATH") { env.insert("LD_LIBRARY_PATH", value); continue; } #endif qDebug() << "Env: " << key << value; env.insert(key, value); } #ifdef Q_OS_LINUX // HACK: Workaround for QTBUG42500 if(!env.contains("LD_LIBRARY_PATH")) { env.insert("LD_LIBRARY_PATH", ""); } #endif // export some infos auto variables = getVariables(); for (auto it = variables.begin(); it != variables.end(); ++it) { env.insert(it.key(), it.value()); } return env; } MessageLevel::Enum MinecraftInstance::guessLevel(const QString &line, MessageLevel::Enum level) { QRegularExpression re("\\[(?[0-9:]+)\\] \\[[^/]+/(?[^\\]]+)\\]"); auto match = re.match(line); if(match.hasMatch()) { // New style logs from log4j QString timestamp = match.captured("timestamp"); QString levelStr = match.captured("level"); if(levelStr == "INFO") level = MessageLevel::Message; if(levelStr == "WARN") level = MessageLevel::Warning; if(levelStr == "ERROR") level = MessageLevel::Error; if(levelStr == "FATAL") level = MessageLevel::Fatal; if(levelStr == "TRACE" || levelStr == "DEBUG") level = MessageLevel::Debug; } else { // Old style forge logs if (line.contains("[INFO]") || line.contains("[CONFIG]") || line.contains("[FINE]") || line.contains("[FINER]") || line.contains("[FINEST]")) level = MessageLevel::Message; if (line.contains("[SEVERE]") || line.contains("[STDERR]")) level = MessageLevel::Error; if (line.contains("[WARNING]")) level = MessageLevel::Warning; if (line.contains("[DEBUG]")) level = MessageLevel::Debug; } if (line.contains("overwriting existing")) return MessageLevel::Fatal; if (line.contains("Exception in thread") || line.contains(QRegularExpression("\\s+at "))) return MessageLevel::Error; return level; } #include "MinecraftInstance.moc"