VanguardReMaster/docs/SESSION-STATE.md

480 lines
40 KiB
Markdown
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.

# Vanguard ReMaster — состояние сессии
**Дата:** 2026-10-27
**HEAD:** см. `git log -1`
**Коротко:** сервер готов, клиент — рабочий каркас с 3D-сценами.
## Правила работы
- Ответы короткие, без повторов и длинных вступлений — экономия токенов.
- Любое сомнение/вопрос — диалог: 2–4 варианта с рекомендацией, выбор за
пользователем (или его свободный ответ). Не угадывать.
- Полный свод правил — `AGENTS.md`.
- Новые изменения: анализ DeepSeek → план в
`docs/Development/IMPLEMENTATION_PLAN.md` → реализация. Обе стадии выполняет
DeepSeek, раздельно по проходам. Код на этапе анализа не меняется; процесс — `docs/Development/AGENT-WORKFLOW.md`.
## Сервер
- .NET 10 / ASP.NET Core, EF Core, PostgreSQL, Redis, опциональный Orleans.
- Реализовано: auth/JWT, онбординг, коллекция, колоды, магазин, экономика,
матчмейкинг, WebSocket-матч, история, реплеи.
- Orleans включается `Orleans:Enabled`; в compose включён. Один silo,
in-process реестр соединений.
- Тесты: **151** правил + **45** серверных, CI зелёный.
- Стенд: `http://192.168.31.158:18080`, `/health` → ok.
- Диагностика Ride в `MatchGrain`: входящие интенты, результат, события,
снапшоты и `rideReady` по руке/рангам; логи через `docker compose logs`.
- Документация: `docs/server-api.md`, `docs/protocol.md`,
`docs/game-rules.md`, `docs/HANDOFF.md`.
## Клиент
- **Unity 6000.6.6f1**, URP; проект в `client/`.
- Пакеты: URP, Input System, Addressables, Localization, Newtonsoft.Json,
VContainer (OpenUPM).
- Визуальное направление: **3D**, отдельные сцены-экраны:
`Login`, `Lobby`, `Community`, `DeckBuilder`, `Battle`.
`DeckBuilder` совмещает коллекцию и колоды; `Boot` — стартовая служебная
сцена; `VanguardApp` персистентный.
- Переходы — `SceneFlow`; очередь, магазин и история — экраны **Lobby**;
выбор стартовой триал-деки — отдельный экран до Lobby.
- 3D-окружение сейчас из примитивов (`SceneEnvironment`): камера, свет,
пол, тематические кубы. UI — code-generated uGUI, пока gray-box.
- Login переведён на референс: полноэкранный арт
`Resources/Login/login_bg`, неоновая панель, меню (язык, версия, адрес
сервера). Tab/Shift+Tab переключают поля, Enter отправляет форму, Esc
закрывает меню. 3D-окружение в `Login` больше не строится
(`TASK-2026-021`).
- Lobby — 2D-дашборд по референсу (`TASK-2026-022`): процедурный фон,
топбар с MMR и меню, BATTLE/DECK BUILDER/SHOP, миссии, балансы,
заглушки чата и друзей; «Рейтинг» — заглушка, «Сообщество» — отдельная
сцена `Community` с вкладками «Гайды / Колоды / Тикеты». BATTLE
открывает оверлей выбора колоды и режима (Ranked / С ботом). 3D в Lobby
не строится; `MetaView` удалён.
- Интерфейс рассчитан на reference **1920×1080** (`CanvasScaler`,
`matchWidthOrHeight = 0.5`); standalone принудительно открывается в
1920×1080 fullscreen, `defaultIsNativeResolution` выключен.
- Login: тёмный неон + 3D-карточный стол, форма по центру на
полупрозрачной панели.
- Сервисы: `ApiClient`, `AuthService`, `MetaService`, `TokenStore`,
`PlayerState`, `GameConnection`.
- Работает: логин/регистрация/refresh, онбординг, коллекция с разбором,
декбилдер (слева карточная сетка коллекции с мультифильтрами, справа
панель «Мои колоды» ⇄ «Колода»; список карт колоды — грейд→имя,
превью-иллюстрации), магазин (бустер/триал-дека), история матчей и
реплей, очередь, WebSocket-матч (snapshot, интенты, маллиган, сдача,
`GameFinished`), таймер, результат.
- Декбилдер: `DeckBuilderView` (один экран), `DeckListFilter`
(`DeckFilter`/`DeckListModel`); каталог метаданных — `GET /api/cards`
(grade, trigger, clan, rarity, printing, power/shield/type, текст
способности), клиент объединяет с коллекцией.
Превью карт — иллюстрация (верхние 59% арта) без искажений; полный арт
остаётся в карточке и 3D-поле.
- ПКМ по карте — оверлей с картой, способностями, разбором в пыль и
крафтом; SP/TD не разбираются и не крафтятся.
- Локализация RU/EN: `Loc` + `LocalizedText`; переключатель в Login и
Lobby (кнопка `EN`/`RU`), выбор сохраняется в `PlayerPrefs`. Русские
строки остаются ключами, переводятся и статические, и динамические
подписи; имена/тексты карт берутся из `nameRu/nameEn` и `textRu/textEn`.
- Тренировка с ботом: кнопка «С ботом» в редакторе колоды; сервер
создаёт casual-матч против случайного бота (`POST /api/game/practice`),
без истории, MMR и наград.
- Боевой экран: поле, рука и стопки — **3D** (`GameBoard3D`), HUD/кнопки
остаются uGUI. Карты — тонкие 3D-объекты с артом, рубашкой, торцом и
коллайдером. Rest (атака/поддержка) — поворот по часовой стрелке вокруг Y,
урон лежит на боку против часовой; закрытость — переворот вокруг X.
Рубашка — стандартная VF Vanguard (`Resources/CardArt/vanguard_back.png`),
общая для 2D и 3D. Рука закреплена в поле зрения камеры снизу по центру
и всегда смотрит на игрока, а не лежит на столе; уменьшена, чтобы не
закрывать задний ряд RC. Камера фиксирована по центру поля под небольшим
углом к горизонту и не двигается игроком: `(0, 4.2, -8)`, цель
`(0, 0, 0)`, FOV 46; наклон только по X, без бокового смещения. Драг-н-дроп
на плоскость стола с подсветкой целей и плавным снапом.
Все карты на столе и в руке увеличены на 25% (`cardScale = 1.25`).
- Поле: у каждого игрока два ряда `R V R` / `R R R` (V + 5 RC), у
противника зеркально; между полями общий круг защиты; колода, дроп,
триггер-зона и урон — 3D-зоны. Локальный игрок всегда снизу, даже если
он за вторым местом. Карты в кругах V/R принудительно показываются
лицом вверх; урон — один вертикальный ряд, карта входит открытой.
Над колодой — зона проверки триггера. Под картами V/R — динамические
`P/C`.
- Смена: в фазе Ride доступны карты того же ранга и на 1 выше. На первом
ходу переход в Battle не предлагается; атака по-прежнему запрещена.
Смена — драг карты из руки на VC. Списки всех возможных смен в панелях
убраны; действия доступны из меню выбранной карты в руке.
- Призыв: клик по карте в руке открывает меню действий (Призвать / Сменить /
Активировать способность / Подробнее), drag в RC/VC выполняет призыв/смену.
Если у RC доступен единственный круг перемещения, перемещение выполняется
сразу, без выбора цели.
Призыв разрешён и в занятый RC; прежний юнит уходит в Дроп. Правило
действует для обычного призыва, призыва из души/колоды и выбора круга
способностями.
- Аудит всех 66 карт со способностями и правила реализации:
`docs/ability-implementation.md`. Conroe получил AUTO-call при ride-over.
- Способности: кнопка «Активировать способность» одна на карту; при
нескольких вариантах открывается overlay выбора способности. Карта для
сброса выбирается **кликом по карте в руке**, а не пунктом меню.
Perfect Guard также просит выбрать карту сброса в руке. Клик по карте в
руке с активируемой способностью открывает меню действий; пункт активации
показывается, если фаза и условия позволяют способность.
- Триггеры: Draw после выбора цели силы сразу тянет карту; Heal выбирает
карту только в своей зоне урона и только при выполнении условий, иначе
дополнительный эффект не активируется.
- Оплата способности: выбранные карты цены подсвечиваются в руке, а для
Counter Blast — доступные и выбранные карты в зоне урона. Подтверждение
оплаты — кнопка «Подтвердить оплату» в панели «Действия»; правый клик
отменяет выбор.
- Защита: в панели «Действия» одна кнопка — «Не защищаться» без выбора и
«Защищаться» с выбранными картами. Защитник из руки должен быть не выше
ранга своего авангарда. Карты защиты и перехвата выбираются
кликом/драгом по объектам; допустимые подсвечиваются, выбранные — зелёным.
Щит выбранных карт сразу учитывается в счётчике; после подтверждения карты
уходят в зону защиты, шаг защиты завершается. Дубли карт в Guardian
устранены.
- Локальный standalone работает в фоне (`runInBackground`), чтобы heartbeat
WebSocket не останавливался при потере фокуса.
- При потере соединения весь бой блокируется полноэкранным overlay
«Соединение потеряно»; автоматический reconnect идёт с задержками
0/2/10/30 с, после успеха overlay скрывается и поле показывается снова.
Кнопка внутри overlay позволяет выйти в меню.
- Правую панель действий можно временно скрыть кнопкой «Скрыть панель»
в верхней строке; поле остаётся видимым, вернуть — «Показать панель».
При скрытии панель действий и блоки противника сдвигаются вправо, а рука
центрируется по горизонтали; при показе возвращается влево.
- Кнопка муллигана находится в панели «Действия» и динамическая: без выбора —
«Закончить муллиган», с выбором — «Заменить X карт».
- Trigger-зона у противника расположена над его колодой по направлению
к центру стола (зеркально своей), а не за дальним краем.
- Статистика карт — отдельное UI-наложение: своя панель снизу слева,
противника — сверху справа. Блоки `Рука/Колода/Дроп/Душа/Урон/Защита/Триггер`
кликабельны и открывают общий горизонтальный `CardListView`; из списка
открывается `CardDetailOverlay`. Для колоды и руки противника показываются
только закрытые карты. Душа — юниты под VC: отдельной стопки нет,
ПКМ по VC открывает список. Дроп по умолчанию пуст; сверху показывает
последнюю карту, ЛКМ — список всего дропа. Колода и дроп поменяны
местами (колода ближе к игроку). Справа от круга защиты — панель действий:
конец муллигана (авто после обмена), скип смены, конец главной/боевой;
боевая завершается сама, если нет атак и активаций. Рука противника —
веер закрытых карт у дальнего края стола, только рубашки.
- Зона урона: карты лежат открытыми и на боку; после Counter Blast
выбранная карта переворачивается рубашкой. Heal выбирает карту урона;
Counter Blast — открытую карту до активации способности.
- Маллиган: один раз на игрока, оба игрока; выбранные карты уходят в низ
колоды, добираются новые, затем shuffle. Клик по руке выбирает карты;
кнопка динамическая: без выбора — «Закончить муллиган», с выбором —
«Заменить X карт».
- Анимации: event-фидбек (атака, guard, drive, урон, retire, heal) поверх
стола; ввод заблокирован до завершения через `InputLockService`, очередь
событий + кнопка «Пропустить анимации». Длительности и скорости карт —
`AnimationConfig` (`Resources/AnimationConfig`). Guard/drive/intercept
показывают имя карты и держатся 1.5–2 с. 3D-карты плавно снапятся,
поворачиваются в Rest и переворачиваются; подсветка целей и точки броска
обновляются на каждом снимке. Зависшие причины `InputLockService`
снимаются, когда reconnect/overlay/ability/card-menu/feedback уже
неактивны; `board`-лок больше не накапливается на каждом снапшоте.
- 3D UX (P0/P1): `CardMoveAnimator` переносит карты по дуге с
stagger/`InputLock`; diff идёт по `InstanceId`, пул сохраняет карту при
смене зоны. `AnimationConfig` расширен (`moveDuration`,
`importantMoveDuration`, `moveDelayBetweenCards`, `arcHeight`,
camera/grow/dash). Trigger Zone: своя +90°, противника −90° относительно
базы; `DropZoneFaceDown` в конфиге. `CameraDirector` +
`TriggerCheckSequence`: zoom → hold → return, цепочка, точный Restore;
`EnsureCamera` не перезаписывает камеру во время цепочки.
`ArrowDirector`: красная attack и синяя boost-стрелка, grow/arc/dash
(UV-tile), якоря у края карт. Multi-target Counter Blast: выбранные карты
урона уходят массивом `DamageIndexes`, сервер снимает именно их; счётчик
выбора показывается в панели «Действия». Детали —
`docs/3d-ux-backlog.md`.
- Опциональные AUTO-способности (Barcgal после рейда Marron) открывают
модальный оверлей «Способность» с «Активировать»/«Пропустить»; в боковой
панели этих кнопок нет. После подтверждения призыва сервер предлагает
`AskEmptyRearGuardChoice`, клиент подсвечивает свободные RC и принимает
выбор кликом по кругу — первого круга по умолчанию нет и отдельных
кнопок выбора тоже. Сама панель пока оставлена.
- Общий верхний `ActionPrompt` показывает, что сейчас требуется: муллиган,
смена, защита, бой, выбор карты/круга/цели, триггер, порядок триггеров,
опциональная способность. Он не перехватывает клики и скрыт в ход
противника.
- Правило: выбор карты/круга/зоны/цели делается кликом/драгом по объекту
на поле, не кнопками; кнопки — только глобальные действия/подтверждения.
Зафиксировано в `AGENTS.md` и `docs/client-visual-direction.md`.
- Бой: динамическая плашка `POWER X vs SHIELD Y` (Power атакующего против
Power защищающегося + GuardShield), пересчитывается на каждом снимке, в
том числе после Guard. От атакующего к цели идёт затухающая 3D-стрелка,
которая следует за картами. ЛКМ по своей карте V/R открывает контекстное
меню с действиями из `LegalIntents` (атака/boost, перемещение, способность,
подробнее); карты противника и зоны открывают детали/списки. ПКМ по VC —
душа. Guardian-карты повёрнуты на 90° и уложены с перекрытием ~30%,
новые сверху; Trigger-зона зеркальна у противника. 3D-подписи зон скрыты,
включаются флагом `showZoneLabels`.
- Tejas может атаковать задний ряд противника своей колонки как с RC, так и
с VC (центральный задний ряд).
- Drag в бою: задний ряд → свой передний круг/Авангард объявляет поддержку,
после чего атаковать можно только поддерживаемой картой; передний круг →
карта противника объявляет атаку. Авангард поддерживается центральным
задним кругом. Barcgal имеет ACT `[Rest]` — поиск Llew/Flogal в колоде с
выбором круга призыва; найденные карты показываются оверлеем с плитками
карт и выбираются кликом по карте. Morgana после принятия способности
просит сбросить карту: доступные карты в руке подсвечиваются, выбор —
кликом по карте.
- Реальные арты: `imageKey` из `/api/cards` + `CardImageService` ищет
`Resources/CardArt/{imageKey}`. Скачаны все 124 арта. Импорт:
`tools/import_card_art.py`.
- Взаимодействие в бою: клик по картам/зонам, подсветка целей,
группировка действий (карты → цели, глобальные кнопки отдельно),
выбор силы/эффекта триггера, журнал последних событий. Позванные
rear-guard'ы входят в стоячем положении; rest — только после атаки/буста.
Атака проходит при силе атакующего **>=** силы защищающегося.
В первый ход атака запрещена; первый игрок определяется сидом.
- Отдельная сцена `Collection` и `CollectionView` удалены; коллекция
открывается из Lobby кнопкой «Коллекция» (сцена `DeckBuilder`).
- Не готово: 3D-модели карт/стола (пока процедурные примитивы и арты),
звук, настройки (язык уже есть), DOTween, drag&drop и live-валидация
декбилдера. Камера боя в покое фиксирована, но `CameraDirector` временно
ведёт trigger-последовательность. Не перенесены отдельные retire/ghost
анимации, `AttackResolutionQueue`, multi-target Soul Blast, world-space
Power/Shield.
## Запуск
Сервер (на `ssh home`):
```bash
cd ~/VanguardReMaster
docker compose up -d --build
curl http://127.0.0.1:18080/health
```
Клиент:
1. Unity Hub → `client`, редактор **6000.6.6f1**.
2. Открыть `Assets/Scenes/Boot.unity`, Play.
3. Стенд по умолчанию — `http://192.168.31.158:18080`.
Standalone Windows:
- В редакторе: `Vanguard → Build Windows Standalone`.
- Из CLI (пример для копии проекта):
```powershell
& 'C:\Program Files\Unity\Hub\Editor\6000.6.6f1\Editor\Unity.exe' `
-batchmode -nographics -projectPath client `
-executeMethod Vanguard.Editor.StandaloneBuild.BuildWindowsCli -quit
```
- Результат: `client/Builds/Windows/VanguardReMaster.exe` (папка в
`.gitignore`). Это обычное приложение, не Play Mode; сервер должен быть
доступен по адресу из `AppConfig`.
## Проверки клиента
```powershell
# EditMode
& 'C:\Program Files\Unity\Hub\Editor\6000.6.6f1\Editor\Unity.exe' `
-batchmode -nographics -projectPath client `
-runTests -testPlatform EditMode -testResults client\TestResults.xml
# Boot → Login + 3D environment
& 'C:\Program Files\Unity\Hub\Editor\6000.6.6f1\Editor\Unity.exe' `
-batchmode -nographics -projectPath client `
-executeMethod Vanguard.Editor.SceneSmoke.Run
# 3D playmat sandbox
& 'C:\Program Files\Unity\Hub\Editor\6000.6.6f1\Editor\Unity.exe' `
-batchmode -nographics -projectPath client `
-executeMethod Vanguard.Editor.SceneSmoke.RunPlaymat
```
Клиентские проверки: **67/67** EditMode (включая новые тесты TASK-2026-001:
повторный render скрытых карт, открытие урона, source-позиция нового юнита,
coalescing `CardMoveAnimator`; сборка всех экранов, импорт арта, перевод
строк, live-переключение языка, рендер 3D-доски, геометрия поля, правила
перемещения, рука в поле зрения камеры, обмен колоды/дропа, триггер-зона,
CardListView/Detail, зоны и рука противника, InputLock, контекстное меню,
стрелка атаки, prefab-оверлеи, раскладка на 1920×1080, авто-завершение
муллигана, одна кнопка защиты, отсутствие дублей в Guardian), `SCENE_SMOKE
success=True`, `PLAYMAT_SMOKE success=True cards=25 hand=5/5 fieldVisible=True`.
`SceneSmoke` заменяет PlayMode-тест загрузки сцен: Single-загрузка сцены
ломает стандартный PlayMode test runner. `SceneBuilder` пересобирает сцены:
```powershell
& '...\Unity.exe' -batchmode -nographics -projectPath client `
-executeMethod Vanguard.Editor.SceneBuilder.BuildAll
```
## Ключевые файлы клиента
```
client/Assets/Vanguard/Runtime/App/
VanguardApp.cs composition root, персистентный
SceneFlow.cs переходы Login/Lobby/DeckBuilder/Battle
SceneEnvironment.cs 3D-фон сцен
SceneControllerBase.cs
LoginSceneController.cs
LobbySceneController.cs
DeckBuilderSceneController.cs
BattleSceneController.cs
client/Assets/Vanguard/Runtime/UI/
LoginView.cs OnboardingView.cs
LobbyView.cs LobbyBackdrop.cs LobbyIcon.cs StubUi.cs
BattleEntryOverlay.cs ComingSoonOverlay.cs HamburgerMenu.cs
CommunityView.cs
DeckBuilderView.cs QueueView.cs BattleView.cs
UiKit.cs NeonUi.cs Localization.cs
client/Assets/Vanguard/Runtime/UI/Overlays/
OverlayNavigationService.cs стек список → детали
CardListView.cs общий горизонтальный список
CardDetailOverlay.cs крупная карта и текст
CardListModels.cs зоны и скрытые карты
ZoneBlockStripView.cs кликабельные блоки зон
CardActionMenuView.cs контекстное меню карты
OverlayPrefabs.cs загрузка prefab-оверлеев
client/Assets/Vanguard/Editor/
OverlayPrefabBuilder.cs сборка Resources/Overlays/*.prefab
StandaloneBuild.cs Windows standalone build
client/Assets/Vanguard/Runtime/Battle/
AnimationConfig.cs длительности/скорости анимаций
InputLockService.cs блокировка ввода по причинам
GameConnection.cs
client/Assets/Vanguard/Runtime/Board3D/
Config/PlaymatLayoutConfig.cs ScriptableObject-раскладка
Data/BoardTypes.cs зоны, круги, CardState3D, refs
Logic/PlaymatLayout.cs геометрия, рука, поиск цели броска
Logic/BoardPlacementRules.cs Ride/Call/Move/Guard
View/GameBoard3D.cs стол, круги, пул карт, drag&drop
View/Card3D.cs карта: лицо/рубашка/торец, Rest, флип
View/AttackArrowView.cs стрелка атаки с наконечником
PlaymatSandbox.cs демо без сервера
client/Assets/Vanguard/Resources/AnimationConfig.asset настройки анимаций
client/Assets/Vanguard/Resources/Overlays/*.prefab prefab-оверлеи
client/Assets/Vanguard/Resources/CardArt/vanguard_back.png рубашка VF
client/Assets/Vanguard/Scenes/GameBoard3D.unity песочница поля
client/Assets/Vanguard/Runtime/Api/ApiClient.cs + ApiContracts.cs
client/Assets/Vanguard/Editor/SceneBuilder.cs + SceneSmoke.cs
client/Assets/Vanguard/Scenes/*.unity
client/Assets/Plugins/Vanguard.Shared + MessagePack
```
## Решения
- 3D-визуал, отдельные сцены; подробно — `docs/client-visual-direction.md`.
- `Boot` не показывается; `VanguardApp`/сервисы не пересоздаются.
- Очередь — оверлей Lobby; DeckBuilder «В бой» возвращает в Lobby с
выбранной колодой в `SceneFlow.PendingQueueDeck`.
- Токены в `PlayerPrefs` — dev; для релиза защищённое хранилище.
- HTTP разрешён только для dev (`insecureHttpOption: 2`); для релиза HTTPS.
- `GameConnection` использует `System.Net.WebSockets.ClientWebSocket`
(Windows/десктоп first); WebGL потребует другого транспорта.
- Сервер авторитарный; клиент отправляет только интенты, скрытые данные
не покидают сервер.
## Следующие шаги
1. **TASK-2026-021 — Login по референсу: реализован, ждёт ручной приёмки**
(C10). EditMode 60/60, `SCENE_SMOKE success=True`, standalone собран.
**TASK-2026-022 — Lobby по референсу: реализован C1–C11, ждёт ручной
приёмки.** EditMode 62/62, `SCENE_SMOKE`, `PLAYMAT_SMOKE`, standalone
собраны и запущены. **TASK-2026-023 — DeckBuilder (один экран,
мультифильтры, список колоды): реализован C1–C11, ждёт ручной
приёмки.** EditMode 67/67, `SCENE_SMOKE`, `PLAYMAT_SMOKE`; standalone.
После приёмки — **TASK-2026-019** (загрузочная сцена, fade, кадр без
покадровых аллокаций).
2. **TASK-2026-001 — ручная проверка пользователем** (C10): draw, call, ride,
move/swap, guard, trigger, drive/damage, retire, search, открытие скрытого
урона, рука противника, повторные клики UI во время/после анимации.
Автотесты 47/47; код изменён в `GameBoard3D`, `CardMoveAnimator`,
`BattleView`, `AnimationConfig.asset` + тесты.
2. **TASK-2026-002 — реализован D1–D8, остались серверные проверки и
ручная приёмка.** Реализованы: hold-at-source для queued-карт,
drag-and-drop без локального `DropAt`, Tejas-колонка через границу
игроков, стадийный Perfect Guard (отдельная способность Sentinel после
размещения), боевые паузы 1.5 с, скрытие руки на trigger-зуме.
Клиентские EditMode-тесты 50/50. Серверные тесты (`Vanguard.Rules`)
— только на `ssh home`; ручная проверка — пользователь.
3. **TASK-2026-003 — боевой HUD по мокапу: реализовано, требуется ручная
приёмка.** Готово: правая панель действий убрана, подтверждения в правом
нижнем углу, debug-панель по кнопке, верхний HUD с Turn/фазами/таймером/
банком, центральный баннер хода, компактные панели игроков, `Drop/Soul`
из бара, `Deck` неинтерактивен, счётчик `x/6` над уроном, пластины
слотов, рамка/имя/бейдж триггера карты, статы под картой (`▲`/`◆`, крит
только >1), конкретные подписи триггеров (`+5000`, `Крит +1`,
`Поднять юнита`, `Взять карту`, `Лечить`), trigger-зум с плашкой
«Без триггера». Карты урона идут сверху вниз с перекрытием 30%, новая
поверх старой; trigger-карта повёрнута на 90° против часовой. Имена карт
на поле убраны; панель действий — компактные кнопки справа снизу; рука
центрируется по экрану; подсказка муллигана — в верхней панели, при
выборе карт появляется «Заменить N карт»; центральный баннер убран;
левый бар — `Колода, Душа, Рука, Сброс`, `Душа/Сброс` кликабельны.
EditMode 50/50, серверные правила 155/155, standalone собран, клиент
запущен. Триггер: фокус камеры → анимация раскрытия карты → пауза
0,75 с → резолв; затем выбор `+5000` и эффекта (`Critical` — RC/VC,
`Stand` — только повёрнутый RC, `Draw` — авто, `Heal` — карта урона);
подсказки в верхнем блоке. Урон переворачивается вокруг длинной стороны.
Tejas: колонка `V↔1/3↔2/4↔0`, сервер пересобран и задеплоен на
`ssh home`. В Основной фазе — только кнопка «Боевая фаза». Рамка карты —
тонкая чёрная по краю, в руке рамка скрыта; карты лежат широким веером,
своя рука заполняется слева направо, новая карта добавляется правее и
остаётся поверх предыдущей, ширина сохраняется до 10 карт и плавно
уменьшается начиная с 11-й. Рука противника — зеркальный камеро-зависимый
веер ниже верхней панели: новая карта слева, наклон и глубина зеркальны;
позы обеих рук обновляются каждый кадр, добор не летит к устаревшей цели.
Это закреплено тестом `Hands_Fill_Mirrored_And_Newest_Is_On_Top` (58/58).
Возврат карт в колоду: старая карта уходит из руки по дуге под низ колоды
с переворотом рубашкой вверх; следующая стартует только после завершения
предыдущей. Рука идёт ступенчатым reflow: после каждого ухода оставшиеся
карты, включая ожидающие возврата, сдвигаются под новое количество.
Длительность как у добора (`DrawDuration` / `introDrawDuration = 0.6`),
у противника зеркально. Стартовый
Авангард закрыт до конца муллиганов (`MatchProjection` передаёт реальный
`FaceUp`), затем переворачивается вокруг длинной оси слева направо
(у противника зеркально).
Старт боя: камера над стороной игрока лицом к столу, 1,5 с → дуга вниз
на основную позицию → пауза 1,5 с → одновременный добор обеих рук →
только потом муллиган. Добор общий: карта стартует ровно над колодой
полного размера (`cardScale`), рубашкой вверх, летит в руку с переворотом
лицом вверх; длительность как в муллигане — `introDrawDuration = 0.6 с`.
Любой добор последовательный — следующая карта только после предыдущей.
Частично: bloom/свет
и HUD-анимации. 2026-10-27: боевые feedback-баннеры, вспышки и кнопка
«Пропустить анимации» удалены; журнал событий и trigger-подсказки
оставлены. Рука перестраивается под новое количество одновременно с
перемещением уходящей карты (любой выход из руки). При доборе новые
карты показываются по одной, а рука расширяется после каждой. Раскладка
руки идёт через единый `_visualHandCards`: остатки, возвращаемые и уже
добранные карты участвуют в сдвиге после каждого изменения. Hover карты
в руке плавно поднимает её на 10% высоты и возвращает после ухода курсора.
Карта из руки при зажатии ЛКМ не двигается и остаётся в руке
приподнятой; курсор наводится на зону, при отпускании над VC выполняется
смена. Цель определяется raycast-ом по VC-карте/кругу, затем плоскостью.
Невалидный drop оставляет карту в руке. Валидные для смены карты
подсвечиваются в руке; по логу это были TD02/007EN и BT01/015EN.
Карты поля сохраняют обычный drag. EditMode 58/58.
Детали — `docs/Development/IMPLEMENTATION_PLAN.md`.
4. 3D UX: P0 (движение, ориентации, камера/триггер) и базовый P1 (стрелки,
multi-target Counter Blast) готовы. Осталось: `AttackResolutionQueue`,
multi-target Soul Blast/прочие стоимости, отдельный `CostPaymentOverlay`,
world-space Power/Shield (верхний strip принят как HUD), world-space
dash shader; полировка позиций на конкретном мониторе.
4. Декбилдер: drag&drop карт, пресеты, предупреждение о
несохранённых изменениях, «Все/Ничего» по секциям фильтра.
5. 3D-наполнение: модели карт/стола, prefab-экраны сцен, анимации retire/ghost.
6. Звук и настройки, DOTween.
7. Лаунчер WPF.
Тренировка с ботом и боевой UI с артами/анимациями/локализацией уже есть.
## Подводные камни
- Не запускать `dotnet`/Docker на рабочем ПК; сервер проверяется на `ssh home`.
- В Unity нельзя открыть два экземпляра одного проекта: для batch-проверок
делать копию проекта (без `Library`) или закрывать редактор.
- Сцены ссылаются на скрипты по GUID; при копировании сцен копировать и
`.meta` контроллеров.
- `Vanguard.Shared.dll` — netstandard2.1 + MessagePack 3.1.12; при изменении
протокола пересобрать DLL и заменить в `client/Assets/Plugins`.
- `UiKit.CreateCanvas` по умолчанию **не** персистентный: Canvas принадлежит
сцене; EventSystem остаётся персистентным.
- Сцена `Boot` должна быть первой в Build Settings; сейчас там
`Boot`, `Login`, `Lobby`, `DeckBuilder`, `Battle`.