228 lines
8.3 KiB
C++
228 lines
8.3 KiB
C++
#include "mainwindow.h"
|
|
#include "./ui_mainwindow.h"
|
|
#include <QMessageBox>
|
|
#include <QProgressBar>
|
|
#include <QFile>
|
|
#include <QFileInfo>
|
|
#include <QDir>
|
|
#include <filesystem>
|
|
#include <sstream>
|
|
#include <QFileDialog>
|
|
|
|
#ifdef _WIN64
|
|
#include <Windows.h>
|
|
#endif
|
|
|
|
namespace {
|
|
constexpr uint8_t MAX_INSTALL_STAGES = 3;
|
|
}
|
|
|
|
MainWindow::MainWindow(QWidget *parent)
|
|
: QMainWindow(parent)
|
|
, ui(new Ui::MainWindow)
|
|
{
|
|
ui->setupUi(this);
|
|
UpdateOSAgnosticInformation();
|
|
net = new QNetworkAccessManager(this);
|
|
PreInstallMode();
|
|
QWidget::setWindowTitle("Keeblarcraft Mod Installer");
|
|
// ui->centralwidget->setStyleSheet("background-image:url(background.png); background-position: center;"); // Needs work
|
|
}
|
|
|
|
MainWindow::~MainWindow()
|
|
{
|
|
delete net;
|
|
delete reply;
|
|
delete ui;
|
|
}
|
|
|
|
// Kick off the installation
|
|
void MainWindow::on_install_update_button_clicked()
|
|
{
|
|
if (ConfirmationPopup()) {
|
|
QNetworkRequest request(downloadUrl);
|
|
reply = net->get(request);
|
|
|
|
connect(reply, &QNetworkReply::errorOccurred, this, [this](QNetworkReply::NetworkError) {
|
|
reply->deleteLater();
|
|
QMessageBox::warning(nullptr, "Error", reply->errorString());
|
|
});
|
|
|
|
connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(UpdateProgress(qint64, qint64)));
|
|
connect(reply, SIGNAL(finished()), this, SLOT(FinishedDownloading()));
|
|
}
|
|
}
|
|
|
|
// Callback from network manager on download. Update the progress bar as we download
|
|
void MainWindow::UpdateProgress(qint64 read, qint64 total) {
|
|
ui->mf_progress_bar->setMaximum(total);
|
|
ui->mf_progress_bar->setValue(read);
|
|
}
|
|
|
|
// This is a callback to when the download is completed by the network manager
|
|
void MainWindow::FinishedDownloading() {
|
|
QByteArray data = reply->readAll();
|
|
|
|
QFile file(downloadLocation);
|
|
|
|
if (file.open(QIODevice::WriteOnly)) {
|
|
qint64 bytesWritten = file.write(data);
|
|
} else {
|
|
QMessageBox::warning(nullptr, "Error", file.errorString());
|
|
}
|
|
|
|
reply->deleteLater();
|
|
|
|
// Update button to not be pressable again. Will probably stick this on a timer in the future
|
|
ui->install_update_button->setEnabled(false);
|
|
ui->install_update_button->show();
|
|
ui->install_update_button->setText(QString("Unzipping..."));
|
|
|
|
// Unzip the file - this version isn't really checking if the file is really us so at the very least the name needs to match.
|
|
// Otherwise we could end up damaging the ecosystem more than necessary.
|
|
if (std::filesystem::exists(downloadLocation.toStdString())) {
|
|
Install();
|
|
} else {
|
|
QMessageBox::critical(nullptr, "Wrong format", "The downloaded file appears to not exist - or is more likely just not named mods.zip -> you either downloaded a bad file or Jesse named his file wrong. Tell him to fix it!!");
|
|
PostInstallMode();
|
|
}
|
|
}
|
|
|
|
// Build the unzip command depending on the users operating system
|
|
std::string MainWindow::BuildUnzipCmd() {
|
|
std::stringstream ss;
|
|
#ifdef WIN64
|
|
ss << "tar -xf " << downloadLocation.toStdString() << " -C " << modsDir.toStdString();
|
|
#elif __unix__
|
|
qDebug() << "DL Loc: " << downloadLocation << " modsDir: " << modsDir;
|
|
ss << "unzip " << downloadLocation.toStdString() << " -d " << modsDir.toStdString();
|
|
#endif
|
|
return ss.str();
|
|
}
|
|
|
|
// Installation step covers everything from unzipping to installing the mods to making sure fabric is installed
|
|
void MainWindow::Install() {
|
|
uint8_t installStage = 1;
|
|
ui->mf_progress_bar->setValue(installStage++);
|
|
ui->mf_progress_bar->setMaximum(MAX_INSTALL_STAGES);
|
|
|
|
modsDir.append("mods");
|
|
|
|
// COND 1: If mods dir exists we need to nuke it
|
|
// COND 2: If mods dir exists & it was our install location do NOT nuke it!
|
|
if (std::filesystem::is_directory(modsDir.toStdString()) && modsDir != downloadLocation) {
|
|
std::filesystem::remove_all(modsDir.toStdString()); // Force empty the mods folder inside the .minecraft dir
|
|
}
|
|
|
|
if (!std::filesystem::exists(modsDir.toStdString())) {
|
|
std::filesystem::create_directory(modsDir.toStdString());
|
|
}
|
|
|
|
ui->mf_progress_bar->setValue(installStage++);
|
|
|
|
system(BuildUnzipCmd().c_str());
|
|
|
|
ui->mf_progress_bar->setValue(installStage++);
|
|
|
|
// Clean up after ourselves; remove the file if possible
|
|
try {
|
|
if (std::filesystem::exists(downloadLocation.toStdString())) {
|
|
std::filesystem::remove(downloadLocation.toStdString());
|
|
}
|
|
} catch (std::exception e) {
|
|
QString errorMsg = QString("Slight error - unable to cleanup after ourselves and could not remove leftover downloaded zip file located at %1").arg(downloadLocation);
|
|
QMessageBox::information(nullptr, "Failed to cleanup!", errorMsg);
|
|
}
|
|
|
|
QMessageBox::information(nullptr, "Completed", "The installer has successfully finished. You may now close the installer and launch Minecraft!");
|
|
PostInstallMode();
|
|
}
|
|
|
|
// Callback for downloading
|
|
void MainWindow::Error(QNetworkReply::NetworkError code) {
|
|
reply->deleteLater();
|
|
QMessageBox::warning(nullptr, "Error", reply->errorString());
|
|
}
|
|
|
|
// Setup the window to be ready to update/install the mods folder
|
|
void MainWindow::PreInstallMode() {
|
|
ui->mf_progress_bar->setEnabled(false);
|
|
ui->install_update_button->setText("Update / Install");
|
|
ui->install_update_button->setVisible(true);
|
|
ui->close_launcher->setEnabled(false);
|
|
ui->close_launcher->setVisible(false);
|
|
}
|
|
|
|
// Set window variables after installation and unzipping
|
|
void MainWindow::PostInstallMode() {
|
|
ui->mf_progress_bar->setEnabled(false);
|
|
ui->install_update_button->setEnabled(false);
|
|
ui->install_update_button->setVisible(false);
|
|
ui->close_launcher->setEnabled(true);
|
|
ui->close_launcher->setVisible(true);
|
|
}
|
|
|
|
// Make sure the user is sure they are OK with the current configuration
|
|
bool MainWindow::ConfirmationPopup() {
|
|
// This is the preinstall pop up box
|
|
QString tInstallFabric = "YOU MUST HAVE FABRIC INSTALLED PRIOR TO USING THIS INSTALLER";
|
|
QString tempInstallPath = "Install to: " + modsDir;
|
|
QString tempDlSrvr = "Grab mods.zip from: " + downloadUrl.toString();
|
|
QString deleteAll = "This installer will DELETE YOUR EXISTING MODS DIRECTORY. Back it up if you care about it beforehand!";
|
|
QString formatted = tInstallFabric.append(tempInstallPath).append("\n").append("\n").append(tempDlSrvr).append("\n").append(deleteAll);
|
|
QMessageBox::StandardButton reply = QMessageBox::question(nullptr, "Confirm install options...", formatted);
|
|
|
|
return reply == QMessageBox::Yes;
|
|
}
|
|
|
|
// This handles setting data prior to the install period dependent on the users operating system.
|
|
void MainWindow::UpdateOSAgnosticInformation() {
|
|
#ifdef _WIN64
|
|
char* appDataLoc = std::getenv("APPDATA");
|
|
if (appDataLoc) {
|
|
std::filesystem::path execPath(appDataLoc);
|
|
downloadLocation = QString::fromStdString(execPath.string()); // Stick the mods inside the roaming directory; but not the .minecraft directory itself.
|
|
modsDir = downloadLocation + "\\.minecraft\\";
|
|
downloadLocation.append("\\mods.zip"); // Should point to %APPDATA%\mods.zip
|
|
|
|
} else {
|
|
QMessageBox::warning(nullptr, "Warning", "Unable to resolve APPDATA environment variable. You must manually set the .minecraft folder location");
|
|
}
|
|
#elif __unix__
|
|
downloadLocation = getenv("HOME");
|
|
modsDir = downloadLocation + "/.minecraft/"; // Default value
|
|
downloadLocation.append("/mods.zip");
|
|
#endif
|
|
|
|
// Update the UI to reflect the default values correctly
|
|
ui->sf_dl_server->setPlainText(downloadUrl.toString());
|
|
ui->mcInstallDir->setText(modsDir);
|
|
}
|
|
|
|
// This just closes the application but DOES call the destructor.
|
|
// It technically segfaults on the way out for some odd reason; but the pointers are cleaned up. Who knows!
|
|
void MainWindow::on_close_launcher_clicked()
|
|
{
|
|
QApplication::quit();
|
|
}
|
|
|
|
// This is called if the users default .minecraft path cannot be found (by a user pressing the button of course)
|
|
void MainWindow::on_changeInstallPathButton_clicked()
|
|
{
|
|
QString directory = QFileDialog::getExistingDirectory(this, tr("Find Files"), QDir::currentPath());
|
|
|
|
if (!directory.isEmpty()) {
|
|
// We will trust the user that this is the .minecraft folder and do 0 error checking.
|
|
modsDir = directory;
|
|
}
|
|
|
|
ui->mcInstallDir->setText(modsDir);
|
|
}
|
|
|
|
|
|
void MainWindow::on_sf_dl_server_textChanged()
|
|
{
|
|
downloadUrl = ui->sf_dl_server->toPlainText();
|
|
}
|
|
|