Files
minecraft-launcher/main.cpp

259 lines
9.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <fstream>
#include <sstream>
// Подключение зависимостей
#include <curl/curl.h> // Для 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<std::streamsize>::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<json> 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<std::streamsize>::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;
}
}