quickmod/FuseMounter/main.cpp
Daniel O'Neill 1393a796b2 Implement FUSE VFS as a very early implementation. It can, does, and will break your game.
Updated QML and C++ in various places to build and work with new Qt (6.4+)
Minor bugfixes, possibly caused by the Qt version bump, and mostly in JS logic.
Tried (again) to get mod sorting working by dragging them within the list.
Initial support for Profiles. (To switch between FO4 and FOLON, for example.)
Initial "Launch Game" stuff, but it's far from done. Don't use it (yet).
2025-08-20 07:57:00 -07:00

121 lines
3.6 KiB
C++

#include <QCoreApplication>
#include <QCommandLineParser>
#include <QDir>
#include <QSettings>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mount.h>
#include "archivemanager.h"
#include "database.h"
#include "fusestuff.h"
#include "fsproxy.h"
#include "signalhandler.h"
QDebug operator<<(QDebug debug, const ModLibrary &c)
{
QDebugStateSaver saver(debug);
debug.nospace() << "(ModLibrary:" << c.m_id << ", " << c.m_filename << ')';
return debug;
}
QDebug operator<<(QDebug debug, const ModEntry &c)
{
QDebugStateSaver saver(debug);
debug.nospace() << "(ModEntry:" << c.m_id << ", " << c.m_archivePath << ", " << c.m_installedPath << ')';
return debug;
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
app.setOrganizationDomain("org.oneill");
app.setOrganizationName("Quickmod");
app.setApplicationName("quickmod");
app.setApplicationVersion("1.0");
QCommandLineParser parser;
parser.setApplicationDescription("FUSE-based mod-mounter for QuickMod");
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument("game", QCoreApplication::translate("main", "Name of the game itself. Eg: \"Fallout 4\""));
parser.addPositionalArgument("target", QCoreApplication::translate("main", "Full path to target mountpoint"));
parser.addPositionalArgument("profile", QCoreApplication::translate("main", "Profile ID"));
// A boolean option with a single name (-l)
QCommandLineOption showMountsOption("l", QCoreApplication::translate("main", "Show currently mounted games"));
parser.addOption(showMountsOption);
parser.process(app);
bool force = parser.isSet(showMountsOption);
if( force )
{
printf("This is where I'd list my currently mounted games. Unimplemented. Sowwy.\n");
return 0;
}
const QStringList args = parser.positionalArguments();
if( args.length() < 2 )
{
parser.showHelp(-1);
return -1;
}
QString gamename = args.at(0);
QString targetdir = args.at(1);
int profileId = args.at(2).toInt();
// Lazy unmount in case we were mounted and ... crashed, or who knows:
::umount2( targetdir.toStdString().c_str(), MNT_DETACH );
QSettings s;
s.beginGroup(gamename);
QString dbpath = s.value("dbPath").toString();
QString gamedir = s.value("gamePath").toString();
QString modsdir = s.value("modsPath").toString();
Database db;
if( !db.open(dbpath) )
return -1;
FSProxy proxy;
proxy.setup(&db, profileId, gamename, gamedir);
ArchiveManager manager(&db, modsdir, profileId);
SignalHandler sh;
QObject::connect( &sh, &SignalHandler::hupSignalReceived, &manager, &ArchiveManager::reloadArchives );
QObject::connect( &sh, &SignalHandler::hupSignalReceived, &proxy, &FSProxy::reload );
sh.setup_unix_signal_handlers();
qmfuse_set_archive(&manager);
qmfuse_set_proxy(&proxy);
qmfuse_set_database(&db);
QObject::connect( &sh, &SignalHandler::hupSignalReceived, &sh, []() {
qmfuse_reset();
});
int fuse_fd = qmfuse_main(targetdir.toStdString().c_str());
QSocketNotifier fuse_notifier(fuse_fd, QSocketNotifier::Read);
QObject::connect( &fuse_notifier, &QSocketNotifier::activated, &sh, [&fuse_notifier, &app](){
int ret;
do {
ret = qmfuse_pump();
} while(ret > 0);
if( ret < 0 ) {
fuse_notifier.setEnabled(false);
app.quit();
}
} );
return app.exec();
//return qmfuse_main(targetdir.toStdString().c_str());
//return qmfuse_main(argc, argv);
}