From 923b82be8563774768ab8ca09777a7feea107aca Mon Sep 17 00:00:00 2001 From: MpakobecEx Date: Sat, 24 Oct 2026 01:22:35 +0500 Subject: [PATCH] Add project skill for architecture rules and abilities --- .opencode/skills/vanguard-remaster/SKILL.md | 257 ++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 .opencode/skills/vanguard-remaster/SKILL.md diff --git a/.opencode/skills/vanguard-remaster/SKILL.md b/.opencode/skills/vanguard-remaster/SKILL.md new file mode 100644 index 0000000..54a93c4 --- /dev/null +++ b/.opencode/skills/vanguard-remaster/SKILL.md @@ -0,0 +1,257 @@ +--- +name: Vanguard ReMaster +description: Use for any work in the Vanguard ReMaster repository: server rules and card abilities, battle mechanics, WebSocket/MessagePack protocol and networking, Unity client UI/3D board, tests, deployment, or project structure questions. +--- + +# Vanguard ReMaster + +Рабочие правила для этого репозитория. Сначала прочитать +`docs/SESSION-STATE.md`, затем `docs/HANDOFF.md` и +`docs/client-visual-direction.md`. + +## 1. Структура проекта + +```text +content/ + sets/*.yaml карты, принты, тексты, флаги механик + translations/ru.yaml русские тексты и токены + keywords.yaml ключевые слова +docs/ протокол, правила, состояние, аудит способностей +server/ + src/Vanguard.Shared/ DTO, MessagePack-контракты, union-типы, проекции + src/Vanguard.Content/ загрузка YAML, каталог карт, валидация контента + src/Vanguard.Rules/ чистое игровое ядро: состояние, команды, события + src/Vanguard.Server/ ASP.NET, auth, meta, matchmaking, Orleans, WebSocket + src/Vanguard.Cli/ validate, stats, translations, stress, deck + tests/Vanguard.Rules.Tests/ тесты правил и карт + tests/Vanguard.Server.Tests/тесты сервера и инфраструктуры +client/Assets/Vanguard/ + Runtime/Api/ HTTP-клиент и DTO мета-API + Runtime/Auth/ JWT, refresh, TokenStore + Runtime/State/ PlayerState и клиентское состояние + Runtime/Meta/ каталог карт, коллекция, колоды + Runtime/Battle/ GameConnection, InputLockService, анимации + Runtime/Board3D/ 3D-поле, карты, слоты, зоны, drag&drop + Runtime/UI/ uGUI-экраны и оверлеи + Runtime/App/ сцены, SceneFlow, bootstrap + Editor/ сборка сцен, Windows standalone, smoke-проверки + Tests/Editor/ Unity EditMode тесты +``` + +Ключевые границы: + +- `Vanguard.Rules` — чистая библиотека. Не добавлять в неё сеть, БД, + Orleans, Unity или файловый I/O. +- `Vanguard.Shared` — контракты. `netstandard2.1`-сборка используется Unity, + поэтому там только DTO/сериализация без ссылки на `Vanguard.Rules`. +- `Vanguard.Server` зависит от `Rules`, `Shared`, `Content`; обратной + зависимости быть не должно. +- Клиент не является источником истины: правила, скрытая информация и + случайность остаются на сервере. + +## 2. Сетевой код + +### Протокол + +- Транспорт матча — WebSocket `/game`, бинарные MessagePack-фреймы. +- Контракты и union-номера — только в `Vanguard.Shared/Protocol`. + Не дублировать DTO в клиенте или сервере. +- Изменение union-номера или `[Key(n)]` — ломающее изменение протокола. + Добавлять новые поля/типы, не переиспользовать старые номера. +- `ProtocolConstants.Version` и `MaxFrameBytes` — общие ограничения. + Сервер обязан отклонять неизвестную версию и слишком большой фрейм. +- `ClientIntent` содержит `intentId` (GUID) и `basedOnSeq`; повтор с тем же + `intentId` должен быть идемпотентным. Результат — `ServerIntentResult`. +- `eventSeq` монотонно растёт. Клиент не применяет события старше + `LastSeq`; для пропуска — `ClientResync` и полный snapshot. +- Сервер присылает `ServerHello`, `ServerSnapshot`, `ServerEvents`, + `ServerIntentResult`, `ServerClock`, ping/pong и `ServerError`. +- Скрытые данные (колода, рука противника, закрытый урон, seed) не уходят + клиенту. Проверять каждую новую view/проекцию. + +### Сервер + +- HTTP-концы и realtime разделены: REST — мета/аутентификация/матчмейкинг, + WebSocket — только матч. +- `GameWebSocketEndpoint` принимает соединение; `MatchConnectionRegistry` + связывает игрока с матчем; `MatchGrain` хранит авторитарное состояние и + обрабатывает интенты. +- Команда проходит: intent → проверка `basedOnSeq`/идемпотентности → + `GameEngine.Execute` → события → snapshot/clock. +- Нельзя доверять клиентским `slot`, `printingId`, `damageIndex` и спискам + целей: сервер заново проверяет их по своему состоянию. +- Ошибки — через `ServerIntentResult`/`ServerError`, не через исключения + наружу. Внутренние исключения логировать, наружу отдавать код/причину. +- Reconnect/resume: новый сокет с `resumeFromSeq`; при невозможности — + полный snapshot. Не пересоздавать матч из-за обрыва. + +### Клиент + +- Вся сеть — в `GameConnection`: connect, send, receive loop, ping, + pending intents, seq, reconnect. UI не работает с сокетом напрямую. +- `BattleView`/`MatchGrain`-клиентская часть только читает `MatchView` и + отправляет `IntentPayload`; не менять локально авторитарное состояние. +- Пока `_sending`/`_snapshotPending`/reconnect overlay активны, ввод + блокируется; stale input locks освобождаются по состоянию UI. +- После `SnapshotReceived`/`ServerHello` перерисовать поле из snapshot, а не + накапливать догадки по событиям. +- Все сетевые операции — async + `CancellationToken`; не блокировать + Unity-поток. + +## 3. Способности карт + +Источник текста — `content/sets/*.yaml` (`textEn`). Каждая текстовая +способность должна иметь ровно одну реализацию: `CardScript`, общий движок +или флаг данных. Текст без реализации — баг. Полный аудит: +`docs/ability-implementation.md`. + +### AUTO + +`AbilityDefinition`: + +```csharp +new AbilityDefinition +{ + Trigger = AbilityTrigger.OnPlace, + Condition = ctx => ..., + Optional = true, + CanPay = ctx => ..., + Pay = ctx => ..., + Resolve = ctx => ... +} +``` + +- `Trigger` — только реальное окно события: `OnPlace`, `OnRideOver`, + `OnAttackDeclared`, `OnAttackHit`, `OnBoost`, `OnBoostedHit`, + `OnDriveCheck`, `OnGuard`, `OnRetireFromRC`, `OnOpponentRetire`, + `OnLeaveGuardian`, `OnPhaseStart`, `OnDamageTaken`. +- Проверять зону источника: `IsVanguardOf`, `IsRearGuardOf`, `IsInHand`. + `OnPlace` не должен срабатывать от VC, если текст требует RC. +- `Optional` + `CanPay`/`Pay` — для «you may pay the cost». Без оплаты + эффект не выполняется. +- Несколько целей/карт — только `AskUnitChoice`, `AskUnitMultiChoice`, + `AskHandCardChoice`, `AskEmptyRearGuardChoice`. +- AUTO не должен напрямую менять UI; сервер меняет состояние и добавляет + события. Клиент показывает оверлей подтверждения для optional. + +### ACT + +`ActivatedAbility`: + +- `CanActivate` — только проверка условий; оплата и эффект в `Resolve` + (или `Pay` для AUTO). +- Флаги: `RestsSelf`, `RetiresSelf`, `RequiresDiscard`, `FromHand`, + `FromDropZone`. +- ACT из руки/дропа попадает в `LegalCommands` только в разрешённой фазе; + клиент показывает действие у карты, не отдельным глобальным списком. +- Стоимость (discard, Counter Blast, field units) выбирается по объектам + в руке/уроне/поле; подтверждение — кнопка панели «Действия». +- `RetiresSelf`/`RestsSelf` не должны активироваться из руки/дропа, если + текст этого не разрешает. + +### CONT + +- Сила/критика — `ContinuousAbility` с `Applies`, `PowerBonus`, + `CriticalBonus`. +- Ограничения, которые не выражаются бонусом, — отдельный движок: + `RestrictionType` (`CannotAttack`, `CannotBoost`, `CannotStand`, + `CannotIntercept`, `CannotBeChosen`) или `CardScript.CanBeBoosted`. +- CONT пересчитывается из состояния каждый раз; не хранить вычисленную + силу как истину. + +### Общие механики + +- **Sentinel** — данные `sentinel`; общий Guard + сброс карты того же клана. + Отдельный `CardScript` не нужен. +- **Heal/Trigger** — данные `trigger`; общий движок drive/damage check. +- **Tejas** — `snipeBackRow` в данных + общий движок атаки заднего ряда. +- **Restraint** — флаг `restraint` + `IsRestraint`; ACT снимает через + `RestraintOverride`. +- **Boost/Intercept** — `hasBoost`/`hasIntercept` и общий движок. +- **Perfect Guard** — Sentinel + optional discard cost; nullify до конца боя. + +### Клиентские правила способностей + +- ACT/AUTO выбираются кликом по карте/цели, а не списком кнопок. +- OPTIONAL AUTO — модальный оверлей «Активировать»/«Пропустить». +- Сброс для стоимости — клик по карте в руке. +- Counter Blast — клик по карте урона; доступные/выбранные подсвечиваются. +- Подтверждение оплаты — в панели «Действия»; отмена — правый клик. +- Карта в руке с ACT: клик открывает меню действий с валидными пунктами + (Призвать/Сменить/Активировать/Подробнее). Смена/призыв также работают + драгом. + +## 4. Новые карты и изменения правил + +Порядок: + +1. Добавить/исправить карту в `content/sets/*.yaml`; текст — `textEn`. +2. Найти все AUTO/ACT/CONT/ключевые механики в тексте. +3. Реализовать в `CardScripts` или общем движке; не оставлять дублей. +4. Добавить хотя бы один тест на триггер/активацию/условие. +5. Проверить `CardScripts.Default` целиком: нет ли карты с текстом без + скрипта. +6. Прогнать серверные тесты, `validate`, `translations check`. +7. Для клиентских изменений — Unity EditMode, `SCENE_SMOKE`, + `PLAYMAT_SMOKE`, пересобрать standalone. + +## 5. Игровые механики + +- **Ride**: hand → VC; ранг не выше текущего +1. Старый Vanguard уходит в + soul. Первый ход: без Battle. +- **Call**: hand → RC. Занятый RC разрешён: старый юнит уходит в Drop. + Правило действует также для call из soul/deck и выбора круга. +- **Move**: RC ↔ RC только в своей колонке; занятые круги меняются местами. +- **Attack**: только передний ряд; цель — Vanguard или передний RC + противника. Tejas может бить задний ряд своей колонки. +- **Boost**: стоящий юнит заднего ряда → передний юнит/VC той же колонки; + сила бустера добавляется до конца боя. +- **Guard**: карты из руки, ранг не выше ранга своего Vanguard. Выбор + карт/перехватчиков — по объектам; одна кнопка «Не защищаться»/ + «Защищаться». Щит учитывается сразу; после подтверждения — Guardian. +- **Intercept**: подходящий RC; атака переносится на него. +- **Drive/Damage Check**: только по правилам; триггеры/Heal — общий движок. +- **Counter Blast/Soul Blast/Soul Charge/Counter Charge** — общие методы + `GameEngine`, не дублировать в скриптах. +- **Победа**: 6 damage; после 4+ heal уходит в drop. Проверять инварианты + зон и уникальность `instanceId`. + +## 6. Клиентские взаимодействия + +- Выбор — клик/драг по карте, кругу, зоне или полю. Кнопки — только + глобальные действия и подтверждения. +- Drag-жесты: + - передний ряд → карта противника: attack; + - задний ряд → передний ряд/VC: boost; + - рука → RC: call; + - рука → VC: ride. +- Панель «Действия» не показывает полный список смен; действия берутся из + меню выбранной карты и валидных интентов. +- Информационные оверлеи не перехватывают клики и не дублируют выбор + кнопками. + +## 7. Проверки и окружение + +```powershell +# сервер — только на ssh home / Docker, не локальным dotnet +ssh home "docker run --rm -v ~/VanguardReMaster-test:/src -w /src \ + mcr.microsoft.com/dotnet/sdk:10.0 dotnet test server/Vanguard.slnx" + +# validate / translations +ssh home "docker run --rm ... dotnet run --project server/src/Vanguard.Cli -- validate" +ssh home "docker run --rm ... dotnet run --project server/src/Vanguard.Cli -- translations check" +``` + +Клиент: Unity **6000.6.6f1**, URP. Не открывать второй Unity с тем же +проектом; batch-проверки — в копии без `Library`. Тесты: + +```powershell +& 'C:\Program Files\Unity\Hub\Editor\6000.6.6f1\Editor\Unity.exe' ` + -batchmode -nographics -projectPath ` + -runTests -testPlatform EditMode -testResults \TestResults.xml +``` + +Smoke: `Vanguard.Editor.SceneSmoke.Run` и `RunPlaymat`. Windows build: +`Vanguard.Editor.StandaloneBuild.BuildWindowsCli`. + +После блока: тесты, `validate`, `translations check`, коммит и push.