VanguardReMaster/docs/SESSION-STATE.md

41 KiB
Raw Blame History

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, онбординг, коллекция с разбором, декбилдер (топбар Lobby, крупная сетка карт 6 в ряд со скроллом, мультифильтры в оверлее, справа список колод ⇄ состав), магазин (бустер/триал-дека), история матчей и реплей, очередь, WebSocket-матч (snapshot, интенты, маллиган, сдача, GameFinished), таймер, результат.
  • Декбилдер: DeckBuilderView + общий PlayerTopBar, 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):

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 (пример для копии проекта):
    & '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.

Проверки клиента

# 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

Клиентские проверки: 69/69 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 пересобирает сцены:

& '...\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. TASK-2026-024 — DeckBuilder по референсу (топбар Lobby, крупные карты, фильтры в оверлее): реализован C1–C10, ждёт ручной приёмки. EditMode 69/69, 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 + тесты.
  3. 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; ручная проверка — пользователь.
  4. 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.
  5. 3D UX: P0 (движение, ориентации, камера/триггер) и базовый P1 (стрелки, multi-target Counter Blast) готовы. Осталось: AttackResolutionQueue, multi-target Soul Blast/прочие стоимости, отдельный CostPaymentOverlay, world-space Power/Shield (верхний strip принят как HUD), world-space dash shader; полировка позиций на конкретном мониторе.
  6. Декбилдер: drag&drop карт, пресеты, предупреждение о несохранённых изменениях, «Все/Ничего» по секциям фильтра.
  7. 3D-наполнение: модели карт/стола, prefab-экраны сцен, анимации retire/ghost.
  8. Звук и настройки, DOTween.
  9. Лаунчер 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.