Merge branch 'develop' of https://github.com/PrismLauncher/PrismLauncher into metadata2

This commit is contained in:
Trial97
2024-08-23 08:34:15 +03:00
159 changed files with 4100 additions and 1473 deletions

View File

@ -283,8 +283,7 @@ Net::NetRequest::Ptr AssetObject::getDownloadAction()
if ((!objectFile.isFile()) || (objectFile.size() != size)) {
auto objectDL = Net::ApiDownload::makeFile(getUrl(), objectFile.filePath());
if (hash.size()) {
auto rawHash = QByteArray::fromHex(hash.toLatin1());
objectDL->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawHash));
objectDL->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, hash));
}
objectDL->setProgress(objectDL->getProgress(), size);
return objectDL;

View File

@ -56,18 +56,6 @@ Component::Component(PackProfile* parent, const QString& uid)
m_uid = uid;
}
Component::Component(PackProfile* parent, std::shared_ptr<Meta::Version> version)
{
assert(parent);
m_parent = parent;
m_metaVersion = version;
m_uid = version->uid();
m_version = m_cachedVersion = version->version();
m_cachedName = version->name();
m_loaded = version->isLoaded();
}
Component::Component(PackProfile* parent, const QString& uid, std::shared_ptr<VersionFile> file)
{
assert(parent);
@ -102,9 +90,6 @@ void Component::applyTo(LaunchProfile* profile)
std::shared_ptr<class VersionFile> Component::getVersionFile() const
{
if (m_metaVersion) {
if (!m_metaVersion->isLoaded()) {
m_metaVersion->load(Net::Mode::Online);
}
return m_metaVersion->data();
} else {
return m_file;
@ -131,29 +116,35 @@ int Component::getOrder()
}
return 0;
}
void Component::setOrder(int order)
{
m_orderOverride = true;
m_order = order;
}
QString Component::getID()
{
return m_uid;
}
QString Component::getName()
{
if (!m_cachedName.isEmpty())
return m_cachedName;
return m_uid;
}
QString Component::getVersion()
{
return m_cachedVersion;
}
QString Component::getFilename()
{
return m_parent->patchFilePathForUid(m_uid);
}
QDateTime Component::getReleaseDateTime()
{
if (m_metaVersion) {
@ -198,17 +189,14 @@ bool Component::isCustom()
bool Component::isCustomizable()
{
if (m_metaVersion) {
if (getVersionFile()) {
return true;
}
}
return false;
return m_metaVersion && getVersionFile();
}
bool Component::isRemovable()
{
return !m_important;
}
bool Component::isRevertible()
{
if (isCustom()) {
@ -218,18 +206,18 @@ bool Component::isRevertible()
}
return false;
}
bool Component::isMoveable()
{
// HACK, FIXME: this was too dumb and wouldn't follow dependency constraints anyway. For now hardcoded to 'true'.
return true;
}
bool Component::isVersionChangeable()
{
auto list = getVersionList();
if (list) {
if (!list->isLoaded()) {
list->load(Net::Mode::Online);
}
list->waitToLoad();
return list->count() != 0;
}
return false;

View File

@ -22,7 +22,6 @@ class Component : public QObject, public ProblemProvider {
Component(PackProfile* parent, const QString& uid);
// DEPRECATED: remove these constructors?
Component(PackProfile* parent, std::shared_ptr<Meta::Version> version);
Component(PackProfile* parent, const QString& uid, std::shared_ptr<VersionFile> file);
virtual ~Component() {}

View File

@ -13,6 +13,7 @@
#include "net/Mode.h"
#include "Application.h"
#include "tasks/Task.h"
/*
* This is responsible for loading the components of a component list AND resolving dependency issues between them
@ -93,9 +94,9 @@ static LoadResult loadComponent(ComponentPtr component, Task::Ptr& loadTask, Net
component->m_loaded = true;
result = LoadResult::LoadedLocal;
} else {
metaVersion->load(netmode);
loadTask = metaVersion->getCurrentTask();
if (loadTask)
loadTask = APPLICATION->metadataIndex()->loadVersion(component->m_uid, component->m_version, netmode);
loadTask->start();
if (netmode == Net::Mode::Online)
result = LoadResult::RequiresRemote;
else if (metaVersion->isLoaded())
result = LoadResult::LoadedLocal;
@ -133,21 +134,6 @@ static LoadResult loadPackProfile(ComponentPtr component, Task::Ptr& loadTask, N
}
*/
static LoadResult loadIndex(Task::Ptr& loadTask, Net::Mode netmode)
{
// FIXME: DECIDE. do we want to run the update task anyway?
if (APPLICATION->metadataIndex()->isLoaded()) {
qDebug() << "Index is already loaded";
return LoadResult::LoadedLocal;
}
APPLICATION->metadataIndex()->load(netmode);
loadTask = APPLICATION->metadataIndex()->getCurrentTask();
if (loadTask) {
return LoadResult::RequiresRemote;
}
// FIXME: this is assuming the load succeeded... did it really?
return LoadResult::LoadedLocal;
}
} // namespace
void ComponentUpdateTask::loadComponents()
@ -156,23 +142,7 @@ void ComponentUpdateTask::loadComponents()
size_t taskIndex = 0;
size_t componentIndex = 0;
d->remoteLoadSuccessful = true;
// load the main index (it is needed to determine if components can revert)
{
// FIXME: tear out as a method? or lambda?
Task::Ptr indexLoadTask;
auto singleResult = loadIndex(indexLoadTask, d->netmode);
result = composeLoadResult(result, singleResult);
if (indexLoadTask) {
qDebug() << "Remote loading is being run for metadata index";
RemoteLoadStatus status;
status.type = RemoteLoadStatus::Type::Index;
d->remoteLoadStatusList.append(status);
connect(indexLoadTask.get(), &Task::succeeded, [=]() { remoteLoadSucceeded(taskIndex); });
connect(indexLoadTask.get(), &Task::failed, [=](const QString& error) { remoteLoadFailed(taskIndex, error); });
connect(indexLoadTask.get(), &Task::aborted, [=]() { remoteLoadFailed(taskIndex, tr("Aborted")); });
taskIndex++;
}
}
// load all the components OR their lists...
for (auto component : d->m_list->d->components) {
Task::Ptr loadTask;
@ -206,12 +176,13 @@ void ComponentUpdateTask::loadComponents()
result = composeLoadResult(result, singleResult);
if (loadTask) {
qDebug() << "Remote loading is being run for" << component->getName();
connect(loadTask.get(), &Task::succeeded, [=]() { remoteLoadSucceeded(taskIndex); });
connect(loadTask.get(), &Task::failed, [=](const QString& error) { remoteLoadFailed(taskIndex, error); });
connect(loadTask.get(), &Task::aborted, [=]() { remoteLoadFailed(taskIndex, tr("Aborted")); });
connect(loadTask.get(), &Task::succeeded, this, [this, taskIndex]() { remoteLoadSucceeded(taskIndex); });
connect(loadTask.get(), &Task::failed, this, [this, taskIndex](const QString& error) { remoteLoadFailed(taskIndex, error); });
connect(loadTask.get(), &Task::aborted, this, [this, taskIndex]() { remoteLoadFailed(taskIndex, tr("Aborted")); });
RemoteLoadStatus status;
status.type = loadType;
status.PackProfileIndex = componentIndex;
status.task = loadTask;
d->remoteLoadStatusList.append(status);
taskIndex++;
}
@ -518,7 +489,14 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly)
void ComponentUpdateTask::remoteLoadSucceeded(size_t taskIndex)
{
if (static_cast<size_t>(d->remoteLoadStatusList.size()) < taskIndex) {
qWarning() << "Got task index outside of results" << taskIndex;
return;
}
auto& taskSlot = d->remoteLoadStatusList[taskIndex];
disconnect(taskSlot.task.get(), &Task::succeeded, this, nullptr);
disconnect(taskSlot.task.get(), &Task::failed, this, nullptr);
disconnect(taskSlot.task.get(), &Task::aborted, this, nullptr);
if (taskSlot.finished) {
qWarning() << "Got multiple results from remote load task" << taskIndex;
return;
@ -538,7 +516,14 @@ void ComponentUpdateTask::remoteLoadSucceeded(size_t taskIndex)
void ComponentUpdateTask::remoteLoadFailed(size_t taskIndex, const QString& msg)
{
if (static_cast<size_t>(d->remoteLoadStatusList.size()) < taskIndex) {
qWarning() << "Got task index outside of results" << taskIndex;
return;
}
auto& taskSlot = d->remoteLoadStatusList[taskIndex];
disconnect(taskSlot.task.get(), &Task::succeeded, this, nullptr);
disconnect(taskSlot.task.get(), &Task::failed, this, nullptr);
disconnect(taskSlot.task.get(), &Task::aborted, this, nullptr);
if (taskSlot.finished) {
qWarning() << "Got multiple results from remote load task" << taskIndex;
return;

View File

@ -4,6 +4,7 @@
#include <QString>
#include <cstddef>
#include "net/Mode.h"
#include "tasks/Task.h"
class PackProfile;
@ -13,6 +14,7 @@ struct RemoteLoadStatus {
bool finished = false;
bool succeeded = false;
QString error;
Task::Ptr task;
};
struct ComponentUpdateTaskData {

View File

@ -164,6 +164,11 @@ void LaunchProfile::applyCompatibleJavaMajors(QList<int>& javaMajor)
{
m_compatibleJavaMajors.append(javaMajor);
}
void LaunchProfile::applyCompatibleJavaName(QString javaName)
{
if (!javaName.isEmpty())
m_compatibleJavaName = javaName;
}
void LaunchProfile::applyLibrary(LibraryPtr library, const RuntimeContext& runtimeContext)
{
@ -334,6 +339,11 @@ const QList<int>& LaunchProfile::getCompatibleJavaMajors() const
return m_compatibleJavaMajors;
}
const QString LaunchProfile::getCompatibleJavaName() const
{
return m_compatibleJavaName;
}
void LaunchProfile::getLibraryFiles(const RuntimeContext& runtimeContext,
QStringList& jars,
QStringList& nativeJars,

View File

@ -59,6 +59,7 @@ class LaunchProfile : public ProblemProvider {
void applyMavenFile(LibraryPtr library, const RuntimeContext& runtimeContext);
void applyAgent(AgentPtr agent, const RuntimeContext& runtimeContext);
void applyCompatibleJavaMajors(QList<int>& javaMajor);
void applyCompatibleJavaName(QString javaName);
void applyMainJar(LibraryPtr jar);
void applyProblemSeverity(ProblemSeverity severity);
/// clear the profile
@ -80,6 +81,7 @@ class LaunchProfile : public ProblemProvider {
const QList<LibraryPtr>& getMavenFiles() const;
const QList<AgentPtr>& getAgents() const;
const QList<int>& getCompatibleJavaMajors() const;
const QString getCompatibleJavaName() const;
const LibraryPtr getMainJar() const;
void getLibraryFiles(const RuntimeContext& runtimeContext,
QStringList& jars,
@ -150,5 +152,7 @@ class LaunchProfile : public ProblemProvider {
/// compatible java major versions
QList<int> m_compatibleJavaMajors;
QString m_compatibleJavaName;
ProblemSeverity m_problemSeverity = ProblemSeverity::None;
};

View File

@ -147,9 +147,8 @@ QList<Net::NetRequest::Ptr> Library::getDownloads(const RuntimeContext& runtimeC
options |= Net::Download::Option::MakeEternal;
if (sha1.size()) {
auto rawSha1 = QByteArray::fromHex(sha1.toLatin1());
auto dl = Net::ApiDownload::makeCached(url, entry, options);
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1));
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, sha1));
qDebug() << "Checksummed Download for:" << rawName().serialize() << "storage:" << storage << "url:" << url;
out.append(dl);
} else {

View File

@ -38,6 +38,8 @@
#include "MinecraftInstance.h"
#include "Application.h"
#include "BuildConfig.h"
#include "QObjectPtr.h"
#include "minecraft/launch/AutoInstallJava.h"
#include "minecraft/launch/CreateGameFolders.h"
#include "minecraft/launch/ExtractNatives.h"
#include "minecraft/launch/PrintInstanceInfo.h"
@ -134,25 +136,21 @@ void MinecraftInstance::loadSpecificSettings()
return;
// Java Settings
auto javaOverride = m_settings->registerSetting("OverrideJava", false);
auto locationOverride = m_settings->registerSetting("OverrideJavaLocation", false);
auto argsOverride = m_settings->registerSetting("OverrideJavaArgs", false);
// combinations
auto javaOrLocation = std::make_shared<OrSetting>("JavaOrLocationOverride", javaOverride, locationOverride);
auto javaOrArgs = std::make_shared<OrSetting>("JavaOrArgsOverride", javaOverride, argsOverride);
m_settings->registerSetting("AutomaticJava", false);
if (auto global_settings = globalSettings()) {
m_settings->registerOverride(global_settings->getSetting("JavaPath"), javaOrLocation);
m_settings->registerOverride(global_settings->getSetting("JvmArgs"), javaOrArgs);
m_settings->registerOverride(global_settings->getSetting("IgnoreJavaCompatibility"), javaOrLocation);
m_settings->registerOverride(global_settings->getSetting("JavaPath"), locationOverride);
m_settings->registerOverride(global_settings->getSetting("JvmArgs"), argsOverride);
m_settings->registerOverride(global_settings->getSetting("IgnoreJavaCompatibility"), locationOverride);
// special!
m_settings->registerPassthrough(global_settings->getSetting("JavaSignature"), javaOrLocation);
m_settings->registerPassthrough(global_settings->getSetting("JavaArchitecture"), javaOrLocation);
m_settings->registerPassthrough(global_settings->getSetting("JavaRealArchitecture"), javaOrLocation);
m_settings->registerPassthrough(global_settings->getSetting("JavaVersion"), javaOrLocation);
m_settings->registerPassthrough(global_settings->getSetting("JavaVendor"), javaOrLocation);
m_settings->registerPassthrough(global_settings->getSetting("JavaSignature"), locationOverride);
m_settings->registerPassthrough(global_settings->getSetting("JavaArchitecture"), locationOverride);
m_settings->registerPassthrough(global_settings->getSetting("JavaRealArchitecture"), locationOverride);
m_settings->registerPassthrough(global_settings->getSetting("JavaVersion"), locationOverride);
m_settings->registerPassthrough(global_settings->getSetting("JavaVendor"), locationOverride);
// Window Size
auto windowSetting = m_settings->registerSetting("OverrideWindow", false);
@ -196,8 +194,9 @@ void MinecraftInstance::loadSpecificSettings()
}
// Join server on launch, this does not have a global override
m_settings->registerSetting("JoinServerOnLaunch", false);
m_settings->registerSetting({ "JoinServerOnLaunch", "JoinOnLaunch" }, false);
m_settings->registerSetting("JoinServerOnLaunchAddress", "");
m_settings->registerSetting("JoinWorldOnLaunch", "");
// Use account for instance, this does not have a global override
m_settings->registerSetting("UseAccountForInstance", false);
@ -523,8 +522,7 @@ QStringList MinecraftInstance::javaArguments()
if (javaVersion.isModular() && shouldApplyOnlineFixes())
// allow reflective access to java.net - required by the skin fix
args << "--add-opens"
<< "java.base/java.net=ALL-UNNAMED";
args << "--add-opens" << "java.base/java.net=ALL-UNNAMED";
return args;
}
@ -608,7 +606,7 @@ QProcessEnvironment MinecraftInstance::createLaunchEnvironment()
// dlsym variant is only needed for OpenGL and not included in the vulkan layer
appendLib("libMangoHud_dlsym.so");
appendLib("libMangoHud_opengl.so");
appendLib(mangoHudLib.fileName());
preloadList << mangoHudLibString;
}
env.insert("LD_PRELOAD", preloadList.join(QLatin1String(":")));
@ -656,7 +654,7 @@ static QString replaceTokensIn(QString text, QMap<QString, QString> with)
return result;
}
QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) const
QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin) const
{
auto profile = m_components->getProfile();
QString args_pattern = profile->getMinecraftArguments();
@ -664,12 +662,16 @@ QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session, Mine
args_pattern += " --tweakClass " + tweaker;
}
if (serverToJoin && !serverToJoin->address.isEmpty()) {
if (profile->hasTrait("feature:is_quick_play_multiplayer")) {
args_pattern += " --quickPlayMultiplayer " + serverToJoin->address + ':' + QString::number(serverToJoin->port);
} else {
args_pattern += " --server " + serverToJoin->address;
args_pattern += " --port " + QString::number(serverToJoin->port);
if (targetToJoin) {
if (!targetToJoin->address.isEmpty()) {
if (profile->hasTrait("feature:is_quick_play_multiplayer")) {
args_pattern += " --quickPlayMultiplayer " + targetToJoin->address + ':' + QString::number(targetToJoin->port);
} else {
args_pattern += " --server " + targetToJoin->address;
args_pattern += " --port " + QString::number(targetToJoin->port);
}
} else if (!targetToJoin->world.isEmpty() && profile->hasTrait("feature:is_quick_play_singleplayer")) {
args_pattern += " --quickPlaySingleplayer " + targetToJoin->world;
}
}
@ -713,7 +715,7 @@ QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session, Mine
return parts;
}
QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin)
{
QString launchScript;
@ -732,9 +734,13 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS
launchScript += "appletClass " + appletClass + "\n";
}
if (serverToJoin && !serverToJoin->address.isEmpty()) {
launchScript += "serverAddress " + serverToJoin->address + "\n";
launchScript += "serverPort " + QString::number(serverToJoin->port) + "\n";
if (targetToJoin) {
if (!targetToJoin->address.isEmpty()) {
launchScript += "serverAddress " + targetToJoin->address + "\n";
launchScript += "serverPort " + QString::number(targetToJoin->port) + "\n";
} else if (!targetToJoin->world.isEmpty()) {
launchScript += "worldName " + targetToJoin->world + "\n";
}
}
// generic minecraft params
@ -787,16 +793,15 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS
return launchScript;
}
QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin)
{
QStringList out;
out << "Main Class:"
<< " " + getMainClass() << "";
out << "Native path:"
<< " " + getNativePath() << "";
out << "Main Class:" << " " + getMainClass() << "";
out << "Native path:" << " " + getNativePath() << "";
auto profile = m_components->getProfile();
// traits
auto alltraits = traits();
if (alltraits.size()) {
out << "Traits:";
@ -806,6 +811,7 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr
out << "";
}
// native libraries
auto settings = this->settings();
bool nativeOpenAL = settings->get("UseNativeOpenAL").toBool();
bool nativeGLFW = settings->get("UseNativeGLFW").toBool();
@ -841,6 +847,7 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr
out << "";
}
// mods and core mods
auto printModList = [&](const QString& label, ModFolderModel& model) {
if (model.size()) {
out << QString("%1:").arg(label);
@ -869,6 +876,7 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr
printModList("Mods", *(loaderModList().get()));
printModList("Core Mods", *(coreModList().get()));
// jar mods
auto& jarMods = profile->getJarMods();
if (jarMods.size()) {
out << "Jar Mods:";
@ -884,11 +892,13 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr
out << "";
}
auto params = processMinecraftArgs(nullptr, serverToJoin);
// minecraft arguments
auto params = processMinecraftArgs(nullptr, targetToJoin);
out << "Params:";
out << " " + params.join(' ');
out << "";
// window size
QString windowParams;
if (settings->get("LaunchMaximized").toBool()) {
out << "Window size: max (if available)";
@ -1034,7 +1044,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, MinecraftTarget::Ptr targetToJoin)
{
updateRuntimeContext();
// FIXME: get rid of shared_from_this ...
@ -1048,26 +1058,28 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
process->appendStep(makeShared<TextPrint>(pptr, "Minecraft folder is:\n" + gameRoot() + "\n\n", MessageLevel::Launcher));
}
// check java
{
process->appendStep(makeShared<CheckJava>(pptr));
}
// create the .minecraft folder and server-resource-packs (workaround for Minecraft bug MCL-3732)
{
process->appendStep(makeShared<CreateGameFolders>(pptr));
}
if (!serverToJoin && settings()->get("JoinServerOnLaunch").toBool()) {
if (!targetToJoin && settings()->get("JoinOnLaunch").toBool()) {
QString fullAddress = settings()->get("JoinServerOnLaunchAddress").toString();
serverToJoin.reset(new MinecraftServerTarget(MinecraftServerTarget::parse(fullAddress)));
if (!fullAddress.isEmpty()) {
targetToJoin.reset(new MinecraftTarget(MinecraftTarget::parse(fullAddress, false)));
} else {
QString world = settings()->get("JoinWorldOnLaunch").toString();
if (!world.isEmpty()) {
targetToJoin.reset(new MinecraftTarget(MinecraftTarget::parse(world, true)));
}
}
}
if (serverToJoin && serverToJoin->port == 25565) {
if (targetToJoin && targetToJoin->port == 25565) {
// Resolve server address to join on launch
auto step = makeShared<LookupServerAddress>(pptr);
step->setLookupAddress(serverToJoin->address);
step->setOutputAddressPtr(serverToJoin);
step->setLookupAddress(targetToJoin->address);
step->setOutputAddressPtr(targetToJoin);
process->appendStep(step);
}
@ -1088,6 +1100,12 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
process->appendStep(makeShared<Update>(pptr, Net::Mode::Offline));
}
// check java
{
process->appendStep(makeShared<AutoInstallJava>(pptr));
process->appendStep(makeShared<CheckJava>(pptr));
}
// if there are any jar mods
{
process->appendStep(makeShared<ModMinecraftJar>(pptr));
@ -1100,7 +1118,7 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
// print some instance info here...
{
process->appendStep(makeShared<PrintInstanceInfo>(pptr, session, serverToJoin));
process->appendStep(makeShared<PrintInstanceInfo>(pptr, session, targetToJoin));
}
// extract native jars if needed
@ -1123,7 +1141,7 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
auto step = makeShared<LauncherPartLaunch>(pptr);
step->setWorkingDirectory(gameRoot());
step->setAuthSession(session);
step->setServerToJoin(serverToJoin);
step->setTargetToJoin(targetToJoin);
process->appendStep(step);
}

View File

@ -39,7 +39,7 @@
#include <QDir>
#include <QProcess>
#include "BaseInstance.h"
#include "minecraft/launch/MinecraftServerTarget.h"
#include "minecraft/launch/MinecraftTarget.h"
#include "minecraft/mod/Mod.h"
class ModFolderModel;
@ -56,7 +56,7 @@ class MinecraftInstance : public BaseInstance {
Q_OBJECT
public:
MinecraftInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir);
virtual ~MinecraftInstance() {};
virtual ~MinecraftInstance() = default;
virtual void saveNow() override;
void loadSpecificSettings() override;
@ -121,11 +121,11 @@ class MinecraftInstance : public BaseInstance {
////// 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, MinecraftTarget::Ptr targetToJoin) override;
QStringList extraArguments() override;
QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override;
QStringList verboseDescription(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin) override;
QList<Mod*> getJarMods() const;
QString createLaunchScript(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin);
QString createLaunchScript(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin);
/// get arguments passed to java
QStringList javaArguments();
QString getLauncher();
@ -155,7 +155,7 @@ class MinecraftInstance : public BaseInstance {
virtual QString getMainClass() const;
// FIXME: remove
virtual QStringList processMinecraftArgs(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) const;
virtual QStringList processMinecraftArgs(AuthSessionPtr account, MinecraftTarget::Ptr targetToJoin) const;
virtual JavaVersion getJavaVersion();

View File

@ -16,32 +16,22 @@
#include "MinecraftUpdate.h"
#include "MinecraftInstance.h"
#include <QDataStream>
#include <QFile>
#include <QFileInfo>
#include <QTextStream>
#include <FileSystem.h>
#include "BaseInstance.h"
#include "minecraft/Library.h"
#include "minecraft/PackProfile.h"
#include "tasks/SequentialTask.h"
#include "update/AssetUpdateTask.h"
#include "update/FMLLibrariesTask.h"
#include "update/FoldersTask.h"
#include "update/LibrariesTask.h"
#include <meta/Index.h>
#include <meta/Version.h>
MinecraftUpdate::MinecraftUpdate(MinecraftInstance* inst, QObject* parent) : Task(parent), m_inst(inst) {}
MinecraftUpdate::MinecraftUpdate(MinecraftInstance* inst, QObject* parent) : SequentialTask(parent), m_inst(inst) {}
void MinecraftUpdate::executeTask()
{
m_tasks.clear();
m_queue.clear();
// create folders
{
m_tasks.append(makeShared<FoldersTask>(m_inst));
addTask(makeShared<FoldersTask>(m_inst));
}
// add metadata update task if necessary
@ -50,121 +40,24 @@ void MinecraftUpdate::executeTask()
components->reload(Net::Mode::Online);
auto task = components->getCurrentTask();
if (task) {
m_tasks.append(task);
addTask(task);
}
}
// libraries download
{
m_tasks.append(makeShared<LibrariesTask>(m_inst));
addTask(makeShared<LibrariesTask>(m_inst));
}
// FML libraries download and copy into the instance
{
m_tasks.append(makeShared<FMLLibrariesTask>(m_inst));
addTask(makeShared<FMLLibrariesTask>(m_inst));
}
// assets update
{
m_tasks.append(makeShared<AssetUpdateTask>(m_inst));
addTask(makeShared<AssetUpdateTask>(m_inst));
}
if (!m_preFailure.isEmpty()) {
emitFailed(m_preFailure);
return;
}
next();
}
void MinecraftUpdate::next()
{
if (m_abort) {
emitFailed(tr("Aborted by user."));
return;
}
if (m_failed_out_of_order) {
emitFailed(m_fail_reason);
return;
}
m_currentTask++;
if (m_currentTask > 0) {
auto task = m_tasks[m_currentTask - 1];
disconnect(task.get(), &Task::succeeded, this, &MinecraftUpdate::subtaskSucceeded);
disconnect(task.get(), &Task::failed, this, &MinecraftUpdate::subtaskFailed);
disconnect(task.get(), &Task::aborted, this, &Task::abort);
disconnect(task.get(), &Task::progress, this, &MinecraftUpdate::progress);
disconnect(task.get(), &Task::stepProgress, this, &MinecraftUpdate::propagateStepProgress);
disconnect(task.get(), &Task::status, this, &MinecraftUpdate::setStatus);
disconnect(task.get(), &Task::details, this, &MinecraftUpdate::setDetails);
}
if (m_currentTask == m_tasks.size()) {
emitSucceeded();
return;
}
auto task = m_tasks[m_currentTask];
// if the task is already finished by the time we look at it, skip it
if (task->isFinished()) {
qCritical() << "MinecraftUpdate: Skipping finished subtask" << m_currentTask << ":" << task.get();
next();
}
connect(task.get(), &Task::succeeded, this, &MinecraftUpdate::subtaskSucceeded);
connect(task.get(), &Task::failed, this, &MinecraftUpdate::subtaskFailed);
connect(task.get(), &Task::aborted, this, &Task::abort);
connect(task.get(), &Task::progress, this, &MinecraftUpdate::progress);
connect(task.get(), &Task::stepProgress, this, &MinecraftUpdate::propagateStepProgress);
connect(task.get(), &Task::status, this, &MinecraftUpdate::setStatus);
connect(task.get(), &Task::details, this, &MinecraftUpdate::setDetails);
// if the task is already running, do not start it again
if (!task->isRunning()) {
task->start();
}
}
void MinecraftUpdate::subtaskSucceeded()
{
if (isFinished()) {
qCritical() << "MinecraftUpdate: Subtask" << sender() << "succeeded, but work was already done!";
return;
}
auto senderTask = QObject::sender();
auto currentTask = m_tasks[m_currentTask].get();
if (senderTask != currentTask) {
qDebug() << "MinecraftUpdate: Subtask" << sender() << "succeeded out of order.";
return;
}
next();
}
void MinecraftUpdate::subtaskFailed(QString error)
{
if (isFinished()) {
qCritical() << "MinecraftUpdate: Subtask" << sender() << "failed, but work was already done!";
return;
}
auto senderTask = QObject::sender();
auto currentTask = m_tasks[m_currentTask].get();
if (senderTask != currentTask) {
qDebug() << "MinecraftUpdate: Subtask" << sender() << "failed out of order.";
m_failed_out_of_order = true;
m_fail_reason = error;
return;
}
emitFailed(error);
}
bool MinecraftUpdate::abort()
{
if (!m_abort) {
m_abort = true;
auto task = m_tasks[m_currentTask];
if (task->canAbort()) {
return task->abort();
}
}
return true;
}
bool MinecraftUpdate::canAbort() const
{
return true;
SequentialTask::executeTask();
}

View File

@ -15,43 +15,19 @@
#pragma once
#include <QList>
#include <QObject>
#include <QUrl>
#include "tasks/SequentialTask.h"
#include <quazip/quazip.h>
#include "minecraft/VersionFilterData.h"
#include "net/NetJob.h"
#include "tasks/Task.h"
class MinecraftVersion;
class MinecraftInstance;
// FIXME: This looks very similar to a SequentialTask. Maybe we can reduce code duplications? :^)
class MinecraftUpdate : public Task {
// this needs to be a task because components->reload does stuff that may block
class MinecraftUpdate : public SequentialTask {
Q_OBJECT
public:
explicit MinecraftUpdate(MinecraftInstance* inst, QObject* parent = 0);
virtual ~MinecraftUpdate() {};
virtual ~MinecraftUpdate() = default;
void executeTask() override;
bool canAbort() const override;
private slots:
bool abort() override;
void subtaskSucceeded();
void subtaskFailed(QString error);
private:
void next();
private:
MinecraftInstance* m_inst = nullptr;
QList<Task::Ptr> m_tasks;
QString m_preFailure;
int m_currentTask = -1;
bool m_abort = false;
bool m_failed_out_of_order = false;
QString m_fail_reason;
};

View File

@ -185,6 +185,9 @@ void MojangVersionFormat::readVersionProperties(const QJsonObject& in, VersionFi
out->compatibleJavaMajors.append(requireInteger(compatible));
}
}
if (in.contains("compatibleJavaName")) {
out->compatibleJavaName = requireString(in.value("compatibleJavaName"));
}
if (in.contains("downloads")) {
auto downloadsObj = requireObject(in, "downloads");
@ -259,6 +262,9 @@ void MojangVersionFormat::writeVersionProperties(const VersionFile* in, QJsonObj
}
out.insert("compatibleJavaMajors", compatibleJavaMajorsOut);
}
if (!in->compatibleJavaName.isEmpty()) {
writeString(out, "compatibleJavaName", in->compatibleJavaName);
}
}
QJsonDocument MojangVersionFormat::versionFileToJson(const VersionFilePtr& patch)

View File

@ -36,6 +36,8 @@
#include "OneSixVersionFormat.h"
#include <Json.h>
#include <minecraft/MojangVersionFormat.h>
#include <QList>
#include "java/JavaMetadata.h"
#include "minecraft/Agent.h"
#include "minecraft/ParseUtils.h"
@ -255,6 +257,13 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument& doc
out->m_volatile = requireBoolean(root, "volatile");
}
if (root.contains("runtimes")) {
out->runtimes = {};
for (auto runtime : ensureArray(root, "runtimes")) {
out->runtimes.append(Java::parseJavaMeta(ensureObject(runtime)));
}
}
/* removed features that shouldn't be used */
if (root.contains("tweakers")) {
out->addProblem(ProblemSeverity::Error, QObject::tr("Version file contains unsupported element 'tweakers'"));

View File

@ -73,6 +73,7 @@ void VersionFile::applyTo(LaunchProfile* profile, const RuntimeContext& runtimeC
profile->applyMods(mods);
profile->applyTraits(traits);
profile->applyCompatibleJavaMajors(compatibleJavaMajors);
profile->applyCompatibleJavaName(compatibleJavaName);
for (auto library : libraries) {
profile->applyLibrary(library, runtimeContext);

View File

@ -36,6 +36,8 @@
#pragma once
#include <QDateTime>
#include <QHash>
#include <QList>
#include <QSet>
#include <QString>
#include <QStringList>
@ -45,6 +47,7 @@
#include "Agent.h"
#include "Library.h"
#include "ProblemProvider.h"
#include "java/JavaMetadata.h"
#include "minecraft/Rule.h"
class PackProfile;
@ -98,6 +101,9 @@ class VersionFile : public ProblemContainer {
/// Mojang: list of compatible java majors
QList<int> compatibleJavaMajors;
/// Mojang: the name of recommended java version
QString compatibleJavaName;
/// Mojang: type of the Minecraft version
QString type;
@ -149,6 +155,8 @@ class VersionFile : public ProblemContainer {
/// is volatile -- may be removed as soon as it is no longer needed by something else
bool m_volatile = false;
QList<Java::MetadataPtr> runtimes;
public:
// Mojang: DEPRECATED list of 'downloads' - client jar, server jar, windows server exe, maybe more.
QMap<QString, std::shared_ptr<MojangDownloadInfo>> mojangDownloads;

View File

@ -74,6 +74,8 @@ void MSADeviceCodeStep::perform()
m_task->setAskRetry(false);
m_task->addNetAction(m_request);
connect(m_task.get(), &Task::finished, this, &MSADeviceCodeStep::deviceAutorizationFinished);
m_task->start();
}

View File

@ -0,0 +1,242 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "AutoInstallJava.h"
#include <QDir>
#include <QFileInfo>
#include <memory>
#include "Application.h"
#include "FileSystem.h"
#include "MessageLevel.h"
#include "SysInfo.h"
#include "java/JavaInstall.h"
#include "java/JavaInstallList.h"
#include "java/JavaUtils.h"
#include "java/JavaVersion.h"
#include "java/download/ArchiveDownloadTask.h"
#include "java/download/ManifestDownloadTask.h"
#include "meta/Index.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
#include "net/Mode.h"
AutoInstallJava::AutoInstallJava(LaunchTask* parent)
: LaunchStep(parent)
, m_instance(std::dynamic_pointer_cast<MinecraftInstance>(m_parent->instance()))
, m_supported_arch(SysInfo::getSupportedJavaArchitecture()) {};
void AutoInstallJava::executeTask()
{
auto settings = m_instance->settings();
if (!APPLICATION->settings()->get("AutomaticJavaSwitch").toBool() ||
(settings->get("OverrideJavaLocation").toBool() && QFileInfo::exists(settings->get("JavaPath").toString()))) {
emitSucceeded();
return;
}
auto packProfile = m_instance->getPackProfile();
if (!APPLICATION->settings()->get("AutomaticJavaDownload").toBool()) {
auto javas = APPLICATION->javalist();
m_current_task = javas->getLoadTask();
connect(m_current_task.get(), &Task::finished, this, [this, javas, packProfile] {
for (auto i = 0; i < javas->count(); i++) {
auto java = std::dynamic_pointer_cast<JavaInstall>(javas->at(i));
if (java && packProfile->getProfile()->getCompatibleJavaMajors().contains(java->id.major())) {
if (!java->is_64bit) {
emit logLine(tr("The automatic Java mechanism detected a 32-bit installation of Java."), MessageLevel::Info);
}
setJavaPath(java->path);
return;
}
}
emit logLine(tr("No compatible Java version was found. Using the default one."), MessageLevel::Warning);
emitSucceeded();
});
connect(m_current_task.get(), &Task::progress, this, &AutoInstallJava::setProgress);
connect(m_current_task.get(), &Task::stepProgress, this, &AutoInstallJava::propagateStepProgress);
connect(m_current_task.get(), &Task::status, this, &AutoInstallJava::setStatus);
connect(m_current_task.get(), &Task::details, this, &AutoInstallJava::setDetails);
emit progressReportingRequest();
return;
}
if (m_supported_arch.isEmpty()) {
emit logLine(tr("Your system (%1-%2) is not compatible with automatic Java installation. Using the default Java path.")
.arg(SysInfo::currentSystem(), SysInfo::useQTForArch()),
MessageLevel::Warning);
emitSucceeded();
return;
}
auto wantedJavaName = packProfile->getProfile()->getCompatibleJavaName();
if (wantedJavaName.isEmpty()) {
emit logLine(tr("Your meta information is out of date or doesn't have the information necessary to determine what installation of "
"Java should be used. "
"Using the default Java path."),
MessageLevel::Warning);
emitSucceeded();
return;
}
QDir javaDir(APPLICATION->javaPath());
auto wantedJavaPath = javaDir.absoluteFilePath(wantedJavaName);
if (QFileInfo::exists(wantedJavaPath)) {
setJavaPathFromPartial();
return;
}
auto versionList = APPLICATION->metadataIndex()->get("net.minecraft.java");
m_current_task = versionList->getLoadTask();
connect(m_current_task.get(), &Task::succeeded, this, &AutoInstallJava::tryNextMajorJava);
connect(m_current_task.get(), &Task::failed, this, &AutoInstallJava::emitFailed);
connect(m_current_task.get(), &Task::progress, this, &AutoInstallJava::setProgress);
connect(m_current_task.get(), &Task::stepProgress, this, &AutoInstallJava::propagateStepProgress);
connect(m_current_task.get(), &Task::status, this, &AutoInstallJava::setStatus);
connect(m_current_task.get(), &Task::details, this, &AutoInstallJava::setDetails);
if (!m_current_task->isRunning()) {
m_current_task->start();
}
emit progressReportingRequest();
}
void AutoInstallJava::setJavaPath(QString path)
{
auto settings = m_instance->settings();
settings->set("OverrideJavaLocation", true);
settings->set("JavaPath", path);
settings->set("AutomaticJava", true);
emit logLine(tr("Compatible Java found at: %1.").arg(path), MessageLevel::Info);
emitSucceeded();
}
void AutoInstallJava::setJavaPathFromPartial()
{
auto packProfile = m_instance->getPackProfile();
auto javaName = packProfile->getProfile()->getCompatibleJavaName();
QDir javaDir(APPLICATION->javaPath());
// just checking if the executable is there should suffice
// but if needed this can be achieved through refreshing the javalist
// and retrieving the path that contains the java name
auto relativeBinary = FS::PathCombine(javaName, "bin", JavaUtils::javaExecutable);
auto finalPath = javaDir.absoluteFilePath(relativeBinary);
if (QFileInfo::exists(finalPath)) {
setJavaPath(finalPath);
} else {
emit logLine(tr("No compatible Java version was found (the binary file does not exist). Using the default one."),
MessageLevel::Warning);
emitSucceeded();
}
return;
}
void AutoInstallJava::downloadJava(Meta::Version::Ptr version, QString javaName)
{
auto runtimes = version->data()->runtimes;
for (auto java : runtimes) {
if (java->runtimeOS == m_supported_arch && java->name() == javaName) {
QDir javaDir(APPLICATION->javaPath());
auto final_path = javaDir.absoluteFilePath(java->m_name);
switch (java->downloadType) {
case Java::DownloadType::Manifest:
m_current_task = makeShared<Java::ManifestDownloadTask>(java->url, final_path, java->checksumType, java->checksumHash);
break;
case Java::DownloadType::Archive:
m_current_task = makeShared<Java::ArchiveDownloadTask>(java->url, final_path, java->checksumType, java->checksumHash);
break;
case Java::DownloadType::Unknown:
emitFailed(tr("Could not determine Java download type!"));
return;
}
auto deletePath = [final_path] { FS::deletePath(final_path); };
connect(m_current_task.get(), &Task::failed, this, [this, deletePath](QString reason) {
deletePath();
emitFailed(reason);
});
connect(this, &Task::aborted, this, [this, deletePath] {
m_current_task->abort();
deletePath();
});
connect(m_current_task.get(), &Task::succeeded, this, &AutoInstallJava::setJavaPathFromPartial);
connect(m_current_task.get(), &Task::failed, this, &AutoInstallJava::tryNextMajorJava);
connect(m_current_task.get(), &Task::progress, this, &AutoInstallJava::setProgress);
connect(m_current_task.get(), &Task::stepProgress, this, &AutoInstallJava::propagateStepProgress);
connect(m_current_task.get(), &Task::status, this, &AutoInstallJava::setStatus);
connect(m_current_task.get(), &Task::details, this, &AutoInstallJava::setDetails);
m_current_task->start();
return;
}
}
tryNextMajorJava();
}
void AutoInstallJava::tryNextMajorJava()
{
if (!isRunning())
return;
auto versionList = APPLICATION->metadataIndex()->get("net.minecraft.java");
auto packProfile = m_instance->getPackProfile();
auto wantedJavaName = packProfile->getProfile()->getCompatibleJavaName();
auto majorJavaVersions = packProfile->getProfile()->getCompatibleJavaMajors();
if (m_majorJavaVersionIndex >= majorJavaVersions.length()) {
emit logLine(
tr("No versions of Java were found for your operating system: %1-%2").arg(SysInfo::currentSystem(), SysInfo::useQTForArch()),
MessageLevel::Warning);
emit logLine(tr("No compatible version of Java was found. Using the default one."), MessageLevel::Warning);
emitSucceeded();
return;
}
auto majorJavaVersion = majorJavaVersions[m_majorJavaVersionIndex];
m_majorJavaVersionIndex++;
auto javaMajor = versionList->getVersion(QString("java%1").arg(majorJavaVersion));
if (javaMajor->isLoaded()) {
downloadJava(javaMajor, wantedJavaName);
} else {
m_current_task = APPLICATION->metadataIndex()->loadVersion("net.minecraft.java", javaMajor->version(), Net::Mode::Online);
connect(m_current_task.get(), &Task::succeeded, this,
[this, javaMajor, wantedJavaName] { downloadJava(javaMajor, wantedJavaName); });
connect(m_current_task.get(), &Task::failed, this, &AutoInstallJava::tryNextMajorJava);
connect(m_current_task.get(), &Task::progress, this, &AutoInstallJava::setProgress);
connect(m_current_task.get(), &Task::stepProgress, this, &AutoInstallJava::propagateStepProgress);
connect(m_current_task.get(), &Task::status, this, &AutoInstallJava::setStatus);
connect(m_current_task.get(), &Task::details, this, &AutoInstallJava::setDetails);
if (!m_current_task->isRunning()) {
m_current_task->start();
}
}
}
bool AutoInstallJava::abort()
{
if (m_current_task && m_current_task->canAbort())
return m_current_task->abort();
return true;
}

View File

@ -0,0 +1,68 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <launch/LaunchStep.h>
#include <launch/LaunchTask.h>
#include "java/JavaMetadata.h"
#include "meta/Version.h"
#include "minecraft/MinecraftInstance.h"
#include "tasks/Task.h"
class AutoInstallJava : public LaunchStep {
Q_OBJECT
public:
explicit AutoInstallJava(LaunchTask* parent);
~AutoInstallJava() override = default;
void executeTask() override;
bool canAbort() const override { return m_current_task ? m_current_task->canAbort() : false; }
bool abort() override;
protected:
void setJavaPath(QString path);
void setJavaPathFromPartial();
void downloadJava(Meta::Version::Ptr version, QString javaName);
void tryNextMajorJava();
private:
MinecraftInstancePtr m_instance;
Task::Ptr m_current_task;
qsizetype m_majorJavaVersionIndex = 0;
const QString m_supported_arch;
};

View File

@ -90,7 +90,7 @@ void LauncherPartLaunch::executeTask()
}
}
m_launchScript = minecraftInstance->createLaunchScript(m_session, m_serverToJoin);
m_launchScript = minecraftInstance->createLaunchScript(m_session, m_targetToJoin);
QStringList args = minecraftInstance->javaArguments();
QString allArgs = args.join(", ");
emit logLine("Java Arguments:\n[" + m_parent->censorPrivateInfo(allArgs) + "]\n\n", MessageLevel::Launcher);

View File

@ -19,13 +19,13 @@
#include <launch/LaunchStep.h>
#include <minecraft/auth/AuthSession.h>
#include "MinecraftServerTarget.h"
#include "MinecraftTarget.h"
class LauncherPartLaunch : public LaunchStep {
Q_OBJECT
public:
explicit LauncherPartLaunch(LaunchTask* parent);
virtual ~LauncherPartLaunch() {};
virtual ~LauncherPartLaunch() = default;
virtual void executeTask();
virtual bool abort();
@ -34,7 +34,7 @@ class LauncherPartLaunch : public LaunchStep {
void setWorkingDirectory(const QString& wd);
void setAuthSession(AuthSessionPtr session) { m_session = session; }
void setServerToJoin(MinecraftServerTargetPtr serverToJoin) { m_serverToJoin = std::move(serverToJoin); }
void setTargetToJoin(MinecraftTarget::Ptr targetToJoin) { m_targetToJoin = std::move(targetToJoin); }
private slots:
void on_state(LoggedProcess::State state);
@ -44,7 +44,7 @@ class LauncherPartLaunch : public LaunchStep {
QString m_command;
AuthSessionPtr m_session;
QString m_launchScript;
MinecraftServerTargetPtr m_serverToJoin;
MinecraftTarget::Ptr m_targetToJoin;
bool mayProceed = false;
};

View File

@ -13,13 +13,18 @@
* limitations under the License.
*/
#include "MinecraftServerTarget.h"
#include "MinecraftTarget.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)
MinecraftTarget MinecraftTarget::parse(const QString& fullAddress, bool useWorld)
{
if (useWorld) {
MinecraftTarget target;
target.world = fullAddress;
return target;
}
QStringList split = fullAddress.split(":");
// The logic below replicates the exact logic minecraft uses for parsing server addresses.
@ -56,5 +61,5 @@ MinecraftServerTarget MinecraftServerTarget::parse(const QString& fullAddress)
}
}
return MinecraftServerTarget{ realAddress, realPort };
return MinecraftTarget{ realAddress, realPort };
}

View File

@ -19,11 +19,11 @@
#include <QString>
struct MinecraftServerTarget {
struct MinecraftTarget {
QString address;
quint16 port;
static MinecraftServerTarget parse(const QString& fullAddress);
QString world;
static MinecraftTarget parse(const QString& fullAddress, bool useWorld);
using Ptr = std::shared_ptr<MinecraftTarget>;
};
using MinecraftServerTargetPtr = std::shared_ptr<MinecraftServerTarget>;

View File

@ -129,6 +129,6 @@ void PrintInstanceInfo::executeTask()
#endif
logLines(log, MessageLevel::Launcher);
logLines(instance->verboseDescription(m_session, m_serverToJoin), MessageLevel::Launcher);
logLines(instance->verboseDescription(m_session, m_targetToJoin), MessageLevel::Launcher);
emitSucceeded();
}

View File

@ -16,22 +16,21 @@
#pragma once
#include <launch/LaunchStep.h>
#include <memory>
#include "minecraft/auth/AuthSession.h"
#include "minecraft/launch/MinecraftServerTarget.h"
#include "minecraft/launch/MinecraftTarget.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) {};
virtual ~PrintInstanceInfo() {};
explicit PrintInstanceInfo(LaunchTask* parent, AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin)
: LaunchStep(parent), m_session(session), m_targetToJoin(targetToJoin) {};
virtual ~PrintInstanceInfo() = default;
virtual void executeTask();
virtual bool canAbort() const { return false; }
private:
AuthSessionPtr m_session;
MinecraftServerTargetPtr m_serverToJoin;
MinecraftTarget::Ptr m_targetToJoin;
};

View File

@ -34,7 +34,12 @@
*/
#include "VerifyJavaInstall.h"
#include <memory>
#include "Application.h"
#include "MessageLevel.h"
#include "java/JavaInstall.h"
#include "java/JavaInstallList.h"
#include "java/JavaVersion.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
@ -46,6 +51,15 @@ void VerifyJavaInstall::executeTask()
auto settings = instance->settings();
auto storedVersion = settings->get("JavaVersion").toString();
auto ignoreCompatibility = settings->get("IgnoreJavaCompatibility").toBool();
auto javaArchitecture = settings->get("JavaArchitecture").toString();
auto maxMemAlloc = settings->get("MaxMemAlloc").toInt();
if (javaArchitecture == "32" && maxMemAlloc > 2048) {
emit logLine(tr("Max memory allocation exceeds the supported value.\n"
"The selected installation of Java is 32-bit and doesn't support more than 2048MiB of RAM.\n"
"The instance may not start due to this."),
MessageLevel::Error);
}
auto compatibleMajors = packProfile->getProfile()->getCompatibleJavaMajors();

View File

@ -32,8 +32,7 @@ void AssetUpdateTask::executeTask()
auto hexSha1 = assets->sha1.toLatin1();
qDebug() << "Asset index SHA1:" << hexSha1;
auto dl = Net::ApiDownload::makeCached(indexUrl, entry);
auto rawSha1 = QByteArray::fromHex(assets->sha1.toLatin1());
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1));
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, assets->sha1));
job->addNetAction(dl);
downloadJob.reset(job);