Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
7eed2d9
Добавить хранилище сборок Windows: .hako, instances.json, блокировка …
Liis17 Oct 21, 2026
64bdcb8
Добавить установку Minecraft и Java в Windows-клиенте: каталог Mojang…
Liis17 Oct 22, 2026
b18bc8a
Добавить очередь установки сборок в Windows-клиенте: пауза, продолжен…
Liis17 Oct 22, 2026
be4def9
Добавить запуск игры в Windows-клиенте: обновление сессии Minecraft, …
Liis17 Oct 22, 2026
f0ee996
Добавить сборки и запуск в Windows-клиенте
Liis17 Oct 22, 2026
ae16c4d
Добавить интерфейс сборок в Windows-клиенте: карточки, создание Vanil…
Liis17 Oct 22, 2026
d0eec62
Добавить Fabric в Windows: выбор Loader, установку API, профиль запус…
Liis17 Oct 22, 2026
3537b42
Добавить клиент Modrinth и управление локальными модами и ресурспакам…
Liis17 Oct 22, 2026
a5ca16c
Добавить установку зависимостей и обновления контента Modrinth в Windows
Liis17 Oct 22, 2026
f9f4904
Добавить интерфейс модов, ресурспаков и каталога Modrinth в Windows
Liis17 Oct 22, 2026
6db0197
Добавить чтение, копирование и удаление миров Minecraft в Windows
Liis17 Oct 22, 2026
eca3660
Добавить локальные датапаки и их установку и обновление из Modrinth д…
Liis17 Oct 23, 2026
86f0a23
Добавить интерфейс миров и датапаков в Windows
Liis17 Oct 23, 2026
faa4204
Добавить создание и установку готовых модпаков Modrinth в Windows
Liis17 Oct 23, 2026
b89a2df
Добавить скриншоты, дублирование и резервные копии сборок и миров в W…
Liis17 Oct 23, 2026
c2b4068
Добавить учёт времени игры и перенос гостевой статистики в Windows
Liis17 Oct 23, 2026
95e1383
Актуализировать документацию возможностей Windows-клиента
Liis17 Oct 23, 2026
575da10
Сохранить историю удалённой версии Windows-ветки
Liis17 Oct 23, 2026
139ec0a
Исправить ошибки Windows CI для контента и миров
Liis17 Oct 23, 2026
653c8cf
Исправить гонки процессов в Windows CI
Liis17 Oct 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
Интерфейс на русском и английском: язык выбирается на приветствии и в настройках и меняется без перезапуска.
Каждый push в `main` собирает обе платформы и публикует общий prerelease; независимые стабильные релизы `macos-vX.Y.Z` и `windows-vX.Y.Z` выходят при повышении версии соответствующей платформы. macOS-клиент автоматически получает обновления из стабильных macOS-релизов; прежние клиенты `nightly` переходят на них вручную.
Проект Xcode: `macos/Hako/Hako.xcodeproj`, исходники: `macos/Hako/Hako/`.
Windows-клиент на WinUI 3 (.NET 8) находится в `windows/` и на первом этапе паритета с macOS: приветствие, вход в Microsoft, настройки «Основные» и «Профиль», выход; сборок и запуска игры пока нет. Проекты: `windows/Hako/Hako.csproj`, логика `windows/Hako.Core/`, тесты `windows/Hako.Tests/`.
Windows-клиент на WinUI 3 (.NET 8) находится в `windows/`: приветствие, вход в Microsoft, настройки «Основные», «Игра» и «Профиль», выход, сборки Vanilla/Fabric и запуск Minecraft. Каталог Modrinth устанавливает моды и ресурспаки в сборки, датапаки — в выбранный мир, а готовые модпаки — из `.mrpack`; локальные моды доступны только для Fabric.
Поддерживаются управление мирами и скриншотами, дублирование сборок и архивы `.hakobackup`/`.hakoworld`. Игровое время учитывается с фоновым помощником и переносом гостевой статистики. CurseForge, восстановление архивов и самообновление Windows не реализованы.
Проекты: `windows/Hako/Hako.csproj`, логика `windows/Hako.Core/`, тесты `windows/Hako.Tests/`.

<!-- obsidian:start -->
## База знаний — Obsidian
Expand Down
82 changes: 56 additions & 26 deletions Obsidian/HakoVault/Architecture.md

Large diffs are not rendered by default.

34 changes: 29 additions & 5 deletions Obsidian/HakoVault/Auth/MicrosoftAuth.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,11 @@ email и, если доступен, профиль Minecraft. Без Minecraft
HTTP-статус из этих трёх запросов, пустой `uhs`, пустой или некорректный JSON, сеть, таймаут) даёт пустые поля Minecraft,
вход продолжается с профилем Xbox. Причина не сохраняется и не показывается. Исключение выходит наружу только при отмене
нашим `CancellationToken`. `MinecraftTokenExpiresAt` = момент получения + `expires_in`.
5. Запись `AccountSession` через `AccountSessionStore.SaveAsync` — аккаунт становится текущим, только если
попытка ещё актуальна ([[Data/Persistence#Windows-клиент]]).
5. Перед `AccountSessionStore.SaveAsync` `AppCoordinator` фиксирует на ledger границу ожидающего переноса гостевого
времени. `session.dat` сохраняется только если попытка ещё актуальна; после успешной записи перенос применяется
одной атомарной операцией, только для сохранённого целевого XUID и зафиксированных на границе сумм/сессий.
При ошибке или отмене запись переноса удаляется; при сбое между фазами решение восстанавливается при запуске
по текущему `session.dat` ([[Data/Persistence#Игровое время Windows]]).

Коды `XErr` шагов 1–2 классифицируются: `2148916233` → `XboxProfileMissing`, `2148916235` → `XboxUnavailable`,
`2148916236` и `2148916237` → `XboxAgeVerification`, `2148916238` → `XboxChildAccount`, остальные → `XboxRejected`.
Expand All @@ -167,8 +170,29 @@ email и, если доступен, профиль Minecraft. Без Minecraft
- Одна активная попытка: `StartAttempt` через `InvalidateAttemptLocked` увеличивает поколение и отменяет
предыдущую попытку.
- Отмена: `CancelSignIn` (закрытие `MainWindow`), `BackFromSignIn`, `LogoutAsync`. Ошибки отменённой попытки не показываются.
- Все переходы состояния попытки и финальная запись аккаунта выполняются под `_commitLock`. Запись проходит
только при `IsCurrentAttempt` (то же поколение, попытка активна и не отменена); `File.Move` выполняется
внутри этого условия. Устаревший вход не заменит аккаунт, а завершившийся вход не восстановит аккаунт после выхода.
- Все переходы состояния попытки и финальная запись аккаунта выполняются под `_commitLock`. Подготовка счётчиков
выполняется до финальной фиксации; сама запись проходит только при `IsCurrentAttempt` (то же поколение, попытка
активна и не отменена), а `File.Move` остаётся внутри этого условия. Фаза применения сериализована с выходом,
но файловые операции подготовки не блокируют UI и не удерживают commit lock. Устаревший вход не заменит аккаунт,
а завершившийся вход не восстановит аккаунт после выхода.
- Выход: `LogoutAsync` сначала инвалидирует попытку, затем удаляет `session.dat` под тем же условием. Выбранный язык
при выходе сохраняется (тест `LogoutKeepsSelectedLanguage`).

### Обновление сессии для онлайн-запуска

Строгий путь, отдельный от мягкого шага 4 первого входа (тот не изменён).
`IMicrosoftAuthService.ConnectMinecraftAsync(refreshToken, persistRefreshToken, ct)`: refresh-grant Microsoft →
**сразу** `persistRefreshToken` с ротированным токеном → Xbox → XSTS Minecraft → `login_with_xbox` → профиль.
Сбой после refresh не теряет новый токен. Ошибки различимы: `invalid_grant` → `RefreshTokenRejected`,
403/404 входа или 403 профиля → `MinecraftLicenseMissing`, 404 профиля или пустой профиль → `MinecraftProfileMissing`;
сеть/таймаут → `Network`. Ключи resw: `MinecraftRefreshTokenRejected`, `MinecraftLicenseMissing`, `MinecraftProfileMissing`.
`MinecraftConnection.ToString()` не выводит access token.

`MinecraftSessionCoordinator` (`AppCoordinator.MinecraftSessions`, `windows/Hako.Core/MinecraftSessionCoordinator.cs`):
- `ConnectForLaunchAsync` возвращает текущий `AccountSession`, если Minecraft-токен действует ещё больше минуты
(время — через `TimeProvider`), иначе запускает refresh. Параллельные вызовы ждут одну операцию.
- Каждая запись (`session.dat` и `AppCoordinator.Account`) идёт через `AppCoordinator.TryCommitAccountUpdate` внутри
`commitIfCurrent` с поколением аккаунта; вход, загрузка и выход увеличивают поколение (`AccountGenerationChanged`)
и отменяют refresh. Поздний результат не восстановит удалённый `session.dat` и не заменит новый аккаунт.
- `Status` (`Idle`/`Connecting`/`Connected`/`Failed`) и `Error` для UI; события приходят с потока refresh —
UI маршалит их в `DispatcherQueue`.
34 changes: 34 additions & 0 deletions Obsidian/HakoVault/Data/Backups.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,37 @@ SHA-512 позволяет будущему восстановлению рас
паков выполняются на `InstanceContent`, копирование/zip — вне главного потока.
Восстановление пока не реализовано; будущий импорт обязан проверять версию схемы, все пути
и записи архива перед распаковкой, не доверяя `worldPath` и `datapacks[].path` из JSON.

## Windows-клиент

Реализация без WinUI находится в `windows/Hako.Core/Instances/InstanceBackup.cs`,
`WorldBackup.cs`, `BackupModels.cs`, `BackupJsonConverters.cs` и общем обходчике
`InstanceFileTree.cs`; source-generated типы зарегистрированы в `HakoJsonContext`
(`windows/Hako.Core/JsonContexts.cs`). UI находится в профиле сборки и `InstanceWorldsView`
(`windows/Hako/InstanceProfilePage.xaml.cs`, `InstanceWorldsView.xaml.cs`).

Windows использует те же версии схемы и имена полей, что и Swift. CamelCase JSON пишет source generation,
необязательные null-поля пропускаются, PNG-данные кодируются base64. Даты сериализуются ISO 8601 в UTC
с точностью до секунды и суффиксом `Z`, чтобы соответствовать Swift `JSONEncoder.dateEncodingStrategy = .iso8601`.
Дата в имени архива также UTC: `{folder}_{yyyy-MM-dd_HH-mm-ss}`.

- `.hakobackup` лежит в `%USERPROFILE%\.hako\backups\`; корень ZIP содержит `data.json` и содержимое
папки сборки без родительской папки. В архив входят Java, Minecraft, иконка, служебные реестры происхождения,
Fabric-конфигурация и completed-план модпака. Список `mods` строится из обычных JAR и происхождения Modrinth;
если реестр происхождения нельзя прочитать, моду назначается источник local. transient
`.hako-running.json`, `.hako-launch/`, `.hako-game/` и `minecraft/logs/hako-launch.log` не архивируются.
- `.hakoworld` лежит в `%USERPROFILE%\.hako\worlds\`; ZIP содержит `data.json` манифеста и `world/` со всем
сохранением. Пользовательский `world/data.json` остаётся обычным файлом мира. В манифесте сохраняются источник
сборки, метаданные мира, иконка и включённые/отключённые датапаки с origin; обычные ZIP получают SHA-512,
для папок он отсутствует, доступный `pack.png` ограничен 4 МиБ.
- Архивы создаются потоково, без сборки всего содержимого в память. Перед публикацией файловое дерево повторно
проверяется; reparse points/device entries отклоняются, а зарезервированные папки `backups`/`worlds`, занятые
сборкой или небезопасным объектом, дают типизированный отказ. ZIP сначала пишется в уникальный скрытый
`.partial` рядом с конечным файлом и затем перемещается без перезаписи; отмена или ошибка удаляет только свой
staging-файл. Операция требует готовую сборку и общий content-lease, поэтому игра, установка, дублирование и
другие файловые действия сериализованы. UI показывает прогресс и локализованную причину отказа, затем может
открыть папку архива в Проводнике.

`windows/Hako.Tests/InstanceBackupsAndScreenshotsTests.cs` проверяет имена/содержимое ZIP, совместимость схемы
и дат, base64-иконки, происхождение модов/датапаков, исключение transient-файлов, хеши, потоковую обработку,
коллизии, отмену и очистку staging. Восстановление или импорт архивов не реализованы.
Loading
Loading