Add project skill for architecture rules and abilities
CI / test (push) Has been cancelled Details

This commit is contained in:
MpakobecEx 2026-10-24 01:22:35 +05:00
parent 228bc4ce8c
commit 923b82be85
1 changed files with 257 additions and 0 deletions

View File

@ -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 <copy> `
-runTests -testPlatform EditMode -testResults <copy>\TestResults.xml
```
Smoke: `Vanguard.Editor.SceneSmoke.Run` и `RunPlaymat`. Windows build:
`Vanguard.Editor.StandaloneBuild.BuildWindowsCli`.
После блока: тесты, `validate`, `translations check`, коммит и push.