#include #include #include #include #include #include // Подключение зависимостей #include // Для HTTP-запросов #include "json.hpp" // Для парсинга JSON // Для удобства используем пространство имен для JSON using json = nlohmann::json; // Прототипы функций 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; } int main() { int choice; do { showMenu(); std::cout << "Введите ваш выбор: "; std::cin >> choice; // Проверка на корректность ввода if (std::cin.fail()) { std::cin.clear(); // Сброс флагов ошибок std::cin.ignore(std::numeric_limits::max(), '\n'); // Очистка буфера ввода choice = -1; // Присваиваем неверное значение для вывода ошибки } switch (choice) { case 1: launchMinecraft(); break; case 2: openModsFolder(); break; case 3: downloadMods(); break; case 4: std::cout << "Выход из программы." << std::endl; break; default: std::cout << "Неверный выбор. Пожалуйста, попробуйте снова." << std::endl; 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; } }