Skip to content

Commit

Permalink
add mod updating facility
Browse files Browse the repository at this point in the history
  • Loading branch information
moonshadow565 committed Aug 27, 2022
1 parent af57c49 commit 5582e8e
Show file tree
Hide file tree
Showing 10 changed files with 274 additions and 6 deletions.
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ add_subdirectory(cslol-tools)

option(USE_QT6 "Use Qt6 instead of Qt5" OFF)
if (USE_QT6)
find_package(Qt6 6.1 COMPONENTS Core Gui Quick QmlImportScanner REQUIRED)
find_package(Qt6 6.1 COMPONENTS Core Gui Quick QmlImportScanner Network REQUIRED)
else()
find_package(Qt5 5.15 COMPONENTS Core Gui Quick QmlImportScanner REQUIRED)
find_package(Qt5 5.15 COMPONENTS Core Gui Quick QmlImportScanner Network REQUIRED)
endif()
find_package(Threads REQUIRED)
find_package(Git QUIET REQUIRED)
Expand Down Expand Up @@ -83,7 +83,7 @@ target_sources(cslol-manager PRIVATE
)

target_compile_definitions(cslol-manager PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)
target_link_libraries(cslol-manager PRIVATE Qt::Core Qt::Gui Qt::Quick Threads::Threads)
target_link_libraries(cslol-manager PRIVATE Qt::Core Qt::Gui Qt::Quick Qt::Network Threads::Threads)
target_include_directories(cslol-manager PRIVATE src/)

qt_import_qml_plugins(cslol-manager)
3 changes: 2 additions & 1 deletion src/CSLOLTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ CSLOLTools::CSLOLTools(QObject *parent) : QObject(parent) {
connect(worker_, &CSLOLToolsImpl::modInfoChanged, this, &CSLOLTools::modInfoChanged);
connect(worker_, &CSLOLToolsImpl::modWadsAdded, this, &CSLOLTools::modWadsAdded);
connect(worker_, &CSLOLToolsImpl::modWadsRemoved, this, &CSLOLTools::modWadsRemoved);
connect(worker_, &CSLOLToolsImpl::refreshed, this, &CSLOLTools::refreshed);
connect(worker_, &CSLOLToolsImpl::updatedMods, this, &CSLOLTools::updatedMods);

connect(this, &CSLOLTools::changeLeaguePath, worker_, &CSLOLToolsImpl::changeLeaguePath);
connect(this, &CSLOLTools::changeBlacklist, worker_, &CSLOLToolsImpl::changeBlacklist);
Expand All @@ -47,6 +47,7 @@ CSLOLTools::CSLOLTools(QObject *parent) : QObject(parent) {
connect(this, &CSLOLTools::addModWad, worker_, &CSLOLToolsImpl::addModWad);
connect(this, &CSLOLTools::removeModWads, worker_, &CSLOLToolsImpl::removeModWads);
connect(this, &CSLOLTools::refreshMods, worker_, &CSLOLToolsImpl::refreshMods);
connect(this, &CSLOLTools::doUpdate, worker_, &CSLOLToolsImpl::doUpdate);

connect(this, &CSLOLTools::destroyed, worker_, &CSLOLToolsImpl::deleteLater);
connect(worker_, &CSLOLTools::destroyed, thread_, &QThread::deleteLater);
Expand Down
2 changes: 2 additions & 0 deletions src/CSLOLTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class CSLOLTools : public QObject {
void modWadsAdded(QString modFileName, QJsonArray wads);
void modWadsRemoved(QString modFileName, QJsonArray wads);
void refreshed(QJsonObject mods);
void updatedMods(QJsonArray mods);
void reportError(QString name, QString message, QString stack_trace);

void changeLeaguePath(QString newLeaguePath);
Expand All @@ -63,6 +64,7 @@ class CSLOLTools : public QObject {
void addModWad(QString modFileName, QString wad, bool removeUnknownNames);
void removeModWads(QString modFileName, QJsonArray wads);
void refreshMods();
void doUpdate(QString urls);

public slots:
CSLOLToolsImpl::CSLOLState getState();
Expand Down
82 changes: 82 additions & 0 deletions src/CSLOLToolsImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
#include <QFile>
#include <QFileInfo>
#include <QJsonDocument>
#include <QMap>
#include <QMetaEnum>
#include <QNetworkReply>
#include <QStandardPaths>
#include <QThread>
#include <QVersionNumber>
#include <fstream>

#include "CSLOLVersion.h"
Expand Down Expand Up @@ -407,6 +410,85 @@ void CSLOLToolsImpl::refreshMods() {
}
}

void CSLOLToolsImpl::doUpdate(QString urls) {
if (!networkManager_) {
this->networkManager_ = new QNetworkAccessManager(this);
this->networkManager_->setTransferTimeout(30000);
connect(this->networkManager_, &QNetworkAccessManager::finished, this, [this](QNetworkReply* reply) {
if (reply->error()) {
auto error = reply->errorString();
setStatus("[WRN] Failed to fetch update index: " + error);
this->networkResults_.push_back(QJsonDocument::fromJson("[]"));
} else {
auto result = reply->readAll();
this->networkResults_.push_back(QJsonDocument::fromJson(result));
}

if (this->networkResults_.size() < this->networkRequests_.size()) {
return;
}

auto lookup = QMap<QString, QVersionNumber>{};
for (auto name : modList()) {
auto info = modInfoRead(name);
auto key = info["Name"].toString().toLower();
auto version = QVersionNumber::fromString(info["Version"].toString());
lookup[key] = version;
}

auto mods = QJsonArray{};
for (auto const& result : this->networkResults_) {
if (!result.isArray()) {
continue;
}
for (auto const& value : result.array()) {
auto info = modInfoFixup("", value.toObject());
if (info["Download"].toString().isEmpty() || !info["Download"].isString()) {
info["Download"] = info["Home"];
}
auto key = info["Name"].toString().toLower();
if (lookup.contains(key)) {
auto const& old_version = lookup[key];
auto new_version = QVersionNumber::fromString(info["Version"].toString());
if (old_version < new_version) {
mods.append(info);
}
}
}
}

emit updatedMods(mods);

setState(CSLOLState::StateIdle);
});
}

if (state_ == CSLOLState::StateIdle) {
setState(CSLOLState::StateBusy);
setStatus("Updating mods");

this->networkResults_.clear();
this->networkRequests_.clear();
for (auto url : urls.split('\n')) {
url = url.trimmed();
if (url.isEmpty() || url.startsWith("#")) {
continue;
}
this->networkRequests_.emplace_back(QUrl(url));
}

if (this->networkRequests_.empty()) {
doReportError("Update mods", "Make sure to set update urls in settings!", "");
setState(CSLOLState::StateIdle);
return;
}

for (auto& req : this->networkRequests_) {
this->networkManager_->get(req);
}
}
}

void CSLOLToolsImpl::saveProfile(QString name, QJsonObject mods, bool run, bool skipConflict) {
if (state_ == CSLOLState::StateIdle) {
setState(CSLOLState::StateBusy);
Expand Down
6 changes: 6 additions & 0 deletions src/CSLOLToolsImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <QJsonObject>
#include <QLockFile>
#include <QMap>
#include <QNetworkAccessManager>
#include <QObject>
#include <QProcess>
#include <QString>
Expand Down Expand Up @@ -44,6 +45,7 @@ class CSLOLToolsImpl : public QObject {
void modWadsAdded(QString modFileName, QJsonArray wads);
void modWadsRemoved(QString modFileName, QJsonArray wads);
void refreshed(QJsonObject mods);
void updatedMods(QJsonArray mods);
void reportError(QString name, QString message, QString stack_trace);

public slots:
Expand All @@ -60,6 +62,7 @@ public slots:
void stopProfile();
void makeMod(QString fileName, QJsonObject infoData, QString image);
void refreshMods();
void doUpdate(QString urls);

void startEditMod(QString fileName);
void changeModInfo(QString fileName, QJsonObject infoData, QString image);
Expand All @@ -70,6 +73,9 @@ public slots:
QString getLeaguePath();

private:
QNetworkAccessManager* networkManager_ = nullptr;
std::vector<QJsonDocument> networkResults_ = {};
std::vector<QNetworkRequest> networkRequests_ = {};
QLockFile* lockfile_ = nullptr;
QProcess* patcherProcess_ = nullptr;
QString prog_ = "";
Expand Down
17 changes: 16 additions & 1 deletion src/qml/CSLOLDialogSettings.qml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Dialog {
property alias suppressInstallConflicts: suppressInstallConflictsCheck.checked
property alias enableSystray: enableSystrayCheck.checked
property alias enableAutoRun: enableAutoRunCheck.checked
property alias updateUrls: updateUrlsTextArea.text

property var colors_LIST: [
"Red",
Expand Down Expand Up @@ -78,7 +79,7 @@ Dialog {
StackLayout {
id: settingsStackLayout
width: parent.width
Layout.fillHeight: true
height: parent.height - settingsTabBar.height - 5
currentIndex: settingsTabBar.currentIndex
ColumnLayout {
id: settingsGameTab
Expand Down Expand Up @@ -108,6 +109,7 @@ Dialog {
Layout.fillWidth: true
}
}

ColumnLayout {
id: settingsSystemTab
spacing: 5
Expand All @@ -121,6 +123,19 @@ Dialog {
onClicked: Qt.openUrlExternally(cslolDialogUpdate.update_url)
Layout.fillWidth: true
}
ScrollView {
Layout.fillHeight: true
Layout.fillWidth: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
padding: ScrollBar.vertical.width
clip: true
TextArea {
id: updateUrlsTextArea
placeholderText: qsTr("Update urls")
textFormat: TextEdit.PlainText
}
}
CheckBox {
id: enableUpdatesCheck
text: qsTr("Enable updates")
Expand Down
135 changes: 135 additions & 0 deletions src/qml/CSLOLDialogUpdateMods.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import QtQuick 2.15
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.15
import QtQuick.Controls.Material 2.15

Dialog {
id: cslolDialogUpdateMods
width: parent.width * 0.9
height: parent.height * 0.9
x: (parent.width - width) / 2
y: (parent.height - height) / 2
standardButtons: Dialog.Ok
closePolicy: Popup.CloseOnEscape
modal: true
title: qsTr("Mod updates and fixes:")
Overlay.modal: Rectangle {
color: "#aa333333"
}
onOpened: window.show()

property int columnCount: 1
property real rowHeight: 0
property alias updatedMods: cslolUpdateModsView.model

updatedMods: []

ScrollView {
id: cslolUpdateModsScrollView
width: parent.width
height: parent.height
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
padding: ScrollBar.vertical.width
spacing: 5

GridView {
id: cslolUpdateModsView
cellWidth: cslolUpdateModsView.width / cslolDialogUpdateMods.columnCount
cellHeight: 75
delegate: Pane {
property var model: modelData
width: cslolUpdateModsView.width / cslolDialogUpdateMods.columnCount - cslolUpdateModsScrollView.spacing
Component.onCompleted: {
let newCellHeight = height + cslolUpdateModsScrollView.spacing
if (cslolUpdateModsView.cellHeight < newCellHeight) {
cslolUpdateModsView.cellHeight = newCellHeight;
}
}
Material.elevation: 3
Row {
width: parent.width
Row {
id: modUpdateButtons
width: parent.width * 0.3

ToolButton {
anchors.verticalCenter: parent.verticalCenter
text: "\uf0ed "
font.family: "FontAwesome"
onClicked: {
let url = model.Download
if (window.validUrl.test(url)) {
Qt.openUrlExternally(url)
}
}
CSLOLToolTip {
text: qsTr("Download")
visible: parent.hovered
}
}
Label {
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignHCenter
text: model.Name
elide: Text.ElideRight
Layout.fillWidth: true
}
}
Column {
width: parent.width * 0.39
anchors.verticalCenter: parent.verticalCenter
Label {
horizontalAlignment: Text.AlignHCenter
text: "V" + model.Version + " by " + model.Author
elide: Text.ElideRight
width: parent.width
}
Label {
horizontalAlignment: Text.AlignHCenter
text: model.Description ? model.Description : ""
wrapMode: Text.Wrap
elide: Text.ElideRight
maximumLineCount: 2
width: parent.width
}
}
Row {
id: modUpdateButtons2
width: parent.width * 0.3
anchors.verticalCenter: parent.verticalCenter
layoutDirection: Qt.RightToLeft
ToolButton {
text: "\uf059"
font.family: "FontAwesome"
onClicked: {
let url = model.Home
if (window.validUrl.test(url)) {
Qt.openUrlExternally(url)
}
}
CSLOLToolTip {
text: qsTr("Mod updates")
visible: parent.hovered
}
}
ToolButton {
text: "\uf004"
font.family: "FontAwesome"
onClicked: {
let url = model.Heart
if (window.validUrl.test(url)) {
Qt.openUrlExternally(url)
}
}
CSLOLToolTip {
text: qsTr("Support this author")
visible: parent.hovered
}
}
}
}
}
}
}
}
13 changes: 13 additions & 0 deletions src/qml/CSLOLModsView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ ColumnLayout {

signal tryRefresh()

signal getUpdates()

function addMod(fileName, info, enabled) {
let infoData = {
"FileName": fileName,
Expand Down Expand Up @@ -465,6 +467,17 @@ ColumnLayout {
visible: parent.hovered
}
}
RoundButton {
enabled: !isBussy
text: "\uf0ad"
font.family: "FontAwesome"
onClicked: cslolModsView.getUpdates()
Material.background: Material.primaryColor
CSLOLToolTip {
text: qsTr("Mod updates and fixes")
visible: parent.hovered
}
}
RoundButton {
enabled: !isBussy
text: "\uf067"
Expand Down
Loading

0 comments on commit 5582e8e

Please sign in to comment.