1
This commit is contained in:
60
.gitignore
vendored
60
.gitignore
vendored
@@ -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*
|
|
||||||
|
|
||||||
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
@@ -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": []
|
|
||||||
}
|
|
||||||
29
.vscode/tasks.json
vendored
29
.vscode/tasks.json
vendored
@@ -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"
|
|
||||||
}
|
|
||||||
427
main.cpp
427
main.cpp
@@ -1,42 +1,208 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <cstdlib> // Для system()
|
||||||
#include <cstdlib>
|
#include <fstream> // Для работы с файлами
|
||||||
#include <fstream>
|
#include <filesystem> // Для работы с файловой системой (проверки папок)
|
||||||
#include <sstream>
|
#include <limits> // Для очистки потока ввода
|
||||||
|
|
||||||
// Подключение зависимостей
|
// Пространство имен для работы с файловой системой
|
||||||
#include <curl/curl.h> // Для HTTP-запросов
|
namespace fs = std::filesystem;
|
||||||
#include "json.hpp" // Для парсинга JSON
|
|
||||||
|
|
||||||
// Для удобства используем пространство имен для JSON
|
// Имя файла для хранения URL репозитория
|
||||||
using json = nlohmann::json;
|
const std::string CONFIG_FILE = "launcher_config.txt";
|
||||||
|
|
||||||
// Прототипы функций
|
// Функция для получения пути к папке .minecraft на macOS
|
||||||
void showMenu();
|
// На Mac путь обычно: /Users/ВАШЕ_ИМЯ_ПОЛЬЗОВАТЕЛЯ/Library/Application Support/minecraft
|
||||||
std::string getMinecraftPath();
|
std::string getMinecraftPath() {
|
||||||
void openModsFolder();
|
// Получаем домашнюю директорию пользователя из переменных окружения
|
||||||
void launchMinecraft();
|
const char* homeDir = getenv("HOME");
|
||||||
void downloadMods();
|
if (homeDir == nullptr) {
|
||||||
|
std::cerr << "Ошибка: Не удалось определить домашнюю директорию." << std::endl;
|
||||||
// Функция для сохранения данных, полученных от curl, в строку
|
return "";
|
||||||
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
|
}
|
||||||
((std::string*)userp)->append((char*)contents, size * nmemb);
|
return std::string(homeDir) + "/Library/Application Support/minecraft";
|
||||||
return size * nmemb;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Функция для очистки экрана консоли
|
||||||
|
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<std::streamsize>::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<std::streamsize>::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 main() {
|
||||||
int choice;
|
int choice = 0;
|
||||||
do {
|
while (choice != 5) {
|
||||||
showMenu();
|
showMenu();
|
||||||
std::cout << "Введите ваш выбор: ";
|
|
||||||
std::cin >> choice;
|
std::cin >> choice;
|
||||||
|
|
||||||
// Проверка на корректность ввода
|
// Проверка на корректность ввода
|
||||||
if (std::cin.fail()) {
|
if (std::cin.fail()) {
|
||||||
std::cin.clear(); // Сброс флагов ошибок
|
std::cin.clear(); // Сброс флага ошибки
|
||||||
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // Очистка буфера ввода
|
// Пропуск некорректного ввода
|
||||||
choice = -1; // Присваиваем неверное значение для вывода ошибки
|
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||||
|
choice = 0; // Присваиваем неверное значение для повторного входа в цикл
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (choice) {
|
switch (choice) {
|
||||||
@@ -47,213 +213,20 @@ int main() {
|
|||||||
openModsFolder();
|
openModsFolder();
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
downloadMods();
|
setGitRepository();
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
std::cout << "Выход из программы." << std::endl;
|
updateModsFromGit();
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
std::cout << "Выход из программы...\n";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
std::cout << "Неверный выбор. Пожалуйста, попробуйте снова." << std::endl;
|
std::cout << "\nНеверный выбор. Пожалуйста, попробуйте снова.\n";
|
||||||
|
pause();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
std::cout << std::endl;
|
}
|
||||||
} while (choice != 4);
|
|
||||||
|
|
||||||
return 0;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user