Merge pull request #2633 from Trial97/refactor_minecraft_update

refactor MinecraftUpdate Task
This commit is contained in:
TheKodeToad 2024-08-18 11:44:44 +01:00 committed by GitHub
commit e9791d6bc1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 13 additions and 144 deletions

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