commit 29186b549e3a945531e6193285b908ece6bedd60 Author: Jkibbels Date: Sat Feb 8 04:18:42 2025 -0500 Stuff diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b359359 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/Desktop_Qt_6_7_3-Debug +CMakeLists.txt.user diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..56e252c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,73 @@ +cmake_minimum_required(VERSION 3.16) + +project(keeblarcraft_installer VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network) + +set(PROJECT_SOURCES + main.cpp + mainwindow.cpp + mainwindow.h + mainwindow.ui +) + +file(COPY background.png DESTINATION ${CMAKE_BINARY_DIR}) + +if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) + qt_add_executable(keeblarcraft_installer + MANUAL_FINALIZATION + ${PROJECT_SOURCES} + + ) +# Define target properties for Android with Qt 6 as: +# set_property(TARGET keeblarcraft_installer APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR +# ${CMAKE_CURRENT_SOURCE_DIR}/android) +# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation +else() + if(ANDROID) + add_library(keeblarcraft_installer SHARED + ${PROJECT_SOURCES} + ) +# Define properties for Android with Qt 5 after find_package() calls as: +# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") + else() + add_executable(keeblarcraft_installer + ${PROJECT_SOURCES} + ) + endif() +endif() + +target_link_libraries(keeblarcraft_installer PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Network) + +# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. +# If you are developing for iOS or macOS you should consider setting an +# explicit, fixed bundle identifier manually though. +if(${QT_VERSION} VERSION_LESS 6.1.0) + set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.keeblarcraft_installer) +endif() +set_target_properties(keeblarcraft_installer PROPERTIES + ${BUNDLE_ID_OPTION} + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUElibglu1-mesa-dev +) + +include(GNUInstallDirs) +install(TARGETS keeblarcraft_installer + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + +if(QT_VERSION_MAJOR EQUAL 6) + qt_finalize_executable(keeblarcraft_installer) +endif() diff --git a/background.png b/background.png new file mode 100644 index 0000000..43cc1a6 Binary files /dev/null and b/background.png differ diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..d22b484 --- /dev/null +++ b/main.cpp @@ -0,0 +1,12 @@ +#include "mainwindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.setFixedSize(1166, 580); // Tested on one resolution, we will USE one resolution! + w.show(); + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..3aa048e --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,181 @@ +#include "mainwindow.h" +#include "./ui_mainwindow.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN64 +#include +#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 ui; + delete net; + delete reply; +} + +void MainWindow::on_install_update_button_clicked() +{ + QNetworkRequest request(downloadUrl); + reply = net->get(request); + + // connect(reply, SIGNAL(&QNetworkReply::errorOccurred), this, SLOT(Error(QNetworkReply::NetworkError))); + 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())); +} + +void MainWindow::UpdateProgress(qint64 read, qint64 total) { + ui->mf_progress_bar->setMaximum(total); + ui->mf_progress_bar->setValue(read); +} + +void MainWindow::FinishedDownloading() { + QByteArray data = reply->readAll(); + downloadLocation = "/home/jesse/Downloads/mods.zip"; + + 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 + Install(); +} + +std::string MainWindow::BuildUnzipCmd() { + std::stringstream ss; +#ifdef _WINDOWS + ss << "tar -xf " << downloadLocation.toStdString() << " -C " << modsDir.toStdString(); +#elif __unix__ + ss << "unzip " << downloadLocation.toStdString() << " -d " << modsDir.toStdString(); +#endif + qDebug() << "Tar command is: " << ss.str(); + 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); + // 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().append("mods")) && modsDir != downloadLocation) { + modsDir.append("mods"); + std::filesystem::remove_all(modsDir.toStdString()); + } + + ui->mf_progress_bar->setValue(installStage++); + + system(BuildUnzipCmd().c_str()); + + ui->mf_progress_bar->setValue(installStage++); + + QMessageBox::information(nullptr, "Completed", "The installer has successfully finished. You may now close the installer and launch Minecraft!"); + PostInstallMode(); +} + +void MainWindow::Error(QNetworkReply::NetworkError code) { + reply->deleteLater(); + QMessageBox::warning(nullptr, "Error", reply->errorString()); +} + +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); +} + +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); +} + +void MainWindow::UpdateOSAgnosticInformation() { +#ifdef _WIN64 + isLinux = false; + char* appDataLoc = std::getenv("APPDATA"); + if (appDataLoc) { + std::filesystem::path execPath(appDataLoc); + downloadLocation = QString(execPath.c_str()); // Stick the mods inside the roaming directory; but not the .minecraft directory itself. + modsDir = downloadLocation + "\\.minecraft\\"; + } +#elif __unix__ + isLinux = true; + downloadLocation = getenv("HOME"); + modsDir = downloadLocation + "/.minecraft/"; // Default value + + ui->mcInstallDir->setText(modsDir); // Tell the user the default location for their .minecraft folder. +#endif + + // Update the UI to reflect the default values correctly + ui->sf_dl_server->setPlainText(downloadUrl.toString()); +} + + +void MainWindow::on_close_launcher_clicked() +{ + delete reply; + delete net; + QApplication::quit(); +} + +// unused +void MainWindow::on_changeInstallPathButton_triggered(QAction *arg1){} + + +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; + } + + qDebug() << "New active .minecraft dir is: " << modsDir; + ui->mcInstallDir->setText(modsDir); +} + diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..5135e30 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,51 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +namespace Ui { +class MainWindow; +} +QT_END_NAMESPACE + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + void UpdateOSAgnosticInformation(); + void Install(); + std::string BuildUnzipCmd(); + void PreInstallMode(); + void PostInstallMode(); +private slots: + void UpdateProgress(qint64, qint64); + void FinishedDownloading(); + void Error(QNetworkReply::NetworkError code); + void on_install_update_button_clicked(); + + void on_close_launcher_clicked(); + + void on_changeInstallPathButton_triggered(QAction *arg1); + + void on_changeInstallPathButton_clicked(); + +private: + Ui::MainWindow *ui; + QNetworkAccessManager* net = nullptr; + QUrl downloadUrl {"https://www.techyjessy.tech/downloads/mods.zip"}; + QString modsDir; + QString downloadLocation; + QNetworkReply* reply = nullptr; + + bool isLinux = true; +}; +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..9a8a6c9 --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,176 @@ + + + MainWindow + + + + 0 + 0 + 1166 + 580 + + + + MainWindow + + + + + + -1 + 79 + 1171 + 481 + + + + QFrame::Shape::NoFrame + + + + + 460 + 350 + 241 + 91 + + + + Update / Install + + + + + + 130 + 30 + 891 + 51 + + + + true + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> +p, li { white-space: pre-wrap; } +hr { height: 1px; border-width: 0; } +li.unchecked::marker { content: "\2610"; } +li.checked::marker { content: "\2612"; } +</style></head><body style=" font-family:'Fira Sans'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Fira Sans Semi-Light';">Hi! This is the first version of the Keeblarcraft installer! For now all it does is check if you have the modpack installed &amp; only hangs onto the Config files and overwrites all the individual mod jar files. Have fun!</span></p></body></html> + + + + + + 770 + 360 + 321 + 61 + + + + 0 + + + + + + 30 + 90 + 431 + 41 + + + + Download Server Here + + + + + + true + + + + 460 + 350 + 241 + 91 + + + + Close Installer + + + + + + 470 + 95 + 181 + 31 + + + + <-- Download server here + + + + + + 10 + 370 + 431 + 41 + + + + Default minecraft path here... + + + + + + 410 + 380 + 24 + 23 + + + + ... + + + + + + + -1 + -1 + 1171 + 81 + + + + QFrame::Shape::NoFrame + + + + + + + 0 + 0 + 1166 + 21 + + + + + + + +