From 1250af21a139953981130070041e79f0ea696a84 Mon Sep 17 00:00:00 2001 From: galeon Date: Sun, 21 Sep 2025 23:45:27 +0300 Subject: [PATCH] 1 --- .gitignore | 60 ------- .vscode/launch.json | 7 - .vscode/tasks.json | 29 --- main.cpp | 427 +++++++++++++++++++++----------------------- 4 files changed, 200 insertions(+), 323 deletions(-) delete mode 100644 .gitignore delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/tasks.json diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 3a70b02..0000000 --- a/.gitignore +++ /dev/null @@ -1,60 +0,0 @@ -# ---> C++ -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app - -# ---> Java -# Compiled class file -*.class - -# Log file -*.log - -# BlueJ files -*.ctxt - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* -replay_pid* - diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 5c7247b..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [] -} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index d22751d..0000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "tasks": [ - { - "type": "cppbuild", - "label": "C/C++: clang++ сборка активного файла", - "command": "/usr/bin/clang++", - "args": [ - "-fcolor-diagnostics", - "-fansi-escape-codes", - "-g", - "${file}", - "-o", - "${fileDirname}/${fileBasenameNoExtension}" - ], - "options": { - "cwd": "${fileDirname}" - }, - "problemMatcher": [ - "$gcc" - ], - "group": { - "kind": "build", - "isDefault": true - }, - "detail": "Задача создана отладчиком." - } - ], - "version": "2.0.0" -} \ No newline at end of file diff --git a/main.cpp b/main.cpp index bf6c3a8..44c0812 100644 --- a/main.cpp +++ b/main.cpp @@ -1,42 +1,208 @@ #include #include -#include -#include -#include -#include +#include // Для system() +#include // Для работы с файлами +#include // Для работы с файловой системой (проверки папок) +#include // Для очистки потока ввода -// Подключение зависимостей -#include // Для HTTP-запросов -#include "json.hpp" // Для парсинга JSON +// Пространство имен для работы с файловой системой +namespace fs = std::filesystem; -// Для удобства используем пространство имен для JSON -using json = nlohmann::json; +// Имя файла для хранения URL репозитория +const std::string CONFIG_FILE = "launcher_config.txt"; -// Прототипы функций -void showMenu(); -std::string getMinecraftPath(); -void openModsFolder(); -void launchMinecraft(); -void downloadMods(); - -// Функция для сохранения данных, полученных от curl, в строку -static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) { - ((std::string*)userp)->append((char*)contents, size * nmemb); - return size * nmemb; +// Функция для получения пути к папке .minecraft на macOS +// На Mac путь обычно: /Users/ВАШЕ_ИМЯ_ПОЛЬЗОВАТЕЛЯ/Library/Application Support/minecraft +std::string getMinecraftPath() { + // Получаем домашнюю директорию пользователя из переменных окружения + const char* homeDir = getenv("HOME"); + if (homeDir == nullptr) { + std::cerr << "Ошибка: Не удалось определить домашнюю директорию." << std::endl; + return ""; + } + return std::string(homeDir) + "/Library/Application Support/minecraft"; } +// Функция для очистки экрана консоли +void clearScreen() { + // Простая команда для очистки экрана в Unix-подобных системах (macOS, Linux) + system("clear"); +} + +// Функция для отображения главного меню +void showMenu() { + clearScreen(); + std::cout << "========= Minecraft Launcher (macOS) =========\n"; + std::cout << "1. Запустить Minecraft\n"; + std::cout << "2. Открыть папку с модами (mods)\n"; + std::cout << "3. Указать URL Git-репозитория для модов\n"; + std::cout << "4. Загрузить/Обновить моды из репозитория\n"; + std::cout << "5. Выход\n"; + std::cout << "============================================\n"; + std::cout << "Выберите опцию: "; +} + +// Функция для приостановки выполнения до нажатия Enter +void pause() { + std::cout << "\nНажмите Enter для продолжения..."; + // Очищаем буфер ввода перед ожиданием + std::cin.ignore(std::numeric_limits::max(), '\n'); + std::cin.get(); +} + +// 1. Функция для запуска Minecraft +void launchMinecraft() { + std::cout << "\nЗапускаем Minecraft...\n"; + // Используем стандартную для macOS команду 'open' для запуска приложения + // Предполагается, что Minecraft установлен в стандартной папке /Applications + int result = system("open -a Minecraft.app"); + if (result != 0) { + std::cerr << "Ошибка: Не удалось запустить Minecraft. Убедитесь, что игра установлена в /Applications.\n"; + } + pause(); +} + +// 2. Функция для открытия папки с модами +void openModsFolder() { + std::string minecraftPath = getMinecraftPath(); + if (minecraftPath.empty()) { + pause(); + return; + } + + fs::path modsPath = minecraftPath; + modsPath /= "mods"; + + // Создаем папку mods, если она не существует + if (!fs::exists(modsPath)) { + std::cout << "Папка 'mods' не найдена. Создаем ее...\n"; + try { + fs::create_directories(modsPath); + } catch (const fs::filesystem_error& e) { + std::cerr << "Ошибка при создании папки 'mods': " << e.what() << std::endl; + pause(); + return; + } + } + + std::cout << "Открываем папку: " << modsPath.string() << "\n"; + + // Команда для открытия папки в Finder. Используем кавычки для безопасности. + std::string command = "open \"" + modsPath.string() + "\""; + system(command.c_str()); + pause(); +} + +// 3. Функция для сохранения URL Git-репозитория +void setGitRepository() { + std::string repoUrl; + std::cout << "\nВведите полный URL Git-репозитория (например, https://github.com/user/repo.git):\n"; + std::cin.ignore(std::numeric_limits::max(), '\n'); // Очистка буфера перед считыванием строки + std::getline(std::cin, repoUrl); + + // Открываем файл для записи. Старое содержимое будет стерто. + std::ofstream configFile(CONFIG_FILE); + if (!configFile.is_open()) { + std::cerr << "Ошибка: Не удалось открыть файл конфигурации для записи.\n"; + } else { + configFile << repoUrl; + std::cout << "URL репозитория успешно сохранен.\n"; + } + configFile.close(); + pause(); +} + +// 4. Функция для загрузки или обновления модов +void updateModsFromGit() { + std::cout << "\nНачинаем процесс загрузки/обновления модов...\n"; + + // Шаг 1: Чтение URL из файла конфигурации + std::ifstream configFile(CONFIG_FILE); + std::string repoUrl; + if (!configFile.is_open()) { + std::cerr << "Ошибка: Файл конфигурации не найден. Сначала укажите URL репозитория (опция 3).\n"; + pause(); + return; + } + std::getline(configFile, repoUrl); + configFile.close(); + + if (repoUrl.empty()) { + std::cerr << "Ошибка: URL репозитория не указан в файле конфигурации. Сначала укажите URL (опция 3).\n"; + pause(); + return; + } + + std::cout << "Используется репозиторий: " << repoUrl << std::endl; + + // Шаг 2: Определение пути к папке mods + std::string minecraftPath = getMinecraftPath(); + if (minecraftPath.empty()) { + pause(); + return; + } + fs::path modsPath = minecraftPath; + modsPath /= "mods"; + + // Создаем папку mods, если она не существует + if (!fs::exists(modsPath)) { + std::cout << "Папка 'mods' не найдена. Создаем ее...\n"; + try { + fs::create_directories(modsPath); + } catch (const fs::filesystem_error& e) { + std::cerr << "Ошибка при создании папки 'mods': " << e.what() << std::endl; + pause(); + return; + } + } + + // Шаг 3: Проверка, является ли папка mods уже Git-репозиторием + fs::path gitPath = modsPath; + gitPath /= ".git"; + + std::string command; + if (fs::exists(gitPath)) { + // Если папка .git существует, значит это репозиторий. Делаем pull. + std::cout << "Обнаружен существующий репозиторий. Выполняем 'git pull' для обновления...\n"; + // Переходим в папку mods и выполняем git pull + command = "cd \"" + modsPath.string() + "\" && git pull"; + } else { + // Если папки .git нет, проверяем, пуста ли папка mods + if (!fs::is_empty(modsPath)) { + std::cerr << "Внимание: Папка 'mods' не является Git-репозиторием, но содержит файлы.\n"; + std::cerr << "Для предотвращения потери данных, клонирование не будет выполнено.\n"; + std::cerr << "Пожалуйста, очистите папку 'mods' вручную и попробуйте снова.\n"; + pause(); + return; + } + // Папка пуста, клонируем репозиторий + std::cout << "Папка 'mods' пуста. Выполняем 'git clone' для загрузки модов...\n"; + command = "git clone " + repoUrl + " \"" + modsPath.string() + "\""; + } + + // Шаг 4: Выполнение команды Git + int result = system(command.c_str()); + if (result == 0) { + std::cout << "Операция успешно завершена!\n"; + } else { + std::cerr << "Ошибка при выполнении команды Git. Убедитесь, что Git установлен и URL репозитория корректен.\n"; + } + pause(); +} + + int main() { - int choice; - do { + int choice = 0; + while (choice != 5) { showMenu(); - std::cout << "Введите ваш выбор: "; std::cin >> choice; // Проверка на корректность ввода if (std::cin.fail()) { - std::cin.clear(); // Сброс флагов ошибок - std::cin.ignore(std::numeric_limits::max(), '\n'); // Очистка буфера ввода - choice = -1; // Присваиваем неверное значение для вывода ошибки + std::cin.clear(); // Сброс флага ошибки + // Пропуск некорректного ввода + std::cin.ignore(std::numeric_limits::max(), '\n'); + choice = 0; // Присваиваем неверное значение для повторного входа в цикл } switch (choice) { @@ -47,213 +213,20 @@ int main() { openModsFolder(); break; case 3: - downloadMods(); + setGitRepository(); break; case 4: - std::cout << "Выход из программы." << std::endl; + updateModsFromGit(); + break; + case 5: + std::cout << "Выход из программы...\n"; break; default: - std::cout << "Неверный выбор. Пожалуйста, попробуйте снова." << std::endl; + std::cout << "\nНеверный выбор. Пожалуйста, попробуйте снова.\n"; + pause(); break; } - std::cout << std::endl; - } while (choice != 4); + } return 0; -} - -// Отображает главное меню лаунчера -void showMenu() { - std::cout << "========== Minecraft C++ Launcher ==========" << std::endl; - std::cout << "1. Запустить Minecraft" << std::endl; - std::cout << "2. Открыть папку с модами" << std::endl; - std::cout << "3. Загрузить моды с GitHub" << std::endl; - std::cout << "4. Выход" << std::endl; - std::cout << "==========================================" << std::endl; -} - -// Определяет путь к директории .minecraft в зависимости от ОС -std::string getMinecraftPath() { - std::string path; -#ifdef _WIN32 - // Для Windows путь находится в %APPDATA%\.minecraft - char* appdata = nullptr; - size_t len; - _dupenv_s(&appdata, &len, "APPDATA"); - if (appdata) { - path = std::string(appdata) + "\\.minecraft"; - free(appdata); - } -#elif __APPLE__ - // Для macOS - path = std::string(getenv("HOME")) + "/Library/Application Support/minecraft"; -#else - // Для Linux - path = std::string(getenv("HOME")) + "/.minecraft"; -#endif - return path; -} - -// Открывает папку mods -void openModsFolder() { - std::string minecraftPath = getMinecraftPath(); - if (minecraftPath.empty()) { - std::cout << "Не удалось найти директорию .minecraft." << std::endl; - return; - } - - std::string modsPath = minecraftPath + "/mods"; - std::cout << "Путь к папке с модами: " << modsPath << std::endl; - std::cout << "Открытие папки..." << std::endl; - - std::string command; -#ifdef _WIN32 - command = "explorer " + modsPath; -#elif __APPLE__ - command = "open " + modsPath; -#else - command = "xdg-open " + modsPath; -#endif - - // system() выполняет команду в системной консоли - int result = system(command.c_str()); - if (result != 0) { - std::cerr << "Не удалось открыть папку. Убедитесь, что она существует." << std::endl; - } -} - -// Запускает официальный лаунчер Minecraft -void launchMinecraft() { - std::cout << "Запуск официального лаунчера Minecraft..." << std::endl; - std::string command; -#ifdef _WIN32 - // Эта команда предполагает, что лаунчер установлен в стандартное место - command = "start \"\" \"%ProgramFiles(x86)%\\Minecraft Launcher\\MinecraftLauncher.exe\""; -#elif __APPLE__ - command = "open /Applications/Minecraft.app"; -#else - // Пользователям Linux, возможно, потребуется настроить эту команду - command = "minecraft-launcher"; -#endif - - int result = system(command.c_str()); - if (result != 0) { - std::cerr << "Не удалось запустить Minecraft. Убедитесь, что официальный лаунчер установлен." << std::endl; - } -} - -// Функция для загрузки модов из GitHub репозитория -void downloadMods() { - std::string repo_owner, repo_name; - std::cout << "Введите владельца репозитория GitHub (например, 'octocat'): "; - std::cin >> repo_owner; - std::cout << "Введите имя репозитория (например, 'Hello-World'): "; - std::cin >> repo_name; - - std::string apiUrl = "https://api.github.com/repos/" + repo_owner + "/" + repo_name + "/contents/"; - std::string readBuffer; - - CURL *curl = curl_easy_init(); - if (!curl) { - std::cerr << "Ошибка инициализации cURL." << std::endl; - return; - } - - // Настройка cURL для запроса к GitHub API - curl_easy_setopt(curl, CURLOPT_URL, apiUrl.c_str()); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); - curl_easy_setopt(curl, CURLOPT_USERAGENT, "Minecraft-C++-Launcher/1.0"); // GitHub требует User-Agent - - CURLcode res = curl_easy_perform(curl); - if (res != CURLE_OK) { - std::cerr << "Ошибка запроса к GitHub API: " << curl_easy_strerror(res) << std::endl; - curl_easy_cleanup(curl); - return; - } - - // Проверка HTTP статуса - long http_code = 0; - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); - if (http_code != 200) { - std::cerr << "Репозиторий не найден или API недоступен. HTTP статус: " << http_code << std::endl; - curl_easy_cleanup(curl); - return; - } - - curl_easy_cleanup(curl); - - // Парсинг JSON ответа - try { - json repo_files = json::parse(readBuffer); - std::vector jar_files; - - // Фильтруем только .jar файлы - for (const auto& file : repo_files) { - std::string filename = file["name"]; - if (filename.size() > 4 && filename.substr(filename.size() - 4) == ".jar") { - jar_files.push_back(file); - } - } - - if (jar_files.empty()) { - std::cout << "В репозитории не найдено .jar файлов." << std::endl; - return; - } - - // Отображаем список модов для выбора - std::cout << "Найденные моды (.jar):" << std::endl; - for (int i = 0; i < jar_files.size(); ++i) { - std::cout << i + 1 << ". " << jar_files[i]["name"] << std::endl; - } - - int mod_choice; - std::cout << "Выберите мод для загрузки (введите номер): "; - std::cin >> mod_choice; - - if (std::cin.fail() || mod_choice < 1 || mod_choice > jar_files.size()) { - std::cin.clear(); - std::cin.ignore(std::numeric_limits::max(), '\n'); - std::cerr << "Неверный выбор." << std::endl; - return; - } - - // Получаем URL для загрузки файла - std::string download_url = jar_files[mod_choice - 1]["download_url"]; - std::string mod_filename = jar_files[mod_choice - 1]["name"]; - std::string save_path = getMinecraftPath() + "/mods/" + mod_filename; - - std::cout << "Загрузка '" << mod_filename << "' в " << save_path << "..." << std::endl; - - // Используем cURL для скачивания файла - curl = curl_easy_init(); - if (curl) { - FILE *fp; - errno_t err = fopen_s(&fp, save_path.c_str(), "wb"); // Используем fopen_s для безопасности - if (err != 0 || fp == NULL) { - std::cerr << "Не удалось создать файл для сохранения мода." << std::endl; - curl_easy_cleanup(curl); - return; - } - - curl_easy_setopt(curl, CURLOPT_URL, download_url.c_str()); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL); // Используем стандартную функцию записи - curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); - curl_easy_setopt(curl, CURLOPT_USERAGENT, "Minecraft-C++-Launcher/1.0"); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // Разрешаем редиректы - - res = curl_easy_perform(curl); - fclose(fp); // Закрываем файл - - if (res != CURLE_OK) { - std::cerr << "Ошибка при загрузке мода: " << curl_easy_strerror(res) << std::endl; - } else { - std::cout << "Мод успешно загружен!" << std::endl; - } - curl_easy_cleanup(curl); - } - - } catch (json::parse_error& e) { - std::cerr << "Ошибка парсинга JSON: " << e.what() << std::endl; - } } \ No newline at end of file