Files
minecraft-launcher/minecraft-launcher.cpp

272 lines
11 KiB
C++
Raw Permalink 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> // Для system()
#include <filesystem> // C++17 для работы с файловой системой
#include <fstream> // Для работы с файлами конфигурации
// Пространство имен для удобства работы с файловой системой
namespace fs = std::filesystem;
// Имя файла конфигурации для хранения URL репозитория
const std::string CONFIG_FILE = "launcher_config.txt";
// --- Функции для работы с конфигурацией ---
// Функция для сохранения URL Git-репозитория в файл
void saveGitRepository(const std::string& repoUrl) {
std::ofstream configFile(CONFIG_FILE);
if (configFile.is_open()) {
configFile << repoUrl;
configFile.close();
} else {
std::cerr << "Ошибка: Не удалось открыть файл конфигурации для записи." << std::endl;
}
}
// Функция для загрузки URL Git-репозитория из файла
std::string loadGitRepository() {
std::ifstream configFile(CONFIG_FILE);
std::string repoUrl;
if (configFile.is_open()) {
std::getline(configFile, repoUrl);
configFile.close();
}
return repoUrl;
}
// --- Кроссплатформенные функции ---
// Функция для получения пути к папке .minecraft в зависимости от ОС
fs::path getMinecraftPath() {
fs::path minecraftPath;
#if defined(_WIN32)
// Для Windows путь обычно находится в %APPDATA%\.minecraft
char* appdata = nullptr;
size_t len;
_dupenv_s(&appdata, &len, "APPDATA");
if (appdata != nullptr) {
minecraftPath = fs::path(appdata) / ".minecraft";
free(appdata);
}
#elif defined(__linux__)
// Для Linux путь обычно находится в ~/.minecraft
char* home = getenv("HOME");
if (home != nullptr) {
minecraftPath = fs::path(home) / ".minecraft";
}
#elif defined(__APPLE__)
// Для macOS путь находится в ~/Library/Application Support/minecraft
char* home = getenv("HOME");
if (home != nullptr) {
minecraftPath = fs::path(home) / "Library" / "Application Support" / "minecraft";
}
#else
std::cerr << "Неизвестная операционная система!" << std::endl;
#endif
return minecraftPath;
}
// Функция для открытия папки в файловом менеджере по умолчанию
void openFolder(const fs::path& folderPath) {
if (!fs::exists(folderPath)) {
std::cout << "Папка не существует. Создание папки: " << folderPath.string() << std::endl;
try {
fs::create_directories(folderPath);
} catch (const fs::filesystem_error& e) {
std::cerr << "Ошибка при создании папки: " << e.what() << std::endl;
return;
}
}
std::string command;
#if defined(_WIN32)
command = "explorer \"" + folderPath.string() + "\"";
#elif defined(__linux__)
command = "xdg-open \"" + folderPath.string() + "\"";
#elif defined(__APPLE__)
command = "open \"" + folderPath.string() + "\"";
#else
std::cerr << "Команда для открытия папки на данной ОС не поддерживается." << std::endl;
return;
#endif
// Выполнение системной команды
system(command.c_str());
}
// Функция для очистки содержимого папки
void clearFolder(const fs::path& folderPath) {
if (!fs::exists(folderPath) || !fs::is_directory(folderPath)) {
return; // Если папки нет, ничего не делаем
}
for (const auto& entry : fs::directory_iterator(folderPath)) {
try {
fs::remove_all(entry.path());
} catch (const fs::filesystem_error& e) {
std::cerr << "Не удалось удалить " << entry.path() << ": " << e.what() << std::endl;
}
}
}
// --- Функции меню ---
// Функция для открытия папки с модами
void openModsFolderAction() {
fs::path minecraftPath = getMinecraftPath();
if (minecraftPath.empty()) {
std::cerr << "Не удалось определить путь к папке Minecraft." << std::endl;
return;
}
fs::path modsPath = minecraftPath / "mods";
std::cout << "Путь к папке модов: " << modsPath.string() << std::endl;
openFolder(modsPath);
}
// Функция для установки URL репозитория
void setGitRepositoryAction() {
std::string repoUrl;
std::cout << "\nВведите URL Git-репозитория (например, https://github.com/user/repo.git):" << std::endl;
std::getline(std::cin >> std::ws, repoUrl); // std::ws для очистки буфера от пробельных символов
if (repoUrl.empty()) {
std::cout << "URL не может быть пустым." << std::endl;
return;
}
saveGitRepository(repoUrl);
std::cout << "URL репозитория успешно сохранен." << std::endl;
}
// Функция для загрузки модов из Git
void downloadModsAction() {
std::string repoUrl = loadGitRepository();
if (repoUrl.empty()) {
std::cout << "URL Git-репозитория не настроен. Пожалуйста, сначала установите его (пункт 2)." << std::endl;
return;
}
fs::path modsPath = getMinecraftPath() / "mods";
std::cout << "Папка для модов: " << modsPath.string() << std::endl;
// Убедимся, что папка существует
if (!fs::exists(modsPath)) {
try {
fs::create_directories(modsPath);
} catch (const fs::filesystem_error& e) {
std::cerr << "Ошибка при создании папки mods: " << e.what() << std::endl;
return;
}
}
// Запрос подтверждения перед очисткой
char confirmation;
std::cout << "\nВНИМАНИЕ! Все существующие файлы в папке 'mods' будут удалены." << std::endl;
std::cout << "Продолжить? (y/n): ";
std::cin >> confirmation;
// Проверка, что пользователь ввел 'y' или 'Y'
if (confirmation != 'y' && confirmation != 'Y') {
std::cout << "Загрузка отменена." << std::endl;
// Очистка буфера ввода после чтения символа
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return;
}
// Очистка буфера ввода
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Очистка папки mods..." << std::endl;
clearFolder(modsPath);
std::cout << "Папка очищена." << std::endl;
// Формирование команды для клонирования репозитория
// Клонируем содержимое репозитория прямо в папку mods
std::string command = "git clone " + repoUrl + " \"" + modsPath.string() + "\"";
std::cout << "\nВыполнение команды: " << command << std::endl;
std::cout << "Начинается загрузка модов. Это может занять некоторое время..." << std::endl;
int result = system(command.c_str());
if (result == 0) {
std::cout << "Моды успешно загружены!" << std::endl;
} else {
std::cerr << "Произошла ошибка при загрузке модов. Убедитесь, что Git установлен и URL репозитория верный." << std::endl;
}
}
// Отображение главного меню
void printMenu() {
std::cout << "\n--- Minecraft Mod Launcher ---" << std::endl;
std::cout << "1. Открыть папку с модами (.minecraft/mods)" << std::endl;
std::cout << "2. Указать/изменить URL Git-репозитория с модами" << std::endl;
std::cout << "3. Загрузить/обновить моды из Git-репозитория" << std::endl;
std::cout << "4. Выход" << std::endl;
std::cout << "-----------------------------" << std::endl;
std::string currentRepo = loadGitRepository();
if (currentRepo.empty()) {
std::cout << "Текущий репозиторий: не задан" << std::endl;
} else {
std::cout << "Текущий репозиторий: " << currentRepo << std::endl;
}
std::cout << "\nВведите ваш выбор: ";
}
// --- Главная функция программы ---
int main() {
// Установка кодировки консоли для корректного отображения кириллицы в Windows
#if defined(_WIN32)
system("chcp 65001 > nul");
#endif
int choice;
while (true) {
printMenu();
std::cin >> choice;
// Проверка на корректность ввода
if (std::cin.fail()) {
std::cout << "Ошибка: введите число." << std::endl;
std::cin.clear(); // Сброс флага ошибки
// Очистка буфера ввода до следующей новой строки
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
continue;
}
switch (choice) {
case 1:
openModsFolderAction();
break;
case 2:
setGitRepositoryAction();
break;
case 3:
downloadModsAction();
break;
case 4:
std::cout << "Выход из программы." << std::endl;
return 0;
default:
std::cout << "Неверный выбор. Пожалуйста, попробуйте снова." << std::endl;
break;
}
std::cout << "\nНажмите Enter для продолжения...";
// Очистка буфера перед ожиданием Enter
if (choice != 3 && choice !=2) {
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
std::cin.get();
}
return 0;
}