16 KiB
16 KiB
Решения, процесс и антипаттерны
1. Источники аудита
[C] Проверены:
.opencode/skills/vanguard-remaster/SKILL.md(прежняя версия);AGENTS.md,docs/SESSION-STATE.md,docs/HANDOFF.md,docs/game-rules.md,docs/ability-implementation.md,docs/protocol.md,docs/client-visual-direction.md,docs/3d-ux-backlog.md,docs/translation-rules.md;- локальная база OpenCode: две сессии Vanguard ReMaster (1259 и 5617 сообщений), включая сообщения пользователя и финальные тексты ассистента;
- исходный код server/client, YAML-контент, тесты,
README.md,DEVELOPMENT_CHECKLIST.md,content/cards-mvp.md.
История доступна локально, но не является «полной истиной»: часть решений могла быть принята вне OpenCode. В спорных местах ниже стоит [O], а не выдуманное правило.
2. Подтверждённые решения
Игра и контент
- [D] Фанатский ремейк Vanguard, формат Classic, BT01 + TD01/TD02, 94 карты / 124 принта.
- [D] Две триал-деки: TD01 «Blaster Blade», TD02 «Dragonic Overlord»; полный декбилдер.
- [D] Официальные арты; локализация EN + RU.
- [D] В коллекции нет лимита копий/артов; 4 копии по имени — только при сборке колоды.
- [D] Смешивать кланы в колоде разрешено; эффекты с клановыми условиями могут не работать. Это осознанное правило проекта.
- [D] Сайд-дека нет, матч BO1.
- [D] Ride Deck/Persona Ride не входят в Classic/текущую игру.
- [D] Стартовый авангард — grade 0 без триггера; после обучения игрок получает триал-деку на выбор и 5 токенов; 1 токен = 1 бустер.
- [D] Таймер: 90 с на ход + банк 5 мин; отсутствие/сдача/разрыв — поражение.
- [D] В первый ход нельзя атаковать и переходить в Battle.
- [D] Локализация: RU+EN; «ё» разрешена; «усиленная карта»; «уничтожить»
оставляем; фазы — Основная/Боевая/Завершающая/Подъёма/Добора/Смены;
close step — завершающий шаг; call — призвать; названия зон не переводим;
имена карт остаются английскими (
nameRu— задел). Детали —docs/translation-rules.md.
Бустеры и экономика
- [D] В бустере 5 карт: 4 C + 1 гарантированная R+.
- [C] Текущие веса R+: R 70% / RR 22% / RRR 7% / SP 1%
(
content/pack_odds.yaml). Пользователь поручил подобрать вероятности, но точные числа не перепроверял; это конфиг, а не вечный закон. - [D] Дубли считаются по
printingId, порог 4; SP — отдельный принт; при отсутствии замены карта остаётся в коллекции и разбирается в пыль. - [D] Gold начисляется за победу и поражение; [C] текущая конфигурация — 30 / 15 / 20 (победа/поражение/ничья), Gold = XP / 5. Точные числа — балансный конфиг, можно менять.
- [C] Бустер 100 Gold, триал-дека 500 Gold; за сдачу/АФК награды не
начисляются (
RewardsForForfeit = falseпо умолчанию). - [C] Пыль: разбор C/R/RR/RRR = 5/10/25/100, крафт ×4; фойл ×2.
- [C] XP пишется с первого дня; баттлпасс/квесты/Draft — после MVP.
Клиент и UX
- [D] 3D-сцена, отдельные сцены Login/Lobby/DeckBuilder/Battle; HUD — uGUI; reference 1920×1080.
- [D] Камера в покое фиксирована по центру поля с небольшим наклоном;
временно двигается только
CameraDirectorв trigger-последовательности. - [D] Выбор карты/круга/зоны/цели — клик/драг по объекту; кнопки только для глобальных действий/подтверждений.
- [D] Guard: карты из руки с grade ≤ grade своего Vanguard; одна кнопка «Не защищаться»/«Защищаться»; выбранные подсвечиваются, щит считается сразу, после подтверждения — в Guardian.
- [D] Карты противника нельзя драгать; можно выбирать целью, смотреть детали и зоны. Клик по своей карте — меню валидных действий.
- [D] Зоны открываются общим горизонтальным
CardListView; сверху — последняя добавленная карта; из списка доступенCardDetailOverlay. - [D] Call в занятый RC разрешён; старый юнит → Drop.
- [D] Move: RC↔RC в колонке; занятые меняются; при единственном доступном круге клиент перемещает сразу.
- [D] Draw: после цели силы сразу тянет карту; Heal: только своя зона урона и только при условиях; Tejas: задний ряд своей колонки.
- [D] Optional AUTO — оверлей «Активировать/Пропустить»; ACT из руки — меню карты; оплата — по объектам, подтверждение в панели/оверлее.
- [D] Mulligan: выбор карт в руке; после замены этап завершается автоматически, неактивная кнопка «Закончить муллиган» не остаётся.
- [D] Панель фаз переименована в «Действия» и содержит guard, подтверждение оплаты и глобальные действия; список всех возможных смен там не показывается.
- [D] Под картами V/R показываются динамические Power/Critical;
верхний
CombatStatsstrip — допустимый HUD; world-space Power/Shield — отложенный долг. - [D] Отдельный
CostPaymentOverlayдля multi-target стоимости нужен; текущий CB в панели «Действия» — промежуточная реализация.
3. Фактическое устройство (не путать с договорённостью)
- [C]
GameEngine— авторитарное ядро;MatchGrainсериализует интенты;MatchProjectionскрывает информацию. - [C] Multi-target CB уже поддержан
DamageIndexesвActivateAbilityIntent; старыйDamageIndexоставлен. - [C]
CardMoveAnimator,CameraDirector,TriggerCheckSequence,ArrowDirectorесть; анимации наTick, без UniTask/DOTween. - [C]
CardMoveAnimatorимеет таймаут иCancelCard; это исправление зависшегоcard-move-лока (коммитfd21a96). - [C]
DropZoneFaceDownесть, defaultfalse. - [C]
DeckValidatorне проверяет единство клана; это соответствует решению «смешивать можно». - [C]
CombatStats— верхний uGUI strip; отдельного боевого overlay нет. - [C]
docs/protocol.mdранее указывал неверный порядок отображения урона; фактически сначала открытые, затем закрытые.
4. Процесс разработки
Формальный двухэтапный процесс DeepSeek → Kimi описан в
docs/Development/AGENT-WORKFLOW.md; активный план задачи — в
docs/Development/IMPLEMENTATION_PLAN.md. Ниже — краткие правила, без
дублирования шаблона плана.
- Прочитай Skill и связанные docs; найди существующую реализацию.
- Проверь, не решён ли вопрос в коде/истории. Не спрашивай о том, что уже установлено.
- Если есть существенная неопределённость —
questionс 2–4 вариантами. - Вноси минимальные изменения; не трогай несвязанное.
- Для правил: тест на сценарий; для карт — тест на триггер/активацию; для клиента — EditMode/smoke.
- Серверные проверки — только
ssh home/Docker; Unity batch — копия безLibrary. - После блока:
validate,translations check, коммит/push. - Геймплей вручную проверяет пользователь; не выдавай свой тест за приёмку.
5. Антипаттерны
| Не делать | Почему | Как делать |
|---|---|---|
| Список кнопок вместо клика по карте/кругу | Нарушает принятый UX | Подсветка объектов + клик/драг |
transform.position = ... в игровой логике |
Ломает анимации/локи | Card3D/CardMoveAnimator/SetPose |
Дублировать эффект в нескольких CardScript |
Расходится поведение | Один CardScript, общий движок или флаг |
OnPlace без проверки VC/RC |
Срабатывает не в той зоне | IsVanguardOf/IsRearGuardOf |
Менять GameState на клиенте |
Рассинхрон с сервером | Только IntentPayload, рисовать snapshot |
Запускать dotnet/Docker локально |
Запрещено пользователем | ssh home/Docker |
| Второй Unity с тем же проектом | Ломает Library/импорт | Копия без Library |
| Заявлять тест без запуска | Вводит в заблуждение | Указать, что проверено, а что нет |
| Самому проходить геймплей как приёмку | Пользователь проверяет лично | Автотесты + передать сценарий |
Менять Vanguard.Shared без пересборки DLL |
Unity увидит старый контракт | Собрать netstandard2.1 и заменить DLL |
Вечный InputLock без таймаута |
Блокирует ход/смену | try/finally, timeout, CancelCard |
| Освобождать карту из пула во время анимации/обмена | Дубли/неактивные карты | Сначала распределить по InstanceId, потом release |
| Новый универсальный effect/DSL без нужды | Усложняет и дублирует | Расширять существующие AbilityDefinition |
| Хранить вычисленную силу как истину | CONT пересчитывается | EffectivePower/модификаторы |
| Показывать все возможные смены в панели | Пользователь это запретил | Действия из меню карты/валидных интентов |
| Перехватывать клики информационным оверлеем | Мешает выбору по объекту | raycastTarget = false/скрыть ввод |
Считать printingId и nameId одним |
Ломает лимиты/коллекцию | nameId — 4 копии, printingId — принт |
| Perfect Guard даёт щит без оплаты | Неверная защита | Без оплаты 0 щита и нет nullify |
| Heal просит цель при невыполненных условиях | Лишний выбор/зависание | Сначала серверная проверка, потом AskDamageChoice |
6. Известные ошибки и уроки
- Зависший
card-move-лок (2026-10-24): карта освобождалась из пула, оставаясь в_active;Tickбольше не вызывался,InputLockне снимался. Исправлено таймаутом/CancelCard. Не возвращать. - Дубли/нахлёст при обмене RC: нельзя освобождать карту из занятого
ключа, если она должна переехать в другой ключ. Сначала распределение по
InstanceId, затем release. - Conroe долго не имел AUTO
OnRideOver— проверять весь текст, а не только очевидные ACT/CONT. - Barcgal: при выборе призыва из колоды клиент должен показать оверлей доступных карт; не подставлять первый круг/карту автоматически.
- Ride после хода противника ломался из-за клиентского ввода/логики, а не
только сервера; проверять lock и
LegalIntents. - Пустой Mulligan: после замены карт кнопка «Закончить муллиган» не должна оставаться неактивной; муллиган завершается автоматически.
- Guard дубли: Guardian и
Battle.GuardCardsмогут содержать одну карту; клиент дедуплицирует поInstanceId. - Perfect Guard: без discard карта даёт 0 щита; не считать Sentinel обычным щитом.
- Trigger check: карта сначала в Trigger, затем эффект, затем hand/ damage; не переставлять.
7. Открытые вопросы
- [O] Отдельная проверка «авангард исчез» в
GameEngineотсутствует; нужно ли добавлять — решать пользователю. - [O]
OnPlace+OnRideOverпри pending-способностиOnPlace: текущая реализация может не запуститьOnRideOver; нужно ли чинить — отдельное решение. - [O] Multi-target Soul Blast/другие стоимости: протокол и UI ещё не сделаны.
- [O]
CostPaymentOverlayтребуется, но его форма/EffectConfigи момент включения ещё не реализованы; текущий CB — промежуточный. - [O] World-space Power/Shield: верхний strip принят как HUD, перенос — долг.
- [O]
AttackResolutionQueueи несколько boost-стрелок — будущая архитектура, сейчас бой с одной целью. - [O]
DropZoneFaceDownUX: defaultfalse; нужен ли другой режим — не решено. - [O] Точная легальность формата/banlist и обязательность ровно одного
стартового авангарда в
DeckValidatorне выделены. - [O] Полная история вне OpenCode недоступна; спорные места не считаются восстановленными.