mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 15:29:55 +00:00
Support navmesh generation from launcher
This commit is contained in:
parent
c9b8ba7b46
commit
9e0451c714
5 changed files with 179 additions and 7 deletions
|
@ -1,4 +1,5 @@
|
|||
#include "datafilespage.hpp"
|
||||
#include "maindialog.hpp"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
@ -8,6 +9,7 @@
|
|||
#include <QSortFilterProxyModel>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <algorithm>
|
||||
|
||||
#include <apps/launcher/utils/cellnameloader.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
@ -24,11 +26,14 @@
|
|||
|
||||
const char *Launcher::DataFilesPage::mDefaultContentListName = "Default";
|
||||
|
||||
Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings, Config::LauncherSettings &launcherSettings, QWidget *parent)
|
||||
Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings,
|
||||
Config::LauncherSettings &launcherSettings, MainDialog *parent)
|
||||
: QWidget(parent)
|
||||
, mMainDialog(parent)
|
||||
, mCfgMgr(cfg)
|
||||
, mGameSettings(gameSettings)
|
||||
, mLauncherSettings(launcherSettings)
|
||||
, mNavMeshToolInvoker(new Process::ProcessInvoker(this))
|
||||
{
|
||||
ui.setupUi (this);
|
||||
setObjectName ("DataFilesPage");
|
||||
|
@ -57,8 +62,6 @@ Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config:
|
|||
|
||||
void Launcher::DataFilesPage::buildView()
|
||||
{
|
||||
ui.verticalLayout->insertWidget (0, mSelector->uiWidget());
|
||||
|
||||
QToolButton * refreshButton = mSelector->refreshButton();
|
||||
|
||||
//tool buttons
|
||||
|
@ -89,6 +92,13 @@ void Launcher::DataFilesPage::buildView()
|
|||
this, SLOT (slotProfileChangedByUser(QString, QString)));
|
||||
|
||||
connect(ui.refreshDataFilesAction, SIGNAL(triggered()),this, SLOT(slotRefreshButtonClicked()));
|
||||
|
||||
connect(ui.updateNavMeshButton, SIGNAL(clicked()), this, SLOT(startNavMeshTool()));
|
||||
connect(ui.cancelNavMeshButton, SIGNAL(clicked()), this, SLOT(killNavMeshTool()));
|
||||
|
||||
connect(mNavMeshToolInvoker->getProcess(), SIGNAL(readyReadStandardOutput()), this, SLOT(updateNavMeshProgress()));
|
||||
connect(mNavMeshToolInvoker->getProcess(), SIGNAL(readyReadStandardError()), this, SLOT(updateNavMeshProgress()));
|
||||
connect(mNavMeshToolInvoker->getProcess(), SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(navMeshToolFinished(int, QProcess::ExitStatus)));
|
||||
}
|
||||
|
||||
bool Launcher::DataFilesPage::loadSettings()
|
||||
|
@ -411,3 +421,55 @@ void Launcher::DataFilesPage::reloadCells(QStringList selectedFiles)
|
|||
std::sort(cellNamesList.begin(), cellNamesList.end());
|
||||
emit signalLoadedCellsChanged(cellNamesList);
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::startNavMeshTool()
|
||||
{
|
||||
mMainDialog->writeSettings();
|
||||
|
||||
ui.navMeshLogPlainTextEdit->clear();
|
||||
ui.navMeshProgressBar->setValue(0);
|
||||
ui.navMeshProgressBar->setMaximum(1);
|
||||
|
||||
if (!mNavMeshToolInvoker->startProcess(QLatin1String("openmw-navmeshtool")))
|
||||
return;
|
||||
|
||||
ui.cancelNavMeshButton->setEnabled(true);
|
||||
ui.navMeshProgressBar->setEnabled(true);
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::killNavMeshTool()
|
||||
{
|
||||
mNavMeshToolInvoker->killProcess();
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::updateNavMeshProgress()
|
||||
{
|
||||
QProcess& process = *mNavMeshToolInvoker->getProcess();
|
||||
QString text;
|
||||
while (process.canReadLine())
|
||||
{
|
||||
const QByteArray line = process.readLine();
|
||||
const auto end = std::find_if(line.rbegin(), line.rend(), [] (auto v) { return v != '\n' && v != '\r'; });
|
||||
text = QString::fromUtf8(line.mid(0, line.size() - (end - line.rbegin())));
|
||||
ui.navMeshLogPlainTextEdit->appendPlainText(text);
|
||||
}
|
||||
const QRegularExpression pattern(R"([\( ](\d+)/(\d+)[\) ])");
|
||||
QRegularExpressionMatch match = pattern.match(text);
|
||||
if (!match.hasMatch())
|
||||
return;
|
||||
int maximum = match.captured(2).toInt();
|
||||
if (text.contains("cell"))
|
||||
maximum *= 100;
|
||||
ui.navMeshProgressBar->setMaximum(std::max(ui.navMeshProgressBar->maximum(), maximum));
|
||||
ui.navMeshProgressBar->setValue(match.captured(1).toInt());
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::navMeshToolFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
updateNavMeshProgress();
|
||||
ui.navMeshLogPlainTextEdit->appendPlainText(QString::fromUtf8(mNavMeshToolInvoker->getProcess()->readAll()));
|
||||
if (exitCode == 0 && exitStatus == QProcess::ExitStatus::NormalExit)
|
||||
ui.navMeshProgressBar->setValue(ui.navMeshProgressBar->maximum());
|
||||
ui.cancelNavMeshButton->setEnabled(false);
|
||||
ui.navMeshProgressBar->setEnabled(false);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
#define DATAFILESPAGE_H
|
||||
|
||||
#include "ui_datafilespage.h"
|
||||
|
||||
#include <components/process/processinvoker.hpp>
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
|
||||
|
@ -19,6 +22,7 @@ namespace Config { class GameSettings;
|
|||
|
||||
namespace Launcher
|
||||
{
|
||||
class MainDialog;
|
||||
class TextInputDialog;
|
||||
class ProfilesComboBox;
|
||||
|
||||
|
@ -31,7 +35,7 @@ namespace Launcher
|
|||
|
||||
public:
|
||||
explicit DataFilesPage (Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings,
|
||||
Config::LauncherSettings &launcherSettings, QWidget *parent = nullptr);
|
||||
Config::LauncherSettings &launcherSettings, MainDialog *parent = nullptr);
|
||||
|
||||
QAbstractItemModel* profilesModel() const;
|
||||
|
||||
|
@ -69,12 +73,18 @@ namespace Launcher
|
|||
void on_cloneProfileAction_triggered();
|
||||
void on_deleteProfileAction_triggered();
|
||||
|
||||
void startNavMeshTool();
|
||||
void killNavMeshTool();
|
||||
void updateNavMeshProgress();
|
||||
void navMeshToolFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
|
||||
public:
|
||||
/// Content List that is always present
|
||||
const static char *mDefaultContentListName;
|
||||
|
||||
private:
|
||||
|
||||
MainDialog *mMainDialog;
|
||||
TextInputDialog *mNewProfileDialog;
|
||||
TextInputDialog *mCloneProfileDialog;
|
||||
|
||||
|
@ -87,6 +97,8 @@ namespace Launcher
|
|||
QStringList previousSelectedFiles;
|
||||
QString mDataLocal;
|
||||
|
||||
Process::ProcessInvoker* mNavMeshToolInvoker;
|
||||
|
||||
void buildView();
|
||||
void setProfile (int index, bool savePrevious);
|
||||
void setProfile (const QString &previous, const QString ¤t, bool savePrevious);
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
#include <QDebug>
|
||||
#include <QCoreApplication>
|
||||
|
||||
Process::ProcessInvoker::ProcessInvoker()
|
||||
Process::ProcessInvoker::ProcessInvoker(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
mProcess = new QProcess(this);
|
||||
|
||||
|
@ -56,6 +57,7 @@ bool Process::ProcessInvoker::startProcess(const QString &name, const QStringLis
|
|||
// mProcess = new QProcess(this);
|
||||
mName = name;
|
||||
mArguments = arguments;
|
||||
mIgnoreErrors = false;
|
||||
|
||||
QString path(name);
|
||||
#ifdef Q_OS_WIN
|
||||
|
@ -151,6 +153,8 @@ bool Process::ProcessInvoker::startProcess(const QString &name, const QStringLis
|
|||
|
||||
void Process::ProcessInvoker::processError(QProcess::ProcessError error)
|
||||
{
|
||||
if (mIgnoreErrors)
|
||||
return;
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle(tr("Error running executable"));
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
|
@ -166,6 +170,8 @@ void Process::ProcessInvoker::processError(QProcess::ProcessError error)
|
|||
void Process::ProcessInvoker::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
if (exitCode != 0 || exitStatus == QProcess::CrashExit) {
|
||||
if (mIgnoreErrors)
|
||||
return;
|
||||
QString error(mProcess->readAllStandardError());
|
||||
error.append(tr("\nArguments:\n"));
|
||||
error.append(mArguments.join(" "));
|
||||
|
@ -181,3 +187,9 @@ void Process::ProcessInvoker::processFinished(int exitCode, QProcess::ExitStatus
|
|||
msgBox.exec();
|
||||
}
|
||||
}
|
||||
|
||||
void Process::ProcessInvoker::killProcess()
|
||||
{
|
||||
mIgnoreErrors = true;
|
||||
mProcess->kill();
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Process
|
|||
|
||||
public:
|
||||
|
||||
ProcessInvoker();
|
||||
ProcessInvoker(QObject* parent = nullptr);
|
||||
~ProcessInvoker();
|
||||
|
||||
// void setProcessName(const QString &name);
|
||||
|
@ -27,12 +27,16 @@ namespace Process
|
|||
inline bool startProcess(const QString &name, bool detached = false) { return startProcess(name, QStringList(), detached); }
|
||||
bool startProcess(const QString &name, const QStringList &arguments, bool detached = false);
|
||||
|
||||
void killProcess();
|
||||
|
||||
private:
|
||||
QProcess *mProcess;
|
||||
|
||||
QString mName;
|
||||
QStringList mArguments;
|
||||
|
||||
bool mIgnoreErrors = false;
|
||||
|
||||
private slots:
|
||||
void processError(QProcess::ProcessError error);
|
||||
void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
|
|
|
@ -2,13 +2,95 @@
|
|||
<ui version="4.0">
|
||||
<class>DataFilesPage</class>
|
||||
<widget class="QWidget" name="DataFilesPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>571</width>
|
||||
<height>384</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::DefaultContextMenu</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Data Files</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QWidget" name="contentSelectorWidget" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>Navigation mesh cache</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="updateNavMeshButton">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Generate navigation mesh cache for all content. Will be used by the engine to make cell loading faster.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Update</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="navMeshProgressBar">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancelNavMeshButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Cancel navigation mesh generation. Already processed data will be saved.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="navMeshLogPlainTextEdit">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="lineWrapMode">
|
||||
<enum>QPlainTextEdit::NoWrap</enum>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="profileGroupBox">
|
||||
<property name="focusPolicy">
|
||||
|
|
Loading…
Reference in a new issue