diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..3939dff
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,43 @@
+cmake_minimum_required(VERSION 3.19)
+project(minecraft-launcher LANGUAGES CXX)
+
+find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets)
+
+qt_standard_project_setup()
+
+qt_add_executable(minecraft-launcher
+ WIN32 MACOSX_BUNDLE
+
+
+
+
+ main.cpp
+ mainwindow.h mainwindow.cpp
+ settingsdialog.h settingsdialog.cpp
+ settingsdialog.ui
+ mainwindow.ui
+
+
+
+)
+
+target_link_libraries(minecraft-launcher
+ PRIVATE
+ Qt::Core
+ Qt::Widgets
+)
+
+include(GNUInstallDirs)
+
+install(TARGETS minecraft-launcher
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_app_script(
+ TARGET minecraft-launcher
+ OUTPUT_SCRIPT deploy_script
+ NO_UNSUPPORTED_PLATFORM_ERROR
+)
+install(SCRIPT ${deploy_script})
diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user
new file mode 100644
index 0000000..9d354e7
--- /dev/null
+++ b/CMakeLists.txt.user
@@ -0,0 +1,314 @@
+
+
+
+
+
+ EnvironmentId
+ {137161dd-990c-4c0b-851a-d10872a75af9}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ true
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 0
+ 80
+ true
+ true
+ 1
+ 0
+ false
+ true
+ false
+ 2
+ true
+ true
+ 0
+ 8
+ true
+ false
+ 1
+ true
+ true
+ true
+ *.md, *.MD, Makefile
+ false
+ true
+ true
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+ false
+ true
+ true
+ true
+ true
+
+ false
+
+
+ 0
+ true
+
+ true
+ true
+ Builtin.DefaultTidyAndClazy
+ 16
+ true
+
+ G:/Documents/The_Grand_Archives/Qt_projects/minecraft-launcher/CMakeLists.txt
+
+
+
+ true
+
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop
+ true
+ Desktop Qt 6.9.2 MinGW 64-bit
+ Desktop Qt 6.9.2 MinGW 64-bit
+ qt.qt6.692.win64_mingw_kit
+ 0
+ 0
+ 0
+
+ Debug
+ 2
+ false
+
+ -DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
+-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
+-DQT_MAINTENANCE_TOOL:FILEPATH=E:/Qt/MaintenanceTool.exe
+-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
+-DCMAKE_BUILD_TYPE:STRING=Debug
+-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
+-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
+-DCMAKE_GENERATOR:STRING=Ninja
+-DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON
+ 0
+ G:\Documents\The_Grand_Archives\Qt_projects\minecraft-launcher\build\Desktop_Qt_6_9_2_MinGW_64_bit-Debug
+
+
+
+
+ all
+
+ false
+
+ true
+ Собрать
+ CMakeProjectManager.MakeStep
+
+ 1
+ Сборка
+ Сборка
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ clean
+
+ false
+
+ true
+ Собрать
+ CMakeProjectManager.MakeStep
+
+ 1
+ Очистка
+ Очистка
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Отладка
+ CMakeProjectManager.CMakeBuildConfiguration
+ 0
+ 0
+
+
+ 0
+ Развёртывание
+ Развёртывание
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+
+
+
+
+
+
+
+ false
+
+ true
+ ApplicationManagerPlugin.Deploy.CMakePackageStep
+
+
+ install-package --acknowledge
+ true
+ Install Application Manager package
+ ApplicationManagerPlugin.Deploy.InstallPackageStep
+
+
+
+
+
+
+
+ 2
+ Развёртывание
+ Развёртывание
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ApplicationManagerPlugin.Deploy.Configuration
+
+ 2
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+ minecraft-launcher
+ CMakeProjectManager.CMakeRunConfiguration.
+ minecraft-launcher
+ false
+ true
+ true
+ true
+ G:/Documents/The_Grand_Archives/Qt_projects/minecraft-launcher/build/Desktop_Qt_6_9_2_MinGW_64_bit-Debug
+
+ 1
+
+ 1
+
+
+ 0
+ Развёртывание
+ Развёртывание
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+
+
+
+
+
+
+
+ false
+
+ true
+ ApplicationManagerPlugin.Deploy.CMakePackageStep
+
+
+ install-package --acknowledge
+ true
+ Install Application Manager package
+ ApplicationManagerPlugin.Deploy.InstallPackageStep
+
+
+
+
+
+
+
+ 2
+ Развёртывание
+ Развёртывание
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ApplicationManagerPlugin.Deploy.Configuration
+
+ 2
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+ minecraft-launcher
+ CMakeProjectManager.CMakeRunConfiguration.
+ minecraft-launcher
+ false
+ true
+ true
+ true
+ G:/Documents/The_Grand_Archives/Qt_projects/minecraft-launcher/build/Desktop_Qt_6_9_2_MinGW_64_bit-Debug
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 1
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 22
+
+
+ Version
+ 22
+
+
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..115a22b
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,10 @@
+#include "mainwindow.h"
+#include
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ MainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/mainwindow.cpp b/mainwindow.cpp
new file mode 100644
index 0000000..81b31b6
--- /dev/null
+++ b/mainwindow.cpp
@@ -0,0 +1,170 @@
+#include "mainwindow.h"
+#include "ui_mainwindow.h" // Подключаем сгенерированный заголовочный файл
+#include "settingsdialog.h"
+
+#include
+#include
+#include
+#include
+#include // Для диалога выбора
+#include // Для проверки файла
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+ , ui(new Ui::MainWindow) // Инициализируем указатель на UI
+{
+ ui->setupUi(this); // Загружаем интерфейс из .ui файла
+
+ // Начальная настройка виджетов
+ ui->progressBar->setRange(0, 0); // Неопределенный прогресс-бар
+ ui->progressBar->setVisible(false);
+
+ // Инициализация логики
+ settings = new QSettings("GaleonDev", "MinecraftLauncher", this);
+ process = new QProcess(this);
+
+ // Подключаем сигналы от процесса (это делается вручную)
+ connect(process, &QProcess::readyReadStandardOutput, this, &MainWindow::readProcessOutput);
+ connect(process, &QProcess::readyReadStandardError, this, &MainWindow::readProcessOutput);
+ connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onProcessFinished(int, QProcess::ExitStatus)));
+ connect(process, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(onProcessError(QProcess::ProcessError)));
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui; // Освобождаем память от объекта UI
+}
+
+void MainWindow::on_launchButton_clicked()
+{
+ QString minecraftPath = getMinecraftPath();
+ if (minecraftPath.isEmpty()) {
+ QMessageBox::warning(this, "Ошибка", "Не удалось найти директорию .minecraft.");
+ return;
+ }
+
+ // 1. Находим папку с версиями
+ QString versionsPath = minecraftPath + "/versions";
+ QDir versionsDir(versionsPath);
+ if (!versionsDir.exists()) {
+ QMessageBox::warning(this, "Ошибка", "Папка 'versions' не найдена!");
+ return;
+ }
+
+ // 2. Получаем список всех папок внутри 'versions' (это и есть наши версии)
+ QStringList versionList = versionsDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
+ if (versionList.isEmpty()) {
+ QMessageBox::warning(this, "Ошибка", "Не найдено ни одной установленной версии Minecraft.");
+ return;
+ }
+
+ // 3. Предлагаем пользователю выбрать версию
+ bool ok;
+ QString selectedVersion = QInputDialog::getItem(this, "Выбор версии",
+ "Выберите версию Minecraft для запуска:",
+ versionList, 0, false, &ok);
+
+ // 4. Если пользователь сделал выбор (нажал "OK" и версия не пустая)
+ if (ok && !selectedVersion.isEmpty()) {
+ // Формируем путь к .jar файлу. Например: /.minecraft/versions/1.19.2/1.19.2.jar
+ QString jarPath = versionsPath + "/" + selectedVersion + "/" + selectedVersion + ".jar";
+
+ // Проверяем, что .jar файл действительно существует
+ QFileInfo jarFile(jarPath);
+ if (!jarFile.exists() || !jarFile.isFile()) {
+ QMessageBox::critical(this, "Ошибка запуска",
+ "Не удалось найти запускаемый .jar файл для версии " + selectedVersion + ".\n"
+ "Проверьте целостность файлов игры.\n"
+ "Ожидаемый путь: " + jarPath);
+ return;
+ }
+
+ // 5. Запускаем игру
+ QString javaPath = "java"; // Java должна быть в системной переменной PATH
+ QStringList arguments;
+ arguments << "-jar" << jarPath << "net.fabricmc.loader.impl.launch.knot.KnotClient";
+
+ ui->logOutput->appendPlainText("Запуск Minecraft версии: " + selectedVersion);
+ process->start(javaPath, arguments);
+ ui->progressBar->setVisible(true);
+ }
+}
+
+void MainWindow::on_modsFolderButton_clicked()
+{
+ QString minecraftPath = getMinecraftPath();
+ if (minecraftPath.isEmpty()) {
+ QMessageBox::warning(this, "Ошибка", "Не удалось найти директорию .minecraft.");
+ return;
+ }
+ QString modsPath = minecraftPath + "/mods";
+ QDesktopServices::openUrl(QUrl::fromLocalFile(modsPath));
+}
+
+void MainWindow::on_settingsButton_clicked()
+{
+ SettingsDialog dialog(this);
+ dialog.exec();
+}
+
+void MainWindow::on_updateModsButton_clicked()
+{
+ QString gitRepoUrl = settings->value("gitRepoUrl").toString();
+ if (gitRepoUrl.isEmpty()) {
+ QMessageBox::information(this, "Настройки", "Пожалуйста, укажите URL Git-репозитория в настройках.");
+ return;
+ }
+
+ QString minecraftPath = getMinecraftPath();
+ if (minecraftPath.isEmpty()) {
+ QMessageBox::warning(this, "Ошибка", "Не удалось найти директорию .minecraft.");
+ return;
+ }
+ QString modsPath = minecraftPath + "/mods";
+ QDir modsDir(modsPath);
+
+ if (!modsDir.exists(".git")) {
+ ui->logOutput->appendPlainText("Клонирование модов из " + gitRepoUrl);
+ process->start("git", QStringList() << "clone" << gitRepoUrl << modsPath);
+ } else {
+ ui->logOutput->appendPlainText("Обновление модов...");
+ process->setWorkingDirectory(modsPath);
+ process->start("git", QStringList() << "pull");
+ }
+ ui->progressBar->setVisible(true);
+}
+
+void MainWindow::onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ ui->progressBar->setVisible(false);
+ if (exitStatus == QProcess::CrashExit) {
+ ui->logOutput->appendPlainText("Процесс завершился с ошибкой.");
+ } else {
+ ui->logOutput->appendPlainText("Процесс успешно завершен с кодом " + QString::number(exitCode));
+ }
+}
+
+void MainWindow::onProcessError(QProcess::ProcessError error)
+{
+ ui->progressBar->setVisible(false);
+ ui->logOutput->appendPlainText("Ошибка запуска процесса: " + process->errorString());
+}
+
+void MainWindow::readProcessOutput()
+{
+ ui->logOutput->appendPlainText(process->readAllStandardOutput());
+ ui->logOutput->appendPlainText(process->readAllStandardError());
+}
+
+QString MainWindow::getMinecraftPath()
+{
+ QString path;
+#if defined(Q_OS_WIN)
+ path = QDir::homePath() + "/AppData/Roaming/.minecraft";
+#elif defined(Q_OS_MAC)
+ path = QDir::homePath() + "/Library/Application Support/minecraft";
+#else
+ path = QDir::homePath() + "/.minecraft";
+#endif
+ return path;
+}
diff --git a/mainwindow.h b/mainwindow.h
new file mode 100644
index 0000000..0bce635
--- /dev/null
+++ b/mainwindow.h
@@ -0,0 +1,41 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include
+#include
+#include
+
+// Предварительное объявление класса, сгенерированного из mainwindow.ui
+QT_BEGIN_NAMESPACE
+namespace Ui { class MainWindow; }
+QT_END_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget *parent = nullptr);
+ ~MainWindow();
+
+private slots:
+ // Слоты для кнопок (автоматически подключаются по имени: on_<имя_объекта>_<сигнал>)
+ void on_launchButton_clicked();
+ void on_modsFolderButton_clicked();
+ void on_updateModsButton_clicked();
+ void on_settingsButton_clicked();
+
+ // Слоты для QProcess (подключаются вручную)
+ void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
+ void onProcessError(QProcess::ProcessError error);
+ void readProcessOutput();
+
+private:
+ QString getMinecraftPath();
+
+ Ui::MainWindow *ui; // Указатель на объект интерфейса
+ QProcess *process;
+ QSettings *settings;
+};
+
+#endif // MAINWINDOW_H
diff --git a/mainwindow.ui b/mainwindow.ui
new file mode 100644
index 0000000..9cce9c2
--- /dev/null
+++ b/mainwindow.ui
@@ -0,0 +1,68 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 600
+ 400
+
+
+
+ Minecraft Лаунчер
+
+
+
+ -
+
+
+ Запустить Minecraft
+
+
+
+ -
+
+
+ Открыть папку с модами
+
+
+
+ -
+
+
+ Обновить моды из Git
+
+
+
+ -
+
+
+ Настройки
+
+
+
+ -
+
+
+ 0
+
+
+ false
+
+
+
+ -
+
+
+ true
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/settingsdialog.cpp b/settingsdialog.cpp
new file mode 100644
index 0000000..d32c6f3
--- /dev/null
+++ b/settingsdialog.cpp
@@ -0,0 +1,27 @@
+#include "settingsdialog.h"
+#include "ui_settingsdialog.h"
+
+SettingsDialog::SettingsDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::SettingsDialog)
+{
+ ui->setupUi(this);
+
+ settings = new QSettings("MyCompany", "MinecraftLauncher", this);
+ ui->gitRepoEdit->setText(settings->value("gitRepoUrl").toString());
+
+ // Сигналы от кнопок (OK, Cancel) автоматически подключены к слотам accept() и reject()
+ // благодаря QDialogButtonBox и .ui файлу
+}
+
+SettingsDialog::~SettingsDialog()
+{
+ delete ui;
+}
+
+// Эта функция будет вызвана при нажатии кнопки "OK"
+void SettingsDialog::accept()
+{
+ settings->setValue("gitRepoUrl", ui->gitRepoEdit->text());
+ QDialog::accept(); // Вызываем базовую реализацию, которая закрывает диалог
+}
diff --git a/settingsdialog.h b/settingsdialog.h
new file mode 100644
index 0000000..a72cfca
--- /dev/null
+++ b/settingsdialog.h
@@ -0,0 +1,27 @@
+#ifndef SETTINGSDIALOG_H
+#define SETTINGSDIALOG_H
+
+#include
+#include
+
+namespace Ui {
+class SettingsDialog;
+}
+
+class SettingsDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit SettingsDialog(QWidget *parent = nullptr);
+ ~SettingsDialog();
+
+private slots:
+ void accept(); // Переопределяем слот, чтобы сохранить настройки
+
+private:
+ Ui::SettingsDialog *ui;
+ QSettings *settings;
+};
+
+#endif // SETTINGSDIALOG_H
diff --git a/settingsdialog.ui b/settingsdialog.ui
new file mode 100644
index 0000000..8965f66
--- /dev/null
+++ b/settingsdialog.ui
@@ -0,0 +1,74 @@
+
+
+ SettingsDialog
+
+
+
+ 0
+ 0
+ 400
+ 120
+
+
+
+ Настройки
+
+
+ -
+
+
+ URL Git-репозитория с модами:
+
+
+
+ -
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ SettingsDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ SettingsDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
\ No newline at end of file