17 KiB
Передача сессии
Состояние проекта на 21 октября 2026. Документ нужен, чтобы новая сессия продолжила работу без повторного разбора истории.
1. Проект
Фан-ремастер Cardfight!! Vanguard базовой эры (2011), формат Classic. MVP: бустер BT01 + триал-деки TD01/TD02 — 94 карты, 124 принта.
Стек:
- сервер — .NET 10, планируются Orleans, PostgreSQL, Redis;
- клиент — Unity 6 (ещё не начат);
- лаунчер — WPF (ещё не начат);
- контент — YAML + C#-скрипты карт;
- транспорт — WebSocket/TCP + MessagePack (решение зафиксировано, кода ещё нет).
Репозиторий:
- ветка
master; - remote
ssh://git@192.168.31.158:2222/mpakobecex/VanguardReMaster.git; - последний коммит на момент передачи —
99532b6; - рабочее дерево чистое.
Главные принципы:
- сервер авторитарный, клиент тонкий;
- скрытая информация (колода, рука противника, закрытый урон, seed) не уходит клиенту;
Vanguard.Rules— чистая библиотека без сети, БД и Orleans: команда на вход, события на выход;- каждый блок работы коммитится и пушится в
master.
2. Текущее состояние
| Проверка | Результат |
|---|---|
| Тесты | 117/117 |
validate |
0 ошибок, 0 предупреждений |
translations check |
94/94 |
stress 1000 |
1000/1000 партий, 0 ошибок |
| Карты | 94/94 (66 с текстом + 28 ванильных) |
| Сервер / клиент / лаунчер | не начаты |
Блок «Игровое ядро» из IMPLEMENTATION_CHECKLIST.md закрыт по его критериям:
боты доигрывают 1000 партий, инварианты держатся, реплей воспроизводится
бит-в-бит по хэшу событий.
3. Как проверить
dotnet установлен в %LOCALAPPDATA%\dotnet, поэтому в PowerShell:
$env:PATH = "$env:LOCALAPPDATA\dotnet;$env:PATH"
dotnet test server\Vanguard.slnx
dotnet run --project server\src\Vanguard.Cli -- validate
dotnet run --project server\src\Vanguard.Cli -- translations check
dotnet run --project server\src\Vanguard.Cli -- stress 1000
Ожидаемо:
Пройден! : не пройдено 0, пройдено 117
OK: ошибок 0, предупреждений 0
Переведено: 94/94
Партий: 1000, завершено: 1000, ошибок: 0
Solution — server/Vanguard.slnx, не .sln.
4. Что сделано
4.1. Контент
- 94 карты, 124 принта в
content/sets/BT01.yaml,TD01.yaml,TD02.yaml. - Импортёр
tools/import_cards.py. - Валидатор контента: щиты, Sentinel, параллельные арты, лимиты колоды.
- Токенизация текстов,
content/keywords.yaml. - Русские переводы
content/translations/ru.yaml— 94/94. - Канон перевода
docs/translation-rules.mdv0.8.
4.2. Игровое ядро
server/src/Vanguard.Rules/Engine/GameEngine.cs.
Реализовано:
- фазы
Mulligan → Stand → Draw → Ride → Main → Battle → End; - стартовый Авангард, маллиган, добор;
- райд, призыв, перемещение в пределах колонки (занятый круг меняется местами);
- атака по Авангарду и переднему ряду Арьергарда;
- поддержка, перехват, идеальная защита (Sentinel);
- drive check и damage check с выбором целей;
- триггеры: Critical, Stand, Draw, Heal;
- победа/поражение, детерминированный RNG;
- стоимости: Counter Blast, Soul Blast, сброс, поворот себя, уничтожение себя;
- поиск в колоде без просмотра, поиск с призывом и с райдом;
- просмотр верхней карты;
- способности:
Triggered,Continuous,Activated; - модификаторы силы/крита с источником и сроком жизни (
StatModifier); - выдача и снятие способностей (
GrantedAbility); - запреты (
CardRestriction): не вставать, не атаковать, не поддерживать, не перехватывать, не быть выбранным; - снятие Сдерживания эффектом;
- возврат карты с поля в колоду после боя и в конце хода;
- способности из руки, сброса и круга защиты;
AskUnitMultiChoiceдля «до N» / «ровно N»;LegalCommands()— все легальные команды текущего момента;GameInvariants.Check()— проверка 50 карт, уникальныхinstanceId, урона ≤ 6.
Триггеры (AbilityTrigger):
OnRideOver, OnPlace, OnBoost, OnBoosted, OnBoostedHit, OnDriveCheck,
OnGuard, OnRetireFromRC, OnOpponentRetire, OnLeaveGuardian,
OnPhaseStart, OnAttackDeclared, OnAttackHit, OnDamageTaken (объявлен,
но пока не вызывается — карт с ним нет).
4.3. Карты
- 59 скриптов в
CardScripts.cs,CardScriptsBT01.cs,CardScriptsTD.cs. - 6 карт Sentinel/Heal обрабатываются данными и движком без скрипта.
- Tejas реализован флагом
snipeBackRowв YAML. - 28 ванильных карт скрипта не требуют.
- Итого 66/66 карт с текстом закрыты.
4.4. Реплей
server/src/Vanguard.Rules/Replay/:
CommandCodec— команда в стабильную строку и обратно;MatchRecord— seed, колоды, команды, хэш событий;MatchRecorder— записывает только принятые команды;ReplayRunner— воспроизводит и проверяет хэш;EventHasher— FNV-1a по тексту событий.
Запись переживает JSON и воспроизводится бит-в-бит.
4.5. Диагностика
server/src/Vanguard.Rules/Diagnostics/GameInvariants.cs;- CLI-команда
stress [партий]— случайный бот, лимит 5000 шагов на партию.
4.6. Тесты
server/tests/Vanguard.Rules.Tests/GameEngineTests.cs — 117 тестов:
- механики фаз, боя, защиты, перехвата, триггеров;
- все ключевые карты и стоимости;
- 50 детерминированных партий случайного бота с инвариантами;
- JSON-реплей полной партии с проверкой хэша.
5. Структура и ключевые файлы
/server/src/Vanguard.Rules
/Engine/GameEngine.cs основной движок (~2500 строк)
/Engine/GameState.cs состояние, зоны, InTransit
/Engine/GameModels.cs CardInstance, Step, Phase, PendingChoice
/Engine/GameCommands.cs команды
/Engine/GameEvents.cs события
/Engine/Modifiers.cs StatModifier, GrantedAbility, CardRestriction
/Engine/Abilities/Abilities.cs AbilityDefinition, ActivatedAbility, триггеры
/Engine/Abilities/CardScripts.cs реестр Default + базовые карты
/Engine/Abilities/CardScriptsBT01.cs
/Engine/Abilities/CardScriptsTD.cs
/Cards/CardDefinition.cs статы, Sentinel, Restraint, snipeBackRow
/Decks/DeckValidator.cs правила колоды
/Replay/ запись и воспроизведение
/Diagnostics/GameInvariants.cs
/server/src/Vanguard.Content загрузка YAML и валидация
/server/src/Vanguard.Cli validate, stats, translations, stress
/server/tests/Vanguard.Rules.Tests 117 тестов
/content/sets карты
/content/translations/ru.yaml переводы
/docs/translation-rules.md канон перевода
/docs/HANDOFF.md этот файл
6. Принятые решения
Их не нужно пересматривать без причины.
- Формат называется Classic, не Standard.
- Имена карт английские;
nameRuзарезервировано. - Термины: Авангард, Арьергард, ранг, смена, поддержка, проверка, фазы Подъёма/Добора/Смены/Основная/Боевая/Завершающая, завершающий шаг, Сдерживание, «вы», буква ё.
- Способности ищутся по
nameId, а не по принту. - Лимит 4 копий — по
nameId, только правило декбилдера. - Дубль в коллекции — по
printingId; порог 4, замена внутри редкости. - Бустер: 5 карт = 4 C + 1 R+; веса R 70 / RR 22 / RRR 7 / SP 1.
- Gold за матч: 30/15/20 (победа/поражение/ничья); Gold = XP / 5.
- Таймер хода 90 с + банк 5 мин.
- Порядок триггеров выбирает игрок; опциональные способности спрашиваются.
- Непрерывные эффекты пересчитываются при каждом запросе.
- Поиск в колоде: 0 — уведомление и перемешивание, 1 — сразу, 2+ — выбор.
- Эффекты не вкладываются: цепочка строго друг за другом.
- Каждый блок — коммит и push в
master.
7. Что осталось
7.1. Ближайший блок — сервер
Порядок:
docs/protocol.md— спецификация:- кадры, handshake, версия, ping/pong;
intentсintentId,eventSeq;resyncпо запросу;- реконнект 0 / 2 / 10 / 30 с;
- отсутствие 5 минут → авто-поражение;
- таймер 90 с + банк 5 мин.
Vanguard.Shared:- DTO интентов и событий;
- MessagePack-резолвер;
- проекция состояния под клиента.
Vanguard.Server:- ASP.NET Core + WebSocket;
IGameTicketService(одноразовый тикет, TTL 60 с);IMatchGrain— 1 матч = 1 grain, последовательная обработка;- матчмейкинг: 2 очереди (Classic Ranked / Casual);
- скрытый MMR, расширяющееся окно;
- идемпотентность по
intentId.
- Проекция состояния:
- своя рука и свой триггер — полностью;
- открытые зоны — полностью;
- колода, рука противника, закрытый урон — только количество;
- seed и RNG не уходят.
- Персистентность:
- PostgreSQL — снапшот матча, восстановление grain;
- Redis — тикеты, очереди, кэш.
- Docker Compose +
/health.
Критерий готовности: два клиента играют полный матч по сети; kill клиента на любом шаге восстанавливается.
7.2. Мета-API
User, BCrypt, JWT (access 15 мин + refresh 30 дней, ротация).register,login,refresh,logout,me.- Коллекция по принтам, без верхнего предела.
- Колоды: CRUD,
validate, лимит 30, шаринг по коду. - Магазин, бустеры, триал-деки, токены.
- Пыль: разбор C 5 / R 10 / RR 25 / RRR 100, крафт ×4, SP не крафтится.
- Онбординг: триал-дека + 5 токенов.
- Матчмейкинг, результат матча, Gold/XP, история.
- Rate limiting.
7.3. Клиент
- Unity 6 LTS, URP, Addressables, Input System, Localization, DOTween.
- Сцены
Boot,Meta,Battle. - VContainer,
ApiClient,GameConnection. - Экраны: логин, меню, магазин, коллекция, декбилдер, очередь, настройки.
- Боевая сцена: поле, рука, зоны, анимации, таймер.
- Локализация RU/EN на лету.
7.4. Лаунчер
- WPF: обновления, запуск клиента, выбор сервера.
7.5. Мелкие технические долги
OnDamageTakenне вызывается — добавить, когда появится карта с таким триггером.- Глобальный лимит шагов внутри движка не enforced — только в стресс-тесте.
GameEngine.csбольшой; при росте разнести на partial-файлы.MatchRecordсейчас JSON; для сети позже MessagePack.- В
LegalCommands()не входят активируемые способности со стоимостью «сброс карты» — для UI их нужно будет перечислить с вариантами сброса.
8. Порядок действий в новой сессии
- Прочитать
docs/HANDOFF.md,IMPLEMENTATION_CHECKLIST.md,README.md. - Прогнать проверки из раздела 3.
- Начать с
docs/protocol.mdиVanguard.Shared. - После каждого блока: тесты,
validate,translations check, коммит, push. - Не ломать
Vanguard.Rules: сервер должен зависеть от него, а не наоборот.
9. Подводные камни
- Кодировка. Не использовать PowerShell
Get-Content/Set-Contentдля UTF-8 файлов с русским текстом: однажды это уже испортило комментарии. Правки — только черезedit/write, либо Python сencoding="utf-8". - PATH.
dotnetлежит в%LOCALAPPDATA%\dotnet; без добавления в PATH команды не находятся. - Solution.
server/Vanguard.slnx, не.sln. - Тесты.
StartedEngine()принудительно ставит Conroe стартовым Авангардом, чтобы Barcgal не срабатывал. - Порядок фаз. Вход в Основную —
EnterMainPhase()сOnPhaseStart. - Отложенные продолжения.
State.Continuation— что выполнить после паузы;State.PendingQueue+_resolvingDepthзапрещают вложенность эффектов. OfferAbility. ВозвращаетSkipped / Paused / Resolved; вызывающий код продолжает очередь только приSkipped. Ошибка здесь уже приводила к потере шага защиты.InTransit. Найденная карта, ждущая выбора круга, лежит вState.InTransit, иначе инвариант «50 карт» падает.- Задний ряд. Обычные карты атакуют только передний ряд; Tejas — задний
в своей колонке через
snipeBackRow. - Реестр карт. Новая карта без записи в
CardScripts.Defaultмолча останется без способностей; проверять покрытие скриптом. - Тестовые колоды.
BuildDeck()в тестах не содержит все карты; для конкретной карты использоватьMakeCard()и класть вручную.