diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:45:07 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:45:07 +0300 |
| commit | 31b9a8949ed0a288143e23bf739f2eb64fdc63be (patch) | |
| tree | 8a984fa143c38fccad461a77792d6864f3e82cd3 /meshmc/launcher/launch/LaunchTask.cpp | |
| parent | 934382c8a1ce738589dee9ee0f14e1cec812770e (diff) | |
| parent | fad6a1066616b69d7f5fef01178efdf014c59537 (diff) | |
| download | Project-Tick-31b9a8949ed0a288143e23bf739f2eb64fdc63be.tar.gz Project-Tick-31b9a8949ed0a288143e23bf739f2eb64fdc63be.zip | |
Add 'meshmc/' from commit 'fad6a1066616b69d7f5fef01178efdf014c59537'
git-subtree-dir: meshmc
git-subtree-mainline: 934382c8a1ce738589dee9ee0f14e1cec812770e
git-subtree-split: fad6a1066616b69d7f5fef01178efdf014c59537
Diffstat (limited to 'meshmc/launcher/launch/LaunchTask.cpp')
| -rw-r--r-- | meshmc/launcher/launch/LaunchTask.cpp | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/meshmc/launcher/launch/LaunchTask.cpp b/meshmc/launcher/launch/LaunchTask.cpp new file mode 100644 index 0000000000..86f2c11bf4 --- /dev/null +++ b/meshmc/launcher/launch/LaunchTask.cpp @@ -0,0 +1,278 @@ +/* SPDX-FileCopyrightText: 2026 Project Tick + * SPDX-FileContributor: Project Tick + * SPDX-License-Identifier: GPL-3.0-or-later + * + * MeshMC - A Custom Launcher for Minecraft + * Copyright (C) 2026 Project Tick + * + * 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, either version 3 of the License, or + * (at your option) any later version. + * + * 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 "launch/LaunchTask.h" +#include "MessageLevel.h" +#include "MMCStrings.h" +#include "java/JavaChecker.h" +#include "tasks/Task.h" +#include <QDebug> +#include <QDir> +#include <QEventLoop> +#include <QRegularExpression> +#include <QCoreApplication> +#include <QStandardPaths> +#include <assert.h> + +void LaunchTask::init() +{ + m_instance->setRunning(true); +} + +shared_qobject_ptr<LaunchTask> LaunchTask::create(InstancePtr inst) +{ + shared_qobject_ptr<LaunchTask> proc(new LaunchTask(inst)); + proc->init(); + return proc; +} + +LaunchTask::LaunchTask(InstancePtr instance) : m_instance(instance) {} + +void LaunchTask::appendStep(shared_qobject_ptr<LaunchStep> step) +{ + m_steps.append(step); +} + +void LaunchTask::prependStep(shared_qobject_ptr<LaunchStep> step) +{ + m_steps.prepend(step); +} + +void LaunchTask::executeTask() +{ + m_instance->setCrashed(false); + if (!m_steps.size()) { + state = LaunchTask::Finished; + emitSucceeded(); + } + state = LaunchTask::Running; + onStepFinished(); +} + +void LaunchTask::onReadyForLaunch() +{ + state = LaunchTask::Waiting; + emit readyForLaunch(); +} + +void LaunchTask::onStepFinished() +{ + // initial -> just start the first step + if (currentStep == -1) { + currentStep++; + m_steps[currentStep]->start(); + return; + } + + auto step = m_steps[currentStep]; + if (step->wasSuccessful()) { + // end? + if (currentStep == m_steps.size() - 1) { + finalizeSteps(true, QString()); + } else { + currentStep++; + step = m_steps[currentStep]; + step->start(); + } + } else { + finalizeSteps(false, step->failReason()); + } +} + +void LaunchTask::finalizeSteps(bool successful, const QString& error) +{ + for (auto step = currentStep; step >= 0; step--) { + m_steps[step]->finalize(); + } + if (successful) { + emitSucceeded(); + } else { + emitFailed(error); + } +} + +void LaunchTask::onProgressReportingRequested() +{ + state = LaunchTask::Waiting; + emit requestProgress(m_steps[currentStep].get()); +} + +void LaunchTask::setCensorFilter(QMap<QString, QString> filter) +{ + m_censorFilter = filter; +} + +QString LaunchTask::censorPrivateInfo(QString in) +{ + auto iter = m_censorFilter.begin(); + while (iter != m_censorFilter.end()) { + in.replace(iter.key(), iter.value()); + iter++; + } + return in; +} + +void LaunchTask::proceed() +{ + if (state != LaunchTask::Waiting) { + return; + } + m_steps[currentStep]->proceed(); +} + +bool LaunchTask::canAbort() const +{ + switch (state) { + case LaunchTask::Aborted: + case LaunchTask::Failed: + case LaunchTask::Finished: + return false; + case LaunchTask::NotStarted: + return true; + case LaunchTask::Running: + case LaunchTask::Waiting: { + auto step = m_steps[currentStep]; + return step->canAbort(); + } + } + return false; +} + +bool LaunchTask::abort() +{ + switch (state) { + case LaunchTask::Aborted: + case LaunchTask::Failed: + case LaunchTask::Finished: + return true; + case LaunchTask::NotStarted: { + state = LaunchTask::Aborted; + emitFailed("Aborted"); + return true; + } + case LaunchTask::Running: + case LaunchTask::Waiting: { + auto step = m_steps[currentStep]; + if (!step->canAbort()) { + return false; + } + if (step->abort()) { + state = LaunchTask::Aborted; + return true; + } + } + default: + break; + } + return false; +} + +shared_qobject_ptr<LogModel> LaunchTask::getLogModel() +{ + if (!m_logModel) { + m_logModel.reset(new LogModel()); + m_logModel->setMaxLines(m_instance->getConsoleMaxLines()); + m_logModel->setStopOnOverflow( + m_instance->shouldStopOnConsoleOverflow()); + // FIXME: should this really be here? + m_logModel->setOverflowMessage( + tr("MeshMC stopped watching the game log because the log length " + "surpassed %1 lines.\n" + "You may have to fix your mods because the game is still " + "logging to files and" + " likely wasting harddrive space at an alarming rate!") + .arg(m_logModel->getMaxLines())); + } + return m_logModel; +} + +void LaunchTask::onLogLines(const QStringList& lines, + MessageLevel::Enum defaultLevel) +{ + for (auto& line : lines) { + onLogLine(line, defaultLevel); + } +} + +void LaunchTask::onLogLine(QString line, MessageLevel::Enum level) +{ + // if MeshMC part set a log level, use it + auto innerLevel = MessageLevel::fromLine(line); + if (innerLevel != MessageLevel::Unknown) { + level = innerLevel; + } + + // If the level is still undetermined, guess level + if (level == MessageLevel::StdErr || level == MessageLevel::StdOut || + level == MessageLevel::Unknown) { + level = m_instance->guessLevel(line, level); + } + + // censor private user info + line = censorPrivateInfo(line); + + auto& model = *getLogModel(); + model.append(level, line); +} + +void LaunchTask::emitSucceeded() +{ + m_instance->setRunning(false); + Task::emitSucceeded(); +} + +void LaunchTask::emitFailed(QString reason) +{ + m_instance->setRunning(false); + m_instance->setCrashed(true); + Task::emitFailed(reason); +} + +QString LaunchTask::substituteVariables(const QString& cmd) const +{ + QString out = cmd; + auto variables = m_instance->getVariables(); + for (auto it = variables.begin(); it != variables.end(); ++it) { + out.replace("$" + it.key(), it.value()); + } + auto env = QProcessEnvironment::systemEnvironment(); + for (auto var : env.keys()) { + out.replace("$" + var, env.value(var)); + } + return out; +} |
