commit 7a536662455f444acd2f0e3dbf572ce2ce21617d Author: Vladimir Zagainov Date: Sat May 23 18:04:36 2026 +0300 chore: init monorepo with launcher and server submodules diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a8d27cf --- /dev/null +++ b/.gitmodules @@ -0,0 +1,8 @@ +[submodule "launcher"] + path = launcher + url = ssh://git@gitea.mrixs.me:2222/Mrixs/MrixsCraft-launcher.git + branch = master +[submodule "server"] + path = server + url = ssh://git@gitea.mrixs.me:2222/Mrixs/MrixsCraft-server.git + branch = master diff --git a/docs/launcher/Specification.md b/docs/launcher/Specification.md new file mode 100644 index 0000000..6c81267 --- /dev/null +++ b/docs/launcher/Specification.md @@ -0,0 +1,128 @@ +# Спецификация архитектуры Minecraft лаунчера + +## 1. Общие сведения +* **Язык программирования:** Go (Golang) +* **GUI-библиотека:** Fyne +* **Целевые ОС:** Windows, macOS, Linux (кроссплатформенная компиляция) +* **Тип сервера:** Приватный мультисерверный проект (с поддержкой разных модпаков и версий игры) + +## 2. Ключевые модули лаунчера (Core Modules) + +### 2.1. Модуль авторизации (Auth Manager) +* **Протокол:** Yggdrasil API (кастомный сервер). +* **Инъекция:** Использование `authlib-injector.jar` для перенаправления запросов клиента с серверов Mojang на приватный Yggdrasil-сервер. +* **Сохранение сессии:** Локальное хранение `accessToken` и `clientToken` в зашифрованном или скрытом JSON-файле (например, `session.json`). +* **Жизненный цикл:** При запуске лаунчер выполняет `/validate` или `/refresh`. При успехе пропускает экран логина, при неудаче запрашивает пароль. + +### 2.2. Модуль синхронизации файлов (Sync & Download Manager) +* **Манифест:** Скачивание `manifest.json` с описанием структуры файлов (ассеты, библиотеки, моды, конфиги). +* **Хэширование:** Использование алгоритма **SHA-1** для сверки локальных файлов с манифестом. +* **Многопоточность:** Асинхронная загрузка недостающих/поврежденных файлов (горутины + воркер-пулы). +* **Разрешение конфликтов:** Если в папке `mods/` найден файл, которого нет в манифесте, он **не удаляется безвозвратно**, а перемещается в папку `mods_backup/` для предотвращения крашей игры (Soft Deletion/Self-healing). + +### 2.3. Модуль управления Java (JRE Manager) +* **Изоляция:** Лаунчер загружает и использует собственные портативные версии Java (8, 17, 21), не завися от установленной в ОС. +* **Логика:** Манифест сервера указывает требуемую версию Java (например, `java_version: 21`). Лаунчер проверяет наличие папки `Java/21/bin/java` внутри своей рабочей директории (см. раздел 4). Если ее нет — скачивает архив, распаковывает и выдает права на исполнение (для UNIX-систем). + +### 2.4. Модуль запуска (Launch Engine) +* **Агностичность:** Лаунчер не привязан к конкретному Mod Loader'у (Vanilla, Fabric, Forge). +* **Генерация аргументов:** Манифест предоставляет шаблоны `mainClass` и `gameArgs` (массив строк). +* **Интерполяция:** Замена псевдопеременных в строке запуска перед стартом: + * `${player_name}` -> Никнейм игрока + * `${auth_uuid}` -> UUID сессии + * `${auth_access_token}` -> Токен Yggdrasil + * `${classpath}` -> Склейка путей ко всем `.jar` библиотекам +* Обязательное внедрение аргумента: `-javaagent:<путь>/authlib-injector.jar=`. + +### 2.5. Модуль автообновления (Self-Updater) +* **Библиотека:** `github.com/cloudflare/go-selfupdate`. +* **Механика:** Сравнение текущей версии с версией на сервере API. Скачивание нового бинарника, переименование текущего исполняемого файла в `.old` (обход блокировки Windows) и перезапуск программы. + +--- + +## 3. Пользовательский интерфейс (UI - Fyne) + +Основан на компоновке `BorderLayout` со следующими зонами: + +| Зона (Layout) | Элементы виджетов (Fyne Widgets) | Описание логики | +| :--- | :--- | :--- | +| **Left (Лево)** | `widget.List` / `container.VBox` | Вертикальный список серверов (модпаков). Содержит иконки и названия. При выборе меняет контент центральной зоны. | +| **Center (Центр)**| `widget.RichText`, `canvas.Image` | Фоновое изображение выбранного сервера. Поверх него — Markdown-карточка с новостями/патчноутами. | +| **Bottom (Низ)** | `BorderLayout` (вложенный) | Панель управления (Навигация и статус). | +| *Bottom-Left* | `canvas.Image`, `widget.Label` | Аватарка (лицо из скина 8x8) и никнейм. Кнопка "Выйти". | +| *Bottom-Center*| `widget.ProgressBar` | Полоса загрузки (показывает прогресс скачивания файлов). Скрыта, если нет активных загрузок. | +| *Bottom-Right* | `widget.Button` | Кнопка «Настройки» (шестеренка) и большая акцентная кнопка «PLAY». | + +### 3.1. Экран настроек (Модальное окно) +* **ОЗУ:** Слайдер (`widget.Slider`) для выбора выделяемой оперативной памяти (от 1 ГБ до максимума физической ОЗУ пользователя). Конвертируется в флаги `-Xms` и `-Xmx`. +* **Доп. аргументы:** Текстовое поле (`widget.Entry`) для пользовательских флагов JVM (например, настройки Garbage Collector). + +--- + +## 4. Структура файловой системы (Клиентская часть) + +Кастомная корневая директория, зависящая от ОС: +* **Windows:** `%AppData%\Roaming\MrixsCraft\` +* **macOS:** `~/Library/Application Support/MrixsCraft/` +* **Linux:** `~/.MrixsCraft/` + +Внутренняя иерархия папок: +```text +MrixsCraft/ +├── launcher.exe # Исполняемый файл лаунчера +├── launcher.json # Настройки лаунчера (ОЗУ, выбранный сервер) +├── session.json # Токены авторизации Yggdrasil +├── authlib-injector.jar # Перехватчик авторизации +├── Java/ # Портативные версии Java +│ ├── 8/ +│ │ └── bin/java +│ ├── 17/ +│ │ └── bin/java +│ └── 21/ +│ └── bin/java +├── assets/ # Общие ресурсы игры (звуки, текстуры), размещаются здесь для совместимости с игрой +├── libraries/ # Общие библиотеки (LWJGL, утилиты), размещаются здесь для совместимости с игрой +└── instances/ # Изолированные клиенты (модпаки) + ├── HiTech_1_21/ + │ ├── mods/ # Моды (проверяются SHA-1) + │ ├── mods_backup/ # Сюда скидываются неизвестные моды + │ ├── config/ # Конфигурации + │ └── resourcepacks/ + └── Vanilla_1_20/ +``` + +--- + +## 5. Требования к серверной части (API & CDN) + +Для корректной работы лаунчера на сервере должны быть реализованы следующие эндпоинты: + +1. **Yggdrasil API:** `/authserver/authenticate`, `/authserver/refresh`, `/authserver/validate`. +2. **Обновление лаунчера:** GET `/api/launcher/latest` -> Возвращает версию и прямую ссылку на бинарники (Win, Mac, Lin). +3. **Список серверов:** GET `/api/servers.json` -> Отдает массив доступных модпаков. +4. **Манифест сервера:** GET `/api/instances/hitech/manifest.json` -> Отдает полный граф файлов с хэшами SHA-1, путями и параметрами запуска. +5. **Файловый хостинг (CDN):** Раздача статики (модов, ассетов, библиотек). + +--- + +## 6. Предлагаемая структура проекта (Go Packages) + +Для чистоты кода рекомендуется использовать стандартный паттерн структуры Go-приложений: + +```text +/cmd/launcher/ + └── main.go # Точка входа, инициализация Fyne приложения +/internal/ + ├── auth/ # Логика Yggdrasil, токены, профили + ├── config/ # Чтение/запись launcher.json и системных путей + ├── fetcher/ # HTTP-клиент, скачивание файлов, проверка SHA-1 + ├── java/ # Определение ОС, скачивание и распаковка JRE + ├── launch/ # Парсинг manifest.json, интерполяция строк, exec.Command + ├── selfupdate/ # Интеграция библиотеки автообновления лаунчера + └── ui/ # Код Fyne интерфейса + ├── components/ # Отдельные виджеты (аватарка, прогресс-бар) + ├── screens/ # Экраны (Логин, Главное меню, Настройки) + └── theme/ # Кастомная тема Fyne (цвета, шрифты) +/pkg/ + └── utils/ # Вспомогательные функции (вычисление хэша, парсинг zip) +``` \ No newline at end of file diff --git a/docs/server/Specification.md b/docs/server/Specification.md new file mode 100644 index 0000000..bf16180 --- /dev/null +++ b/docs/server/Specification.md @@ -0,0 +1,199 @@ +# Спецификация серверной части Minecraft проекта (Backend & Infrastructure) + +## 1. Стек технологий +* **Бэкенд-платформа:** Go (чистый net/http с роутером github.com/go-chi/chi, для максимальной прозрачности и контроля). +* **База данных:** PostgreSQL (реляционная СУБД для надежного хранения транзакций токенов, пользователей и связей файлов). +* **Фронтенд (Сайт и Админка):** SPA на Vue.js / React / Svelte, либо классический монолит на Go-шаблонах (html/template) для максимального упрощения деплоя (всё в одном исполняемом файле). +* **Статический веб-сервер (CDN):** Nginx (занимается отдачей тяжелых файлов и проксированием API-запросов к Go-бэкенду). + +--- + +## 2. Архитектура хранилища файлов (Content-Addressable Storage - CAS) +Для экономии места на диске сервера и клиента, а также для сквозного кэширования, все файлы модов, библиотек и ассетов хранятся по их SHA-1 хэшам. + +* **Путь на сервере:** `/var/www/cdn/files/[первые два символа хэша]/[полный хэш]` + * *Пример:* Файл с хэшем `a1b2c3d4e5...` будет лежать по пути `/var/www/cdn/files/a1/b2c3d4e5...` (это предотвращает замедление файловой системы при наличии десятков тысяч файлов в одной директории). +* **URL для скачивания:** `https://cdn.myserver.com/files/a1b2c3d4e5...` + +--- + +## 3. Схема Базы Данных (PostgreSQL) + +```sql +-- Таблица пользователей +CREATE TABLE users ( + id SERIAL PRIMARY KEY, + username VARCHAR(32) UNIQUE NOT NULL, + email VARCHAR(255) UNIQUE NOT NULL, + password_hash VARCHAR(255) NOT NULL, + uuid UUID UNIQUE NOT NULL, + role VARCHAR(16) DEFAULT 'user', -- 'user', 'admin' + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Таблица скинов и плащей (ссылки на файлы в CAS) +CREATE TABLE player_textures ( + user_id INT PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE, + skin_hash VARCHAR(40), -- SHA-1 хэш файла скина в CAS + cape_hash VARCHAR(40), -- SHA-1 хэш файла плаща в CAS + is_slim BOOLEAN DEFAULT FALSE -- модель скина (Alex/Steve) +); + +-- Сессии Yggdrasil (для авторизации лаунчера и игры) +CREATE TABLE yggdrasil_sessions ( + client_token UUID NOT NULL, + access_token UUID PRIMARY KEY, + user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE, + expires_at TIMESTAMP NOT NULL +); + +-- Таблица модпаков (игровых серверов) +CREATE TABLE modpacks ( + id SERIAL PRIMARY KEY, + slug VARCHAR(32) UNIQUE NOT NULL, -- например: 'hitech', 'magic' + name VARCHAR(64) NOT NULL, + minecraft_version VARCHAR(16) NOT NULL, + java_version INT NOT NULL, -- 8, 17, 21 + server_ip VARCHAR(255) NOT NULL, -- IP:Port для добавления в servers.dat + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Единый реестр уникальных файлов (CAS) +CREATE TABLE global_files ( + sha1 VARCHAR(40) PRIMARY KEY, + size_bytes BIGINT NOT NULL, + file_name VARCHAR(255) NOT NULL -- оригинальное имя файла (для истории) +); + +-- Релизы лаунчера (заполняются через CI/CD) +CREATE TABLE launcher_releases ( + id SERIAL PRIMARY KEY, + version VARCHAR(32) NOT NULL, -- например: '1.2.0' + os VARCHAR(16) NOT NULL, -- 'windows', 'linux', 'darwin' + arch VARCHAR(16) NOT NULL, -- 'amd64', 'arm64' + sha256 VARCHAR(64) NOT NULL, -- SHA-256 для проверки бинарника лаунчера + file_path VARCHAR(255) NOT NULL, + is_active BOOLEAN DEFAULT TRUE, + is_mandatory BOOLEAN DEFAULT TRUE, -- принудительное обновление + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +``` + +--- + +## 4. Спецификация API Эндпоинтов + +### 4.1. Автоматический деплой из CI/CD (Protected Route) +Эндпоинт, который вызывает твой пайплайн сборки после успешной компиляции лаунчера. +* **Маршрут:** `POST /api/admin/launcher/release` +* **Авторизация:** Заголовок `X-CI-Token: <секретный_токен_из_секретов_репозитория>` +* **Тело запроса (Multipart Form Data):** + * `version`: "1.2.0" + * `os`: "windows" + * `arch`: "amd64" + * `sha256`: "hash_of_binary..." + * `file`: (бинарный файл лаунчера) + +### 4.2. Yggdrasil API (Mojang Emulation) +* `POST /authserver/authenticate` — Аутентификация по логину/паролю. Возвращает UUID и токены. +* `POST /authserver/refresh` — Обновление сессии лаунчера по `clientToken` и `accessToken`. +* `POST /authserver/validate` — Быстрая проверка токена при запуске лаунчера. +* `GET /sessionserver/session/minecraft/profile/{uuid}` — Эндпоинт, к которому обращается сам игровой клиент для загрузки скинов игроков на сервере. + +### 4.3. Публичное API сайта и лаунчера +* `POST /api/web/register` — Регистрация игрока. +* `POST /api/web/login` — Логин в личный кабинет сайта. +* `POST /api/web/profile/skin` — Загрузка скина (принимает PNG, считает его SHA-1, сохраняет в `/files/` и привязывает к юзеру). +* `GET /api/launcher/latest` — Возвращает информацию о последней версии лаунчера и ссылки на скачивание для автообновления. +* `GET /api/servers.json` — Список активных модпаков для меню выбора в лаунчере. + +--- + +## 5. Алгоритмы и Пайплайны работы + +### 5.1. Пайплайн загрузки и сборки модпака (в Админ-панели) + +Когда админ загружает ZIP-архив с обновлением модов/конфигов через панель управления: + +```text + [Архив с модами] -> [Распаковка во временную папку] + │ + ▼ + [Обход каждого файла в цикле] + │ + ▼ + [Расчет SHA-1 хэша] + │ + ┌─────────────┴─────────────┐ + ▼ ▼ + [Хэш ЕСТЬ в базе?] [Хэша НЕТ в базе] + │ │ + │ [Копирование в CAS] + │ [/files/ab/abcdef12...] + │ │ + └─────────────┬─────────────┘ + ▼ + [Добавление в manifest.json] +``` + +**Итоговый формат генерируемого `manifest.json` для лаунчера:** +```json +{ + "minecraft_version": "1.21", + "java_version": 21, + "server_info": { + "name": "HiTech Server", + "ip": "play.myserver.com:25565" + }, + "files": [ + { + "path": "mods/jei-1.21.jar", + "hash": "a1b2c3d4e5f6...", + "size": 1048576, + "url": "https://cdn.myserver.com/files/a1b2c3d4e5f6..." + }, + { + "path": "config/general.json", + "hash": "f7g8h9i0j1k2...", + "size": 1245, + "url": "https://cdn.myserver.com/files/f7g8h9i0j1k2..." + } + ] +} +``` + +### 5.2. Автоматическое добавление сервера в игру (servers.dat) +Перед запуском игры лаунчер читает блок `server_info` из манифеста. Если в `instances//servers.dat` отсутствует сервер с IP `server_info.ip`, лаунчер парсит этот NBT-файл и добавляет в него новую запись: +* **Имя:** `server_info.name` +* **IP:** `server_info.ip` +Это избавляет игроков от ручного ввода IP в клиенте. + +### 5.3. Пайплайн CI/CD Релиза Лаунчера + +```text +[Коммит/Тег в Git] -> [Сборка в CI (Windows/Linux/macOS)] + │ + ▼ + [Расчет SHA-256 для каждого] + │ + ▼ + [POST-запрос с секретным токеном] + │ + ▼ + [Go-Бэкенд сохраняет файлы] + [Обновляет версию лаунчера в БД] + │ + ▼ + [Игроки видят обновление при запуске] +``` + +--- + +## 6. Конфигурация Nginx (CDN & Static) + +Для максимальной производительности Nginx настраивается на прямую отдачу файлов, минуя Go-бэкенд. Запросы к API проксируются. + +* **Статика (`/files/`)**: Настраивается отдавать файлы с вечным кэшированием, так как они никогда не меняются (меняется только сам хэш в манифесте). +* **Скины (`/skins/`)**: Кэширование настраивается на меньший срок (например, 1 час), чтобы при смене скина игроки видели изменения без жесткого сброса кэша. +* **API (`/api/`, `/authserver/`)**: Все запросы перенаправляются на локальный порт Go-приложения (например, `127.0.0.1:8080`). diff --git a/launcher b/launcher new file mode 160000 index 0000000..320f009 --- /dev/null +++ b/launcher @@ -0,0 +1 @@ +Subproject commit 320f009658f5cffff6445d89d7e8cadb7dd83b57 diff --git a/server b/server new file mode 160000 index 0000000..551c75a --- /dev/null +++ b/server @@ -0,0 +1 @@ +Subproject commit 551c75a232d06a374cd36c878ac37489d62803b4