diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 6dd01519..318b59f6 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -242,7 +242,11 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) // --server parser.addOption("server"); parser.addShortOpt("server", 's'); - parser.addDocumentation("server", "Join the specified server on launch (only valid in combination with --launch)"); + parser.addDocumentation("server", "Join the specified server on launch (only valid in combination with --launch, mutually exclusive with --world)"); + // --world + parser.addOption("world"); + parser.addShortOpt("world", 'w'); + parser.addDocumentation("world", "Join the singleplayer world with the specified folder name on launch (only valid in combination with --launch, mutually exclusive with --server, only works with Minecraft 23w14a and later)"); // --profile parser.addOption("profile"); parser.addShortOpt("profile", 'a'); @@ -297,6 +301,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) } m_instanceIdToLaunch = args["launch"].toString(); m_serverToJoin = args["server"].toString(); + m_worldToJoin = args["world"].toString(); m_profileToUse = args["profile"].toString(); if(args["offline"].toBool()) { m_offline = true; @@ -367,6 +372,14 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) return; } + // --world and --server can't be used together + if(!m_worldToJoin.isEmpty() && !m_serverToJoin.isEmpty()) + { + std::cerr << "--server and --world are mutually exclusive!" << std::endl; + m_status = Application::Failed; + return; + } + // all the things invalid when NOT trying to --launch if(m_instanceIdToLaunch.isEmpty()) { if(!m_serverToJoin.isEmpty()) @@ -376,6 +389,13 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) return; } + if(!m_worldToJoin.isEmpty()) + { + std::cerr << "--world can only be used in combination with --launch!" << std::endl; + m_status = Application::Failed; + return; + } + if(!m_profileToUse.isEmpty()) { std::cerr << "--account can only be used in combination with --launch!" << std::endl; @@ -507,6 +527,10 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) { launch.args["server"] = m_serverToJoin; } + if(!m_worldToJoin.isEmpty()) + { + launch.args["world"] = m_worldToJoin; + } if(!m_profileToUse.isEmpty()) { launch.args["profile"] = m_profileToUse; @@ -599,6 +623,10 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) { qDebug() << "Address of server to join :" << m_serverToJoin; } + if(!m_worldToJoin.isEmpty()) + { + qDebug() << "Name of world to join :" << m_worldToJoin; + } qDebug() << "<> Paths set."; } @@ -1070,7 +1098,7 @@ void Application::performMainStartupAction() auto inst = instances()->getInstanceById(m_instanceIdToLaunch); if(inst) { - MinecraftServerTargetPtr serverToJoin = nullptr; + QuickPlayTargetPtr serverOrWorldToJoin = nullptr; MinecraftAccountPtr accountToUse = nullptr; bool offline = m_offline; @@ -1078,10 +1106,16 @@ void Application::performMainStartupAction() if(!m_serverToJoin.isEmpty()) { // FIXME: validate the server string - serverToJoin.reset(new MinecraftServerTarget(MinecraftServerTarget::parse(m_serverToJoin))); + serverOrWorldToJoin.reset(new QuickPlayTarget(QuickPlayTarget::parseMultiplayer(m_serverToJoin))); qDebug() << " Launching with server" << m_serverToJoin; } + if(!m_worldToJoin.isEmpty()) + { + serverOrWorldToJoin.reset(new QuickPlayTarget(QuickPlayTarget::parseSingleplayer(m_worldToJoin))); + qDebug() << " Launching with world" << m_worldToJoin; + } + if(!m_profileToUse.isEmpty()) { accountToUse = accounts()->getAccountByProfileName(m_profileToUse); @@ -1091,7 +1125,7 @@ void Application::performMainStartupAction() qDebug() << " Launching with account" << m_profileToUse; } - launch(inst, !offline, nullptr, serverToJoin, accountToUse, m_offlineName); + launch(inst, !offline, nullptr, serverOrWorldToJoin, accountToUse, m_offlineName); return; } } @@ -1180,9 +1214,9 @@ void Application::messageReceived(const QByteArray& message) return; } - MinecraftServerTargetPtr serverObject = nullptr; + QuickPlayTargetPtr serverObject = nullptr; if(!server.isEmpty()) { - serverObject = std::make_shared(MinecraftServerTarget::parse(server)); + serverObject = std::make_shared(QuickPlayTarget::parseMultiplayer(server)); } MinecraftAccountPtr accountObject; @@ -1297,7 +1331,7 @@ bool Application::launch( InstancePtr instance, bool online, BaseProfilerFactory *profiler, - MinecraftServerTargetPtr serverToJoin, + QuickPlayTargetPtr quickPlayTarget, MinecraftAccountPtr accountToUse, const QString& offlineName ) { @@ -1321,7 +1355,7 @@ bool Application::launch( controller->setInstance(instance); controller->setOnline(online); controller->setProfiler(profiler); - controller->setServerToJoin(serverToJoin); + controller->setQuickPlayTarget(quickPlayTarget); controller->setAccountToUse(accountToUse); controller->setOfflineName(offlineName); if(window) diff --git a/launcher/Application.h b/launcher/Application.h index f9e523f9..1de5327c 100644 --- a/launcher/Application.h +++ b/launcher/Application.h @@ -11,7 +11,7 @@ #include -#include "minecraft/launch/MinecraftServerTarget.h" +#include "minecraft/launch/QuickPlayTarget.h" class LaunchController; class LocalPeer; @@ -150,12 +150,12 @@ signals: public slots: bool launch( - InstancePtr instance, - bool online = true, - BaseProfilerFactory *profiler = nullptr, - MinecraftServerTargetPtr serverToJoin = nullptr, - MinecraftAccountPtr accountToUse = nullptr, - const QString &offlineName = QString() + InstancePtr instance, + bool online = true, + BaseProfilerFactory *profiler = nullptr, + QuickPlayTargetPtr quickPlayTarget = nullptr, + MinecraftAccountPtr accountToUse = nullptr, + const QString &offlineName = QString() ); bool kill(InstancePtr instance); @@ -234,6 +234,7 @@ private: public: QString m_instanceIdToLaunch; QString m_serverToJoin; + QString m_worldToJoin; QString m_profileToUse; bool m_offline = false; QString m_offlineName; diff --git a/launcher/BaseInstance.h b/launcher/BaseInstance.h index c148f37e..4e8b4b83 100644 --- a/launcher/BaseInstance.h +++ b/launcher/BaseInstance.h @@ -33,7 +33,7 @@ #include "net/Mode.h" -#include "minecraft/launch/MinecraftServerTarget.h" +#include "minecraft/launch/QuickPlayTarget.h" class QDir; class Task; @@ -161,7 +161,7 @@ public: /// returns a valid launcher (task container) virtual shared_qobject_ptr createLaunchTask( - AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) = 0; + AuthSessionPtr account, QuickPlayTargetPtr quickPlayTarget) = 0; /// returns the current launch task (if any) shared_qobject_ptr getLaunchTask(); @@ -239,7 +239,7 @@ public: /** * 'print' a verbose description of the instance into a QStringList */ - virtual QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) = 0; + virtual QStringList verboseDescription(AuthSessionPtr session, QuickPlayTargetPtr quickPlayTarget) = 0; Status currentStatus() const; diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 95db0882..c6204c09 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -269,8 +269,8 @@ set(MINECRAFT_SOURCES minecraft/launch/ExtractNatives.h minecraft/launch/LauncherPartLaunch.cpp minecraft/launch/LauncherPartLaunch.h - minecraft/launch/MinecraftServerTarget.cpp - minecraft/launch/MinecraftServerTarget.h + minecraft/launch/QuickPlayTarget.cpp + minecraft/launch/QuickPlayTarget.h minecraft/launch/PrintInstanceInfo.cpp minecraft/launch/PrintInstanceInfo.h minecraft/launch/ReconstructAssets.cpp diff --git a/launcher/InstancePageProvider.h b/launcher/InstancePageProvider.h index 2af90b91..76d183f6 100644 --- a/launcher/InstancePageProvider.h +++ b/launcher/InstancePageProvider.h @@ -45,7 +45,7 @@ public: values.append(new TexturePackPage(onesix.get())); values.append(new ShaderPackPage(onesix.get())); values.append(new NotesPage(onesix.get())); - values.append(new WorldListPage(onesix.get(), onesix->worldList())); + values.append(new WorldListPage(onesix, onesix->worldList())); values.append(new ServersPage(onesix)); // values.append(new GameOptionsPage(onesix.get())); values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots"))); @@ -56,7 +56,7 @@ public: { values.append(new LegacyUpgradePage(legacy)); values.append(new NotesPage(legacy.get())); - values.append(new WorldListPage(legacy.get(), legacy->worldList())); + values.append(new WorldListPage(legacy, legacy->worldList())); values.append(new ScreenshotsPage(FS::PathCombine(legacy->gameRoot(), "screenshots"))); } auto logMatcher = inst->getLogFileMatcher(); diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp index 32c5f49b..597eb4c0 100644 --- a/launcher/LaunchController.cpp +++ b/launcher/LaunchController.cpp @@ -321,7 +321,7 @@ void LaunchController::launchInstance() return; } - m_launcher = m_instance->createLaunchTask(m_session, m_serverToJoin); + m_launcher = m_instance->createLaunchTask(m_session, m_quickPlayTarget); if (!m_launcher) { emitFailed(tr("Couldn't instantiate a launcher.")); diff --git a/launcher/LaunchController.h b/launcher/LaunchController.h index 53a704c0..cb99dc27 100644 --- a/launcher/LaunchController.h +++ b/launcher/LaunchController.h @@ -3,7 +3,7 @@ #include #include -#include "minecraft/launch/MinecraftServerTarget.h" +#include "minecraft/launch/QuickPlayTarget.h" #include "minecraft/auth/MinecraftAccount.h" class InstanceWindow; @@ -40,8 +40,8 @@ public: m_parentWidget = widget; } - void setServerToJoin(MinecraftServerTargetPtr serverToJoin) { - m_serverToJoin = std::move(serverToJoin); + void setQuickPlayTarget(QuickPlayTargetPtr quickPlayTarget) { + m_quickPlayTarget = std::move(quickPlayTarget); } void setAccountToUse(MinecraftAccountPtr accountToUse) { @@ -77,5 +77,5 @@ private: MinecraftAccountPtr m_accountToUse = nullptr; AuthSessionPtr m_session; shared_qobject_ptr m_launcher; - MinecraftServerTargetPtr m_serverToJoin; + QuickPlayTargetPtr m_quickPlayTarget; }; diff --git a/launcher/NullInstance.h b/launcher/NullInstance.h index ed421433..2a777966 100644 --- a/launcher/NullInstance.h +++ b/launcher/NullInstance.h @@ -27,7 +27,7 @@ public: { return instanceRoot(); }; - shared_qobject_ptr createLaunchTask(AuthSessionPtr, MinecraftServerTargetPtr) override + shared_qobject_ptr createLaunchTask(AuthSessionPtr, QuickPlayTargetPtr) override { return nullptr; } @@ -67,7 +67,7 @@ public: { return false; } - QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override + QStringList verboseDescription(AuthSessionPtr session, QuickPlayTargetPtr quickPlayTarget) override { QStringList out; out << "Null instance - placeholder."; diff --git a/launcher/launch/steps/LookupServerAddress.cpp b/launcher/launch/steps/LookupServerAddress.cpp index c7b8cea4..de59af54 100644 --- a/launcher/launch/steps/LookupServerAddress.cpp +++ b/launcher/launch/steps/LookupServerAddress.cpp @@ -32,7 +32,7 @@ void LookupServerAddress::setLookupAddress(const QString &lookupAddress) m_dnsLookup->setName(QString("_minecraft._tcp.%1").arg(lookupAddress)); } -void LookupServerAddress::setOutputAddressPtr(MinecraftServerTargetPtr output) +void LookupServerAddress::setOutputAddressPtr(QuickPlayTargetPtr output) { m_output = std::move(output); } diff --git a/launcher/launch/steps/LookupServerAddress.h b/launcher/launch/steps/LookupServerAddress.h index 5a5c3de1..4966b30e 100644 --- a/launcher/launch/steps/LookupServerAddress.h +++ b/launcher/launch/steps/LookupServerAddress.h @@ -19,7 +19,7 @@ #include #include -#include "minecraft/launch/MinecraftServerTarget.h" +#include "minecraft/launch/QuickPlayTarget.h" class LookupServerAddress: public LaunchStep { Q_OBJECT @@ -35,7 +35,7 @@ public: } void setLookupAddress(const QString &lookupAddress); - void setOutputAddressPtr(MinecraftServerTargetPtr output); + void setOutputAddressPtr(QuickPlayTargetPtr output); private slots: void on_dnsLookupFinished(); @@ -45,5 +45,5 @@ private: QDnsLookup *m_dnsLookup; QString m_lookupAddress; - MinecraftServerTargetPtr m_output; + QuickPlayTargetPtr m_output; }; diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 19256e30..2c7d8558 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -122,8 +122,11 @@ MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsO m_settings->registerOverride(globalSettings->getSetting("RecordGameTime"), gameTimeOverride); // Join server on launch, this does not have a global override + m_settings->registerSetting("JoinWorldOnLaunch", false); m_settings->registerSetting("JoinServerOnLaunch", false); m_settings->registerSetting("JoinServerOnLaunchAddress", ""); + m_settings->registerSetting("JoinSingleplayerWorldOnLaunch", false); + m_settings->registerSetting("JoinSingleplayerWorldOnLaunchName", ""); // DEPRECATED: Read what versions the user configuration thinks should be used m_settings->registerSetting({"IntendedVersion", "MinecraftVersion"}, ""); @@ -415,7 +418,7 @@ static QString replaceTokensIn(QString text, QMap with) } QStringList MinecraftInstance::processMinecraftArgs( - AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) const + AuthSessionPtr session, QuickPlayTargetPtr quickPlayTarget) const { auto profile = m_components->getProfile(); QString args_pattern = profile->getMinecraftArguments(); @@ -424,18 +427,23 @@ QStringList MinecraftInstance::processMinecraftArgs( args_pattern += " --tweakClass " + tweaker; } - if (serverToJoin && !serverToJoin->address.isEmpty()) + if (quickPlayTarget && !quickPlayTarget->address.isEmpty()) { if (m_components->getComponent("net.minecraft")->getReleaseDateTime() >= g_VersionFilterData.quickPlayBeginsDate) { - args_pattern += " --quickPlayMultiplayer " + serverToJoin->address + ":" + QString::number(serverToJoin->port); + args_pattern += " --quickPlayMultiplayer " + quickPlayTarget->address + ":" + QString::number(quickPlayTarget->port); } else { - args_pattern += " --server " + serverToJoin->address; - args_pattern += " --port " + QString::number(serverToJoin->port); + args_pattern += " --server " + quickPlayTarget->address; + args_pattern += " --port " + QString::number(quickPlayTarget->port); } } + + if (quickPlayTarget && quickPlayTarget->world.isEmpty()) + { + args_pattern += " --quickPlaySingleplayer \"" + quickPlayTarget->world + "\""; + } QMap token_mapping; // yggdrasil! @@ -474,7 +482,7 @@ QStringList MinecraftInstance::processMinecraftArgs( return parts; } -QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) +QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, QuickPlayTargetPtr quickPlayTarget) { QString launchScript; @@ -495,17 +503,22 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS launchScript += "appletClass " + appletClass + "\n"; } - if (serverToJoin && !serverToJoin->address.isEmpty()) + if (quickPlayTarget && !quickPlayTarget->address.isEmpty()) { launchScript += "useQuickPlay " + QString::number(m_components->getComponent("net.minecraft")->getReleaseDateTime() >= g_VersionFilterData.quickPlayBeginsDate) + "\n"; - launchScript += "serverAddress " + serverToJoin->address + "\n"; - launchScript += "serverPort " + QString::number(serverToJoin->port) + "\n"; + launchScript += "serverAddress " + quickPlayTarget->address + "\n"; + launchScript += "serverPort " + QString::number(quickPlayTarget->port) + "\n"; + } + + if (quickPlayTarget && !quickPlayTarget->world.isEmpty()) + { + launchScript += "joinWorld " + quickPlayTarget->world + "\n"; } // generic minecraft params for (auto param : processMinecraftArgs( session, - nullptr /* When using a launch script, the server parameters are handled by it*/ + nullptr /* When using a launch script, the server and world parameters are handled by it*/ )) { launchScript += "param " + param + "\n"; @@ -558,7 +571,7 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS return launchScript; } -QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) +QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, QuickPlayTargetPtr quickPlayTarget) { QStringList out; out << "Main Class:" << " " + getMainClass() << ""; @@ -673,7 +686,7 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr out << ""; } - auto params = processMinecraftArgs(nullptr, serverToJoin); + auto params = processMinecraftArgs(nullptr, quickPlayTarget); out << "Params:"; out << " " + params.join(' '); out << ""; @@ -834,7 +847,7 @@ Task::Ptr MinecraftInstance::createUpdateTask(Net::Mode mode) return nullptr; } -shared_qobject_ptr MinecraftInstance::createLaunchTask(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) +shared_qobject_ptr MinecraftInstance::createLaunchTask(AuthSessionPtr session, QuickPlayTargetPtr quickPlayTarget) { // FIXME: get rid of shared_from_this ... auto process = LaunchTask::create(std::dynamic_pointer_cast(shared_from_this())); @@ -866,18 +879,26 @@ shared_qobject_ptr MinecraftInstance::createLaunchTask(AuthSessionPt process->appendStep(new CreateGameFolders(pptr)); } - if (!serverToJoin && m_settings->get("JoinServerOnLaunch").toBool()) + if (!quickPlayTarget && m_settings->get("JoinWorldOnLaunch").toBool()) { - QString fullAddress = m_settings->get("JoinServerOnLaunchAddress").toString(); - serverToJoin.reset(new MinecraftServerTarget(MinecraftServerTarget::parse(fullAddress))); + if (m_settings->get("JoinServerOnLaunch").toBool()) + { + QString fullAddress = m_settings->get("JoinServerOnLaunchAddress").toString(); + quickPlayTarget.reset(new QuickPlayTarget(QuickPlayTarget::parseMultiplayer(fullAddress))); + } + else if (m_settings->get("JoinSingleplayerWorldOnLaunch").toBool()) + { + QString worldName = m_settings->get("JoinSingleplayerWorldOnLaunchName").toString(); + quickPlayTarget.reset(new QuickPlayTarget(QuickPlayTarget::parseSingleplayer(worldName))); + } } - if(serverToJoin && serverToJoin->port == 25565) + if(quickPlayTarget && quickPlayTarget->port == 25565) { // Resolve server address to join on launch auto *step = new LookupServerAddress(pptr); - step->setLookupAddress(serverToJoin->address); - step->setOutputAddressPtr(serverToJoin); + step->setLookupAddress(quickPlayTarget->address); + step->setOutputAddressPtr(quickPlayTarget); process->appendStep(step); } @@ -914,7 +935,7 @@ shared_qobject_ptr MinecraftInstance::createLaunchTask(AuthSessionPt // print some instance info here... { - process->appendStep(new PrintInstanceInfo(pptr, session, serverToJoin)); + process->appendStep(new PrintInstanceInfo(pptr, session, quickPlayTarget)); } // extract native jars if needed @@ -940,7 +961,7 @@ shared_qobject_ptr MinecraftInstance::createLaunchTask(AuthSessionPt auto step = new LauncherPartLaunch(pptr); step->setWorkingDirectory(gameRoot()); step->setAuthSession(session); - step->setServerToJoin(serverToJoin); + step->setQuickPlayTarget(quickPlayTarget); process->appendStep(step); } else if (method == "DirectJava") @@ -948,7 +969,7 @@ shared_qobject_ptr MinecraftInstance::createLaunchTask(AuthSessionPt auto step = new DirectJavaLaunch(pptr); step->setWorkingDirectory(gameRoot()); step->setAuthSession(session); - step->setServerToJoin(serverToJoin); + step->setQuickPlayTarget(quickPlayTarget); process->appendStep(step); } } diff --git a/launcher/minecraft/MinecraftInstance.h b/launcher/minecraft/MinecraftInstance.h index fda58aa7..c66bf70d 100644 --- a/launcher/minecraft/MinecraftInstance.h +++ b/launcher/minecraft/MinecraftInstance.h @@ -4,7 +4,7 @@ #include "minecraft/mod/Mod.h" #include #include -#include "minecraft/launch/MinecraftServerTarget.h" +#include "minecraft/launch/QuickPlayTarget.h" class ModFolderModel; class WorldList; @@ -78,11 +78,11 @@ public: ////// Launch stuff ////// Task::Ptr createUpdateTask(Net::Mode mode) override; - shared_qobject_ptr createLaunchTask(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) override; + shared_qobject_ptr createLaunchTask(AuthSessionPtr account, QuickPlayTargetPtr quickPlayTarget) override; QStringList extraArguments() const override; - QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override; + QStringList verboseDescription(AuthSessionPtr session, QuickPlayTargetPtr quickPlayTarget) override; QList getJarMods() const; - QString createLaunchScript(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin); + QString createLaunchScript(AuthSessionPtr session, QuickPlayTargetPtr quickPlayTarget); /// get arguments passed to java QStringList javaArguments() const; @@ -109,7 +109,7 @@ public: virtual QString getMainClass() const; // FIXME: remove - virtual QStringList processMinecraftArgs(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) const; + virtual QStringList processMinecraftArgs(AuthSessionPtr account, QuickPlayTargetPtr quickPlayTarget) const; virtual JavaVersion getJavaVersion() const; diff --git a/launcher/minecraft/launch/DirectJavaLaunch.cpp b/launcher/minecraft/launch/DirectJavaLaunch.cpp index 2bcff664..7019fb46 100644 --- a/launcher/minecraft/launch/DirectJavaLaunch.cpp +++ b/launcher/minecraft/launch/DirectJavaLaunch.cpp @@ -55,7 +55,7 @@ void DirectJavaLaunch::executeTask() // make detachable - this will keep the process running even if the object is destroyed m_process.setDetachable(true); - auto mcArgs = minecraftInstance->processMinecraftArgs(m_session, m_serverToJoin); + auto mcArgs = minecraftInstance->processMinecraftArgs(m_session, m_quickPlayTarget); args.append(mcArgs); QString wrapperCommandStr = instance->getWrapperCommand().trimmed(); diff --git a/launcher/minecraft/launch/DirectJavaLaunch.h b/launcher/minecraft/launch/DirectJavaLaunch.h index 58b119b8..5e27ed56 100644 --- a/launcher/minecraft/launch/DirectJavaLaunch.h +++ b/launcher/minecraft/launch/DirectJavaLaunch.h @@ -19,7 +19,7 @@ #include #include -#include "MinecraftServerTarget.h" +#include "QuickPlayTarget.h" class DirectJavaLaunch: public LaunchStep { @@ -41,9 +41,9 @@ public: m_session = session; } - void setServerToJoin(MinecraftServerTargetPtr serverToJoin) + void setQuickPlayTarget(QuickPlayTargetPtr quickPlayTarget) { - m_serverToJoin = std::move(serverToJoin); + m_quickPlayTarget = std::move(quickPlayTarget); } private slots: @@ -53,6 +53,6 @@ private: LoggedProcess m_process; QString m_command; AuthSessionPtr m_session; - MinecraftServerTargetPtr m_serverToJoin; + QuickPlayTargetPtr m_quickPlayTarget; }; diff --git a/launcher/minecraft/launch/LauncherPartLaunch.cpp b/launcher/minecraft/launch/LauncherPartLaunch.cpp index 8fd11eca..35d5c67e 100644 --- a/launcher/minecraft/launch/LauncherPartLaunch.cpp +++ b/launcher/minecraft/launch/LauncherPartLaunch.cpp @@ -60,7 +60,7 @@ void LauncherPartLaunch::executeTask() auto instance = m_parent->instance(); std::shared_ptr minecraftInstance = std::dynamic_pointer_cast(instance); - m_launchScript = minecraftInstance->createLaunchScript(m_session, m_serverToJoin); + m_launchScript = minecraftInstance->createLaunchScript(m_session, m_quickPlayTarget); QStringList args = minecraftInstance->javaArguments(); QString allArgs = args.join(", "); emit logLine("Java Arguments:\n[" + m_parent->censorPrivateInfo(allArgs) + "]\n\n", MessageLevel::Launcher); diff --git a/launcher/minecraft/launch/LauncherPartLaunch.h b/launcher/minecraft/launch/LauncherPartLaunch.h index 6a7ee0e5..19add61f 100644 --- a/launcher/minecraft/launch/LauncherPartLaunch.h +++ b/launcher/minecraft/launch/LauncherPartLaunch.h @@ -19,7 +19,7 @@ #include #include -#include "MinecraftServerTarget.h" +#include "QuickPlayTarget.h" class LauncherPartLaunch: public LaunchStep { @@ -41,9 +41,9 @@ public: m_session = session; } - void setServerToJoin(MinecraftServerTargetPtr serverToJoin) + void setQuickPlayTarget(QuickPlayTargetPtr quickPlayTarget) { - m_serverToJoin = std::move(serverToJoin); + m_quickPlayTarget = std::move(quickPlayTarget); } private slots: @@ -54,7 +54,7 @@ private: QString m_command; AuthSessionPtr m_session; QString m_launchScript; - MinecraftServerTargetPtr m_serverToJoin; + QuickPlayTargetPtr m_quickPlayTarget; bool mayProceed = false; }; diff --git a/launcher/minecraft/launch/PrintInstanceInfo.cpp b/launcher/minecraft/launch/PrintInstanceInfo.cpp index e8fbcb9b..5311fc08 100644 --- a/launcher/minecraft/launch/PrintInstanceInfo.cpp +++ b/launcher/minecraft/launch/PrintInstanceInfo.cpp @@ -142,6 +142,6 @@ void PrintInstanceInfo::executeTask() #endif logLines(log, MessageLevel::Launcher); - logLines(instance->verboseDescription(m_session, m_serverToJoin), MessageLevel::Launcher); + logLines(instance->verboseDescription(m_session, m_quickPlayTarget), MessageLevel::Launcher); emitSucceeded(); } diff --git a/launcher/minecraft/launch/PrintInstanceInfo.h b/launcher/minecraft/launch/PrintInstanceInfo.h index fdc30f31..23d4c4a2 100644 --- a/launcher/minecraft/launch/PrintInstanceInfo.h +++ b/launcher/minecraft/launch/PrintInstanceInfo.h @@ -18,15 +18,15 @@ #include #include #include "minecraft/auth/AuthSession.h" -#include "minecraft/launch/MinecraftServerTarget.h" +#include "minecraft/launch/QuickPlayTarget.h" // FIXME: temporary wrapper for existing task. class PrintInstanceInfo: public LaunchStep { Q_OBJECT public: - explicit PrintInstanceInfo(LaunchTask *parent, AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) : - LaunchStep(parent), m_session(session), m_serverToJoin(serverToJoin) {}; + explicit PrintInstanceInfo(LaunchTask *parent, AuthSessionPtr session, QuickPlayTargetPtr quickPlayTarget) : + LaunchStep(parent), m_session(session), m_quickPlayTarget(quickPlayTarget) {}; virtual ~PrintInstanceInfo(){}; virtual void executeTask(); @@ -36,6 +36,6 @@ public: } private: AuthSessionPtr m_session; - MinecraftServerTargetPtr m_serverToJoin; + QuickPlayTargetPtr m_quickPlayTarget; }; diff --git a/launcher/minecraft/launch/MinecraftServerTarget.cpp b/launcher/minecraft/launch/QuickPlayTarget.cpp similarity index 85% rename from launcher/minecraft/launch/MinecraftServerTarget.cpp rename to launcher/minecraft/launch/QuickPlayTarget.cpp index 0f98f356..ac08afa3 100644 --- a/launcher/minecraft/launch/MinecraftServerTarget.cpp +++ b/launcher/minecraft/launch/QuickPlayTarget.cpp @@ -13,12 +13,12 @@ * limitations under the License. */ -#include "MinecraftServerTarget.h" +#include "QuickPlayTarget.h" #include // FIXME: the way this is written, it can't ever do any sort of validation and can accept total junk -MinecraftServerTarget MinecraftServerTarget::parse(const QString &fullAddress) { +QuickPlayTarget QuickPlayTarget::parseMultiplayer(const QString &fullAddress) { QStringList split = fullAddress.split(":"); // The logic below replicates the exact logic minecraft uses for parsing server addresses. @@ -63,5 +63,12 @@ MinecraftServerTarget MinecraftServerTarget::parse(const QString &fullAddress) { } } - return MinecraftServerTarget { realAddress, realPort }; + return QuickPlayTarget {realAddress, realPort }; +} + +QuickPlayTarget QuickPlayTarget::parseSingleplayer(const QString &worldName) +{ + QuickPlayTarget target; + target.world = worldName; + return target; } diff --git a/launcher/minecraft/launch/MinecraftServerTarget.h b/launcher/minecraft/launch/QuickPlayTarget.h similarity index 70% rename from launcher/minecraft/launch/MinecraftServerTarget.h rename to launcher/minecraft/launch/QuickPlayTarget.h index a402421a..f4a8dc82 100644 --- a/launcher/minecraft/launch/MinecraftServerTarget.h +++ b/launcher/minecraft/launch/QuickPlayTarget.h @@ -19,11 +19,16 @@ #include -struct MinecraftServerTarget { +struct QuickPlayTarget { + // Multiplayer QString address; quint16 port; - static MinecraftServerTarget parse(const QString &fullAddress); + // Singleplayer + QString world; + + static QuickPlayTarget parseMultiplayer(const QString &fullAddress); + static QuickPlayTarget parseSingleplayer(const QString &worldName); }; -typedef std::shared_ptr MinecraftServerTargetPtr; +typedef std::shared_ptr QuickPlayTargetPtr; diff --git a/launcher/minecraft/legacy/LegacyInstance.cpp b/launcher/minecraft/legacy/LegacyInstance.cpp index f467ec06..1849d315 100644 --- a/launcher/minecraft/legacy/LegacyInstance.cpp +++ b/launcher/minecraft/legacy/LegacyInstance.cpp @@ -225,7 +225,7 @@ QString LegacyInstance::getStatusbarDescription() return tr("Instance from previous versions."); } -QStringList LegacyInstance::verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) +QStringList LegacyInstance::verboseDescription(AuthSessionPtr session, QuickPlayTargetPtr quickPlayTarget) { QStringList out; diff --git a/launcher/minecraft/legacy/LegacyInstance.h b/launcher/minecraft/legacy/LegacyInstance.h index 298543f7..7751ef97 100644 --- a/launcher/minecraft/legacy/LegacyInstance.h +++ b/launcher/minecraft/legacy/LegacyInstance.h @@ -112,7 +112,7 @@ public: return false; } shared_qobject_ptr createLaunchTask( - AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) override + AuthSessionPtr account, QuickPlayTargetPtr quickPlayTarget) override { return nullptr; } @@ -126,7 +126,7 @@ public: } QString getStatusbarDescription() override; - QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override; + QStringList verboseDescription(AuthSessionPtr session, QuickPlayTargetPtr quickPlayTarget) override; QProcessEnvironment createEnvironment() override { diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp index 397504fc..36e837d0 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.cpp +++ b/launcher/ui/pages/instance/InstanceSettingsPage.cpp @@ -16,6 +16,10 @@ #include "java/JavaInstallList.h" #include "FileSystem.h" +#include "minecraft/MinecraftInstance.h" +#include "minecraft/PackProfile.h" +#include "minecraft/VersionFilterData.h" +#include "minecraft/WorldList.h" InstanceSettingsPage::InstanceSettingsPage(BaseInstance *inst, QWidget *parent) : QWidget(parent), ui(new Ui::InstanceSettingsPage), m_instance(inst) @@ -27,6 +31,23 @@ InstanceSettingsPage::InstanceSettingsPage(BaseInstance *inst, QWidget *parent) connect(ui->openGlobalJavaSettingsButton, &QCommandLinkButton::clicked, this, &InstanceSettingsPage::globalSettingsButtonClicked); connect(APPLICATION, &Application::globalSettingsAboutToOpen, this, &InstanceSettingsPage::applySettings); connect(APPLICATION, &Application::globalSettingsClosed, this, &InstanceSettingsPage::loadSettings); + + auto *mcInst = dynamic_cast(inst); + if (mcInst && mcInst->getPackProfile()->getComponent("net.minecraft")->getReleaseDateTime() >= g_VersionFilterData.quickPlayBeginsDate) + { + mcInst->worldList()->update(); + for (const auto &world : mcInst->worldList()->allWorlds()) + { + ui->worldsComboBox->addItem(world.folderName()); + } + } + else + { + ui->worldRadioButton->setVisible(false); + ui->worldsComboBox->setVisible(false); + ui->serverAddressRadioButton->setChecked(true); + } + loadSettings(); } @@ -195,8 +216,12 @@ void InstanceSettingsPage::applySettings() } // Join server on launch - bool joinServerOnLaunch = ui->serverJoinGroupBox->isChecked(); + bool joinWorldOnLaunch = ui->quickPlayGroupBox->isChecked(); + m_settings->set("JoinWorldOnLaunch", joinWorldOnLaunch); + + bool joinServerOnLaunch = ui->serverAddressRadioButton->isChecked(); m_settings->set("JoinServerOnLaunch", joinServerOnLaunch); + if (joinServerOnLaunch) { m_settings->set("JoinServerOnLaunchAddress", ui->serverJoinAddress->text()); @@ -205,6 +230,18 @@ void InstanceSettingsPage::applySettings() { m_settings->reset("JoinServerOnLaunchAddress"); } + + bool joinSingleplayerWorldOnLaunch = ui->worldRadioButton->isChecked(); + m_settings->set("JoinSingleplayerWorldOnLaunch", joinSingleplayerWorldOnLaunch); + + if (joinSingleplayerWorldOnLaunch) + { + m_settings->set("JoinSingleplayerWorldOnLaunchName", ui->worldsComboBox->currentText()); + } + else + { + m_settings->reset("JoinSingleplayerWorldOnLaunchName"); + } } void InstanceSettingsPage::loadSettings() @@ -272,8 +309,23 @@ void InstanceSettingsPage::loadSettings() ui->showGameTime->setChecked(m_settings->get("ShowGameTime").toBool()); ui->recordGameTime->setChecked(m_settings->get("RecordGameTime").toBool()); - ui->serverJoinGroupBox->setChecked(m_settings->get("JoinServerOnLaunch").toBool()); - ui->serverJoinAddress->setText(m_settings->get("JoinServerOnLaunchAddress").toString()); + if (!m_settings->contains("JoinWorldOnLaunch")) + { + ui->quickPlayGroupBox->setChecked(m_settings->get("JoinServerOnLaunch").toBool()); + ui->serverAddressRadioButton->setChecked(m_settings->get("JoinServerOnLaunch").toBool()); + ui->worldRadioButton->setChecked(false); + } + else + { + ui->quickPlayGroupBox->setChecked(m_settings->get("JoinWorldOnLaunch").toBool()); + ui->serverAddressRadioButton->setChecked(m_settings->get("JoinServerOnLaunch").toBool()); + ui->serverJoinAddress->setEnabled(m_settings->get("JoinServerOnLaunch").toBool()); + ui->serverJoinAddress->setText(m_settings->get("JoinServerOnLaunchAddress").toString()); + ui->worldRadioButton->setChecked(m_settings->get("JoinSingleplayerWorldOnLaunch").toBool()); + ui->worldsComboBox->setEnabled(m_settings->get("JoinSingleplayerWorldOnLaunch").toBool()); + ui->worldsComboBox->setCurrentText(m_settings->get("JoinSingleplayerWorldOnLaunchName").toString()); + } + } void InstanceSettingsPage::on_javaDetectBtn_clicked() @@ -334,6 +386,16 @@ void InstanceSettingsPage::on_javaTestBtn_clicked() checker->run(); } +void InstanceSettingsPage::on_serverAddressRadioButton_toggled(bool checked) +{ + ui->serverJoinAddress->setEnabled(checked); +} + +void InstanceSettingsPage::on_worldRadioButton_toggled(bool checked) +{ + ui->worldsComboBox->setEnabled(checked); +} + void InstanceSettingsPage::checkerFinished() { checker.reset(); diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.h b/launcher/ui/pages/instance/InstanceSettingsPage.h index 5c8c8e66..bb117def 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.h +++ b/launcher/ui/pages/instance/InstanceSettingsPage.h @@ -22,6 +22,7 @@ #include #include "ui/pages/BasePage.h" #include "JavaCommon.h" +#include "minecraft/WorldList.h" #include "Application.h" class JavaChecker; @@ -60,6 +61,8 @@ private slots: void on_javaDetectBtn_clicked(); void on_javaTestBtn_clicked(); void on_javaBrowseBtn_clicked(); + void on_serverAddressRadioButton_toggled(bool checked); + void on_worldRadioButton_toggled(bool checked); void applySettings(); void loadSettings(); diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui index 729f8e2a..e8310d38 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.ui +++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui @@ -39,7 +39,7 @@ QTabWidget::Rounded - 0 + 4 @@ -454,9 +454,9 @@ - + - Set a server to join on launch + Set a world to join on launch true @@ -466,15 +466,9 @@ - + - - - - 0 - 0 - - + Server address: @@ -483,6 +477,16 @@ + + + + Singleplayer world: + + + + + + diff --git a/launcher/ui/pages/instance/ServersPage.cpp b/launcher/ui/pages/instance/ServersPage.cpp index 8116d2bf..7cd39180 100644 --- a/launcher/ui/pages/instance/ServersPage.cpp +++ b/launcher/ui/pages/instance/ServersPage.cpp @@ -762,7 +762,8 @@ void ServersPage::on_actionMove_Down_triggered() void ServersPage::on_actionJoin_triggered() { const auto &address = m_model->at(currentServer)->m_address; - APPLICATION->launch(m_inst, true, nullptr, std::make_shared(MinecraftServerTarget::parse(address))); + APPLICATION->launch(m_inst, true, nullptr, std::make_shared( + QuickPlayTarget::parseMultiplayer(address))); } #include "ServersPage.moc" diff --git a/launcher/ui/pages/instance/WorldListPage.cpp b/launcher/ui/pages/instance/WorldListPage.cpp index d2bf63bd..908b464d 100644 --- a/launcher/ui/pages/instance/WorldListPage.cpp +++ b/launcher/ui/pages/instance/WorldListPage.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include "tools/MCEditTool.h" #include "FileSystem.h" @@ -32,6 +31,9 @@ #include "ui/GuiUtil.h" #include "DesktopServices.h" +#include "minecraft/PackProfile.h" +#include "minecraft/VersionFilterData.h" + #include "Application.h" @@ -62,7 +64,7 @@ public: }; -WorldListPage::WorldListPage(BaseInstance *inst, std::shared_ptr worlds, QWidget *parent) +WorldListPage::WorldListPage(InstancePtr inst, std::shared_ptr worlds, QWidget *parent) : QMainWindow(parent), m_inst(inst), ui(new Ui::WorldListPage), m_worlds(worlds) { ui->setupUi(this); @@ -311,8 +313,15 @@ void WorldListPage::mceditState(LoggedProcess::State state) void WorldListPage::worldChanged(const QModelIndex ¤t, const QModelIndex &previous) { + auto mcInst = std::dynamic_pointer_cast(m_inst); + bool enableJoinActions = mcInst && mcInst->getPackProfile()->getComponent("net.minecraft")->getReleaseDateTime() >= g_VersionFilterData.quickPlayBeginsDate; + QModelIndex index = getSelectedWorld(); bool enable = index.isValid(); + // FIXME: Hide the join buttons if the Minecraft version is too old instead of just disabling them. + // ui->actionJoin->setVisible(false) had no effect for some reason, at least on my machine -arthomnix + ui->actionJoin->setEnabled(enable && enableJoinActions); + ui->actionJoinOffline->setEnabled(enable && enableJoinActions); ui->actionCopy_Seed->setEnabled(enable); ui->actionMCEdit->setEnabled(enable); ui->actionRemove->setEnabled(enable); @@ -409,4 +418,29 @@ void WorldListPage::on_actionRefresh_triggered() m_worlds->update(); } +void WorldListPage::joinSelectedWorld(bool online) +{ + auto index = getSelectedWorld(); + if (!index.isValid()) + { + return; + } + + auto worldVariant = m_worlds->data(index, WorldList::ObjectRole); + auto world = (World *) worldVariant.value(); + auto name = world->folderName(); + + APPLICATION->launch(m_inst, online, nullptr, std::make_shared(QuickPlayTarget::parseSingleplayer(name))); +} + +void WorldListPage::on_actionJoin_triggered() +{ + joinSelectedWorld(true); +} + +void WorldListPage::on_actionJoinOffline_triggered() +{ + joinSelectedWorld(false); +} + #include "WorldListPage.moc" diff --git a/launcher/ui/pages/instance/WorldListPage.h b/launcher/ui/pages/instance/WorldListPage.h index e07d5794..ceb6df98 100644 --- a/launcher/ui/pages/instance/WorldListPage.h +++ b/launcher/ui/pages/instance/WorldListPage.h @@ -34,7 +34,7 @@ class WorldListPage : public QMainWindow, public BasePage public: explicit WorldListPage( - BaseInstance *inst, + InstancePtr inst, std::shared_ptr worlds, QWidget *parent = 0 ); @@ -67,13 +67,14 @@ protected: QMenu * createPopupMenu() override; protected: - BaseInstance *m_inst; + InstancePtr m_inst; private: QModelIndex getSelectedWorld(); bool isWorldSafe(QModelIndex index); bool worldSafetyNagQuestion(); void mceditError(); + void joinSelectedWorld(bool online); private: Ui::WorldListPage *ui; @@ -92,6 +93,8 @@ private slots: void on_actionView_Folder_triggered(); void on_actionDatapacks_triggered(); void on_actionReset_Icon_triggered(); + void on_actionJoin_triggered(); + void on_actionJoinOffline_triggered(); void worldChanged(const QModelIndex ¤t, const QModelIndex &previous); void mceditState(LoggedProcess::State state); diff --git a/launcher/ui/pages/instance/WorldListPage.ui b/launcher/ui/pages/instance/WorldListPage.ui index 7c68bfae..074f88fc 100644 --- a/launcher/ui/pages/instance/WorldListPage.ui +++ b/launcher/ui/pages/instance/WorldListPage.ui @@ -81,6 +81,9 @@ + + + @@ -97,6 +100,22 @@ Add + + + Join + + + Launch the instance directly into the selected world + + + + + Join offline + + + Launch the instance in offline mode directly into the selected world + + Rename diff --git a/libraries/launcher/org/multimc/onesix/OneSixLauncher.java b/libraries/launcher/org/multimc/onesix/OneSixLauncher.java index f57ad636..edf1c9b2 100644 --- a/libraries/launcher/org/multimc/onesix/OneSixLauncher.java +++ b/libraries/launcher/org/multimc/onesix/OneSixLauncher.java @@ -55,6 +55,8 @@ public class OneSixLauncher implements Launcher private String serverPort; private boolean useQuickPlay; + private String joinWorld; + // the much abused system classloader, for convenience (for further abuse) private ClassLoader cl; @@ -82,6 +84,7 @@ public class OneSixLauncher implements Launcher serverAddress = params.firstSafe("serverAddress", null); serverPort = params.firstSafe("serverPort", null); useQuickPlay = params.firstSafe("useQuickPlay").startsWith("1"); + joinWorld = params.firstSafe("joinWorld", null); cwd = System.getProperty("user.dir"); @@ -185,6 +188,12 @@ public class OneSixLauncher implements Launcher mcparams.add(Integer.toString(winSizeH)); } + if (joinWorld != null) + { + mcparams.add("--quickPlaySingleplayer"); + mcparams.add(joinWorld); + } + if (serverAddress != null) { if (useQuickPlay)