NOISSUE Add support for launching worlds directly via Quick Play

This commit is contained in:
arthomnix 2023-04-08 18:03:20 +01:00
parent 22f82c34bf
commit 71cf4f8d18
30 changed files with 306 additions and 103 deletions

View File

@ -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>(MinecraftServerTarget::parse(server));
serverObject = std::make_shared<QuickPlayTarget>(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)

View File

@ -11,7 +11,7 @@
#include <BaseInstance.h>
#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;

View File

@ -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<LaunchTask> createLaunchTask(
AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) = 0;
AuthSessionPtr account, QuickPlayTargetPtr quickPlayTarget) = 0;
/// returns the current launch task (if any)
shared_qobject_ptr<LaunchTask> 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;

View File

@ -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

View File

@ -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();

View File

@ -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."));

View File

@ -3,7 +3,7 @@
#include <BaseInstance.h>
#include <tools/BaseProfiler.h>
#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<LaunchTask> m_launcher;
MinecraftServerTargetPtr m_serverToJoin;
QuickPlayTargetPtr m_quickPlayTarget;
};

View File

@ -27,7 +27,7 @@ public:
{
return instanceRoot();
};
shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr, MinecraftServerTargetPtr) override
shared_qobject_ptr<LaunchTask> 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.";

View File

@ -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);
}

View File

@ -19,7 +19,7 @@
#include <QObjectPtr.h>
#include <QDnsLookup>
#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;
};

View File

@ -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<QString, QString> 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<QString, QString> 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<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr session, QuickPlayTargetPtr quickPlayTarget)
{
// FIXME: get rid of shared_from_this ...
auto process = LaunchTask::create(std::dynamic_pointer_cast<MinecraftInstance>(shared_from_this()));
@ -866,18 +879,26 @@ shared_qobject_ptr<LaunchTask> 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<LaunchTask> 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<LaunchTask> 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<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
auto step = new DirectJavaLaunch(pptr);
step->setWorkingDirectory(gameRoot());
step->setAuthSession(session);
step->setServerToJoin(serverToJoin);
step->setQuickPlayTarget(quickPlayTarget);
process->appendStep(step);
}
}

View File

@ -4,7 +4,7 @@
#include "minecraft/mod/Mod.h"
#include <QProcess>
#include <QDir>
#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<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) override;
shared_qobject_ptr<LaunchTask> 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<Mod> 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;

View File

@ -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();

View File

@ -19,7 +19,7 @@
#include <LoggedProcess.h>
#include <minecraft/auth/AuthSession.h>
#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;
};

View File

@ -60,7 +60,7 @@ void LauncherPartLaunch::executeTask()
auto instance = m_parent->instance();
std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(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);

View File

@ -19,7 +19,7 @@
#include <LoggedProcess.h>
#include <minecraft/auth/AuthSession.h>
#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;
};

View File

@ -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();
}

View File

@ -18,15 +18,15 @@
#include <launch/LaunchStep.h>
#include <memory>
#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;
};

View File

@ -13,12 +13,12 @@
* limitations under the License.
*/
#include "MinecraftServerTarget.h"
#include "QuickPlayTarget.h"
#include <QStringList>
// 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;
}

View File

@ -19,11 +19,16 @@
#include <QString>
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<MinecraftServerTarget> MinecraftServerTargetPtr;
typedef std::shared_ptr<QuickPlayTarget> QuickPlayTargetPtr;

View File

@ -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;

View File

@ -112,7 +112,7 @@ public:
return false;
}
shared_qobject_ptr<LaunchTask> 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
{

View File

@ -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<MinecraftInstance *>(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();

View File

@ -22,6 +22,7 @@
#include <QObjectPtr.h>
#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();

View File

@ -39,7 +39,7 @@
<enum>QTabWidget::Rounded</enum>
</property>
<property name="currentIndex">
<number>0</number>
<number>4</number>
</property>
<widget class="QWidget" name="minecraftTab">
<attribute name="title">
@ -454,9 +454,9 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="serverJoinGroupBox">
<widget class="QGroupBox" name="quickPlayGroupBox">
<property name="title">
<string>Set a server to join on launch</string>
<string>Set a world to join on launch</string>
</property>
<property name="checkable">
<bool>true</bool>
@ -466,15 +466,9 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_11">
<item>
<layout class="QGridLayout" name="serverJoinLayout">
<layout class="QGridLayout" name="quickPlayLayout">
<item row="0" column="0">
<widget class="QLabel" name="serverJoinAddressLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<widget class="QRadioButton" name="serverAddressRadioButton">
<property name="text">
<string>Server address:</string>
</property>
@ -483,6 +477,16 @@
<item row="0" column="1">
<widget class="QLineEdit" name="serverJoinAddress"/>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="worldRadioButton">
<property name="text">
<string>Singleplayer world:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="worldsComboBox"/>
</item>
</layout>
</item>
</layout>

View File

@ -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>(MinecraftServerTarget::parse(address)));
APPLICATION->launch(m_inst, true, nullptr, std::make_shared<QuickPlayTarget>(
QuickPlayTarget::parseMultiplayer(address)));
}
#include "ServersPage.moc"

View File

@ -24,7 +24,6 @@
#include <QMessageBox>
#include <QTreeView>
#include <QInputDialog>
#include <QProcess>
#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<WorldList> worlds, QWidget *parent)
WorldListPage::WorldListPage(InstancePtr inst, std::shared_ptr<WorldList> 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 &current, const QModelIndex &previous)
{
auto mcInst = std::dynamic_pointer_cast<MinecraftInstance>(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<void *>();
auto name = world->folderName();
APPLICATION->launch(m_inst, online, nullptr, std::make_shared<QuickPlayTarget>(QuickPlayTarget::parseSingleplayer(name)));
}
void WorldListPage::on_actionJoin_triggered()
{
joinSelectedWorld(true);
}
void WorldListPage::on_actionJoinOffline_triggered()
{
joinSelectedWorld(false);
}
#include "WorldListPage.moc"

View File

@ -34,7 +34,7 @@ class WorldListPage : public QMainWindow, public BasePage
public:
explicit WorldListPage(
BaseInstance *inst,
InstancePtr inst,
std::shared_ptr<WorldList> 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 &current, const QModelIndex &previous);
void mceditState(LoggedProcess::State state);

View File

@ -81,6 +81,9 @@
</attribute>
<addaction name="actionAdd"/>
<addaction name="separator"/>
<addaction name="actionJoin" />
<addaction name="actionJoinOffline" />
<addaction name="separator" />
<addaction name="actionRename"/>
<addaction name="actionCopy"/>
<addaction name="actionRemove"/>
@ -97,6 +100,22 @@
<string>Add</string>
</property>
</action>
<action name="actionJoin">
<property name="text">
<string>Join</string>
</property>
<property name="toolTip">
<string>Launch the instance directly into the selected world</string>
</property>
</action>
<action name="actionJoinOffline">
<property name="text">
<string>Join offline</string>
</property>
<property name="toolTip">
<string>Launch the instance in offline mode directly into the selected world</string>
</property>
</action>
<action name="actionRename">
<property name="text">
<string>Rename</string>

View File

@ -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)