Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cslol-tools/dep/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ FetchContent_Declare(
FetchContent_GetProperties(miniz)
if(NOT miniz_POPULATED)
FetchContent_Populate(miniz)
# Patch the CMakeLists.txt to use a newer minimum version
file(READ ${miniz_SOURCE_DIR}/CMakeLists.txt MINIZ_CMAKE)
string(REPLACE "cmake_minimum_required(VERSION 3.0)" "cmake_minimum_required(VERSION 3.20)" MINIZ_CMAKE ${MINIZ_CMAKE})
file(WRITE ${miniz_SOURCE_DIR}/CMakeLists.txt ${MINIZ_CMAKE})
add_subdirectory(${miniz_SOURCE_DIR} ${miniz_BINARY_DIR})
target_compile_definitions(miniz PRIVATE -DMINIZ_DISABLE_ZIP_READER_CRC32_CHECKS=1)
endif()
Expand Down
4 changes: 4 additions & 0 deletions src/CSLOLTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ CSLOLTools::CSLOLTools(QObject *parent) : QObject(parent) {
connect(worker_, &CSLOLToolsImpl::modWadsAdded, this, &CSLOLTools::modWadsAdded);
connect(worker_, &CSLOLToolsImpl::modWadsRemoved, this, &CSLOLTools::modWadsRemoved);
connect(worker_, &CSLOLToolsImpl::updatedMods, this, &CSLOLTools::updatedMods);
connect(worker_, &CSLOLToolsImpl::conflictDetected, this, &CSLOLTools::conflictDetected);

connect(this, &CSLOLTools::changeLeaguePath, worker_, &CSLOLToolsImpl::changeLeaguePath);
connect(this, &CSLOLTools::changeBlacklist, worker_, &CSLOLToolsImpl::changeBlacklist);
Expand All @@ -38,6 +39,9 @@ CSLOLTools::CSLOLTools(QObject *parent) : QObject(parent) {
connect(this, &CSLOLTools::deleteMod, worker_, &CSLOLToolsImpl::deleteMod);
connect(this, &CSLOLTools::exportMod, worker_, &CSLOLToolsImpl::exportMod);
connect(this, &CSLOLTools::installFantomeZip, worker_, &CSLOLToolsImpl::installFantomeZip);
connect(this, &CSLOLTools::installFantomeZips, worker_, &CSLOLToolsImpl::installFantomeZips);
connect(this, &CSLOLTools::handleDroppedUrls, worker_, &CSLOLToolsImpl::handleDroppedUrls);
connect(this, &CSLOLTools::resolveConflict, worker_, &CSLOLToolsImpl::resolveConflict);
connect(this, &CSLOLTools::saveProfile, worker_, &CSLOLToolsImpl::saveProfile);
connect(this, &CSLOLTools::loadProfile, worker_, &CSLOLToolsImpl::loadProfile);
connect(this, &CSLOLTools::deleteProfile, worker_, &CSLOLToolsImpl::deleteProfile);
Expand Down
6 changes: 6 additions & 0 deletions src/CSLOLTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class CSLOLTools : public QObject {
void updatedMods(QJsonArray mods);
void reportError(QString name, QString message, QString stack_trace);

void conflictDetected(QString modName, QString newPath);

void changeLeaguePath(QString newLeaguePath);
void changeBlacklist(bool blacklist);
void changeIgnorebad(bool ignorebad);
Expand All @@ -66,6 +68,10 @@ class CSLOLTools : public QObject {
void refreshMods();
void runDiag();

void installFantomeZips(QStringList paths);
void handleDroppedUrls(QStringList urls);
void resolveConflict(bool overwrite);

public slots:
CSLOLToolsImpl::CSLOLState getState();
QString getStatus();
Expand Down
181 changes: 149 additions & 32 deletions src/CSLOLToolsImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,38 +369,7 @@ void CSLOLToolsImpl::exportMod(QString name, QString dest) {

void CSLOLToolsImpl::installFantomeZip(QString path) {
if (state_ == CSLOLState::StateIdle && !path.isEmpty()) {
setState(CSLOLState::StateBusy);

setStatus("Installing Mod");
auto name = QFileInfo(path)
.fileName()
.replace(".zip", "")
.replace(".fantome", "")
.replace(".wad", "")
.replace(".client", "");
auto dst = prog_ + "/installed/" + name;
if (QDir old(dst); old.exists()) {
auto info = modInfoRead(name);
doReportError("Install mod", "Already exists", "");
setState(CSLOLState::StateIdle);
return;
}

runTool(
{
"import",
path,
dst,
"--game:" + game_,
blacklist_ ? "--noTFT" : "",
},
[=, this](int code, QProcess* process) {
if (code == 0) {
auto info = modInfoRead(name);
emit installedMod(name, info);
}
setState(CSLOLState::StateIdle);
});
installFantomeZips({path});
}
}

Expand Down Expand Up @@ -704,3 +673,151 @@ void CSLOLToolsImpl::runDiagInternal(bool internal_once) {
});
process->start(prog_ + DIAG_TOOL_EXE, QStringList{"d"});
}

void CSLOLToolsImpl::installFantomeZips(QStringList paths) {
if (state_ == CSLOLState::StateIdle && !paths.isEmpty()) {
setState(CSLOLState::StateBusy);
fantomeInstallQueue_ = paths;
fantomeInstallConflictName_ = "";
fantomeInstallConflictPath_ = "";
processFantomeInstallQueue();
}
}

void CSLOLToolsImpl::handleDroppedUrls(QStringList urls) {
if (state_ != CSLOLState::StateIdle || urls.isEmpty()) {
return;
}

setStatus("Processing dropped items...");

QStringList filesToInstall;
const QStringList nameFilters = {"*.zip", "*.fantome", "*.wad", "*.wad.client"};

for (const QString& urlString : urls) {
const QUrl url(urlString);
if (!url.isLocalFile()) {
continue;
}

const QString path = url.toLocalFile();
QFileInfo fileInfo(path);

if (fileInfo.isDir()) {
// If the dropped folder itself is named "chromas", skip it entirely.
if (fileInfo.fileName().compare("chromas", Qt::CaseInsensitive) == 0) {
continue;
}

QDirIterator it(path, nameFilters, QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()) {
const QString filePath = it.next();
// If the file is inside a directory named "chromas", skip it.
// QDirIterator always uses '/', so we only need to check for that separator.
if (filePath.contains("/chromas/", Qt::CaseInsensitive)) {
continue;
}
filesToInstall.append(filePath);
}
} else if (fileInfo.isFile()) {
// This logic remains the same for individual files.
if (nameFilters.contains("*." + fileInfo.completeSuffix())) {
filesToInstall.append(path);
}
}
}

if (!filesToInstall.isEmpty()) {
installFantomeZips(filesToInstall);
} else {
setStatus("No valid mod files found in dropped items.");
}
}

void CSLOLToolsImpl::processFantomeInstallQueue() {
if (fantomeInstallQueue_.isEmpty()) {
setStatus("Finished installing mods.");
setState(CSLOLState::StateIdle);
return;
}

auto path = fantomeInstallQueue_.takeFirst();
setStatus("Installing: " + path);

auto name = QFileInfo(path)
.fileName()
.replace(".zip", "")
.replace(".fantome", "")
.replace(".wad", "")
.replace(".client", "");
auto dst = prog_ + "/installed/" + name;

if (QDir(dst).exists()) {
fantomeInstallConflictName_ = name;
fantomeInstallConflictPath_ = path;
emit conflictDetected(name, path);
// We stop here and wait for resolveConflict to be called
return;
}

runTool(
{
"import",
path,
dst,
"--game:" + game_,
blacklist_ ? "--noTFT" : "",
},
[=, this](int code, QProcess* process) {
if (code == 0) {
auto info = modInfoRead(name);
emit installedMod(name, info);
}
// Process the next file in the queue
processFantomeInstallQueue();
});
}

void CSLOLToolsImpl::resolveConflict(bool overwrite) {
if (fantomeInstallConflictName_.isEmpty()) {
// Should not happen, but as a safeguard
processFantomeInstallQueue();
return;
}

auto name = fantomeInstallConflictName_;
auto path = fantomeInstallConflictPath_;
auto dst = prog_ + "/installed/" + name;

// Clear conflict state
fantomeInstallConflictName_ = "";
fantomeInstallConflictPath_ = "";

if (!overwrite) {
setStatus("Skipping: " + name);
processFantomeInstallQueue(); // Skip to the next file
return;
}

setStatus("Overwriting: " + name);
runTool(
{
"import",
path,
dst,
"--game:" + game_,
blacklist_ ? "--noTFT" : "",
},
[=, this](int code, QProcess* process) {
if (code == 0) {
// The mod was overwritten, so we need to tell the UI to refresh.
QJsonObject mods;
for (auto const& modName : modList()) {
mods.insert(modName, modInfoRead(modName));
}
emit refreshed(mods);
}
// Process the next file in the queue
processFantomeInstallQueue();
});
}
11 changes: 11 additions & 0 deletions src/CSLOLToolsImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class CSLOLToolsImpl : public QObject {
void updatedMods(QJsonArray mods);
void reportError(QString name, QString message, QString stack_trace);

void conflictDetected(QString modName, QString newPath);

public slots:
void changeLeaguePath(QString newLeaguePath);
void changeBlacklist(bool blacklist);
Expand All @@ -73,6 +75,10 @@ public slots:
void removeModWads(QString modFileName, QJsonArray wadNames);
void addModWad(QString modFileName, QString wad, bool removeUnknownNames);

void installFantomeZips(QStringList paths);
void handleDroppedUrls(QStringList urls);
void resolveConflict(bool overwrite);

CSLOLToolsImpl::CSLOLState getState();
QString getLeaguePath();

Expand Down Expand Up @@ -108,6 +114,11 @@ public slots:
void runPatcher(QStringList args);
void runTool(QStringList args, std::function<void(int code, QProcess*)> handle);
void runDiagInternal(bool internal_once);

QStringList fantomeInstallQueue_;
QString fantomeInstallConflictName_;
QString fantomeInstallConflictPath_;
void processFantomeInstallQueue();
};

#endif // QMODMANAGERWORKER_H
44 changes: 44 additions & 0 deletions src/qml/CSLOLDialogConflict.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.12

Dialog {
id: dialog
modal: true
standardButtons: Dialog.NoButton
title: qsTr("Conflict Detected")

property string modName: ""
property string newPath: ""

signal resolve(bool overwrite)

ColumnLayout {
Label {
text: qsTr("The mod '%1' already exists. Do you want to overwrite it?").arg(dialog.modName)
}
Label {
text: qsTr("New file: %1").arg(CSLOLUtils.fromFile(dialog.newPath))
font.italic: true
elide: Text.ElideLeft
}
}

footer: DialogButtonBox {
Button {
text: qsTr("Skip")
onClicked: {
dialog.resolve(false)
dialog.close()
}
}
Button {
text: qsTr("Overwrite")
onClicked: {
dialog.resolve(true)
dialog.close()
}
highlighted: true
}
}
}
8 changes: 4 additions & 4 deletions src/qml/CSLOLDialogOpenZipFantome.qml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Qt.labs.platform 1.0
FileDialog {
id: cslolDialogOpenZipFantome
visible: false
title: qsTr("Select Mod File")
fileMode: FileDialog.OpenFile
nameFilters: "Fantome Mod files (*.fantome *.zip)"
}
title: qsTr("Select Mod File(s)")
fileMode: FileDialog.OpenFiles
nameFilters: "Mod files (*.fantome *.zip *.wad *.wad.client)"
}
4 changes: 2 additions & 2 deletions src/qml/CSLOLModsView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ ColumnLayout {

signal modEdit(string fileName)

signal importFile(string file)
signal importFiles(var paths)

signal installFantomeZip()

Expand Down Expand Up @@ -278,7 +278,7 @@ ColumnLayout {
enabled: !isBussy
onDropped: function(drop) {
if (drop.hasUrls && drop.urls.length > 0) {
cslolModsView.importFile(CSLOLUtils.fromFile(drop.urls[0]))
cslolModsView.importFiles(drop.urls)
}
}
}
Expand Down
Loading