Skip to main content

xgaida-x-nixi-combat-sim

Боевая симуляция Guildmaster: детерминированное ядро на 30 Гц, тик-ордер, система эффектов (producer→consumer, теги, стакинг), авто-атаки и способности, displacement и separation, боевой AI, RuntimeUnit, а также контракт развязки sim→presentation. Зови на любую правку боевой логики и всего под Assets/_Project/Scripts/Combat — даже если слово «симуляция» не звучит. НЕ применять к: определениям контента и баланс-числам в SO (data-authoring), визуальному фидбэку и slowmo (gamefeel-vfx), звуку (audio), тех-доке (tech-scribe).

Zur Installation springen

Quellinformationen

Repository
Kaliguri/Guildmaster-Autobattler
Letzte Quellaktivität
3. August 2026 um 02:39
Erkannte Sprache von SKILL.md
Russisch
Sterne
0
Forks
0

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
4 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
xgaida-x-nixi-combat-sim
description
Боевая симуляция Guildmaster: детерминированное ядро на 30 Гц, тик-ордер, система эффектов (producer→consumer, теги, стакинг), авто-атаки и способности, displacement и separation, боевой AI, RuntimeUnit, а также контракт развязки sim→presentation. Зови на любую правку боевой логики и всего под Assets/_Project/Scripts/Combat — даже если слово «симуляция» не звучит. НЕ применять к: определениям контента и баланс-числам в SO (data-authoring), визуальному фидбэку и slowmo (gamefeel-vfx), звуку (audio), тех-доке (tech-scribe).
# Combat Sim — рабочий контур Guildmaster Этот скилл — процедура, а не справка. Он превращает разрозненные инварианты боя в чеклист, который прогоняется на КАЖДОЙ боевой задаче. Цель — чтобы симуляция оставалась детерминированной, headless-тестируемой и развязанной от презентации, а новый боевой контент ложился в готовые контракты, а не рядом с ними. ## Прежде всего: карта боя Ядро уже построено и покрыто ~29 EditMode-тестами. Ничего не изобретай — читай, продолжай, встраивайся в существующие швы. | Что | Где | |---|---| | Сердце симуляции (`Tick`, порядок систем, `ComputeChecksum`) | `Assets/_Project/Scripts/Combat/CombatSimulation.cs` | | Константы шага (`TickRate=30`, `TickDelta=1/30`, `AiTickRate=10`) | `Assets/_Project/Scripts/Core/Simulation/SimConstants.cs` | | Реалтайм-драйвер (accumulator, ЕДИНСТВЕННЫЙ `Time.deltaTime`) | `Assets/_Project/Scripts/Game/Services/CombatLoopService.cs` | | Шов мутации мира | `Assets/_Project/Scripts/Combat/ICombatContext.cs` | | Юнит sim-модель (POCO) | `Assets/_Project/Scripts/Combat/Units/RuntimeUnit.cs` | | Фабрика/загрузка юнитов | `Assets/_Project/Scripts/Combat/Units/RuntimeUnitFactory.cs`, `EncounterLoader.cs` | | Статы | `Assets/_Project/Scripts/Combat/Stats/Stats.cs` | | Система эффектов | `Assets/_Project/Scripts/Combat/Effects/EffectSystem.cs` | | Экземпляр эффекта (состояние) | `Assets/_Project/Scripts/Combat/Effects/RuntimeEffect.cs` | | Контракты компонентов эффектов | `Assets/_Project/Scripts/Combat/Effects/IRuntimeEffectComponent.cs` | | Компоненты-поведения (~20) | `Assets/_Project/Scripts/Combat/Effects/Components/*.cs` | | Внутренняя шина событий (producer→consumer) | `Assets/_Project/Scripts/Combat/Effects/CombatEvent.cs` | | Displacement / Separation / Movement | `Assets/_Project/Scripts/Combat/Systems/*.cs` | | Способности / авто-атаки | `Assets/_Project/Scripts/Combat/Abilities/*.cs`, `Systems/AutoAttackSystem.cs`, `Systems/AttackTiming.cs` | | Исход боя / стороны (teamId) | `Assets/_Project/Scripts/Combat/BattleOutcome.cs` | | Мост sim→presentation | `Assets/_Project/Scripts/Presentation/CombatPresenter.cs` | | MessagePipe-события боя | `Assets/_Project/Scripts/Presentation/Events/CombatEvents.cs` | | Единственный писатель `Time.timeScale` (GameSpeed/пауза/Cinematic, шов хрономанта) | `Assets/_Project/Scripts/Game/Services/TimeScaleService.cs` | | Режиссёр значимости (global-feel) — **не combat-sim**, потребитель времени | `CombatFeelDirector.cs` → скилл `gamefeel-vfx` | | Combat-тесты (~29, slice-паттерн) | `Assets/_Project/Tests/EditMode/Combat/*.cs` | **Слои (asmdef) — зависимость строго вниз:** `Core ← Data ← Combat`; `Presentation` ссылается на `Combat` и читает его; `Game` сшивает всё через DI (VContainer) и MessagePipe. `Guildmaster.Combat` НЕ тянет Presentation, MessagePipe, VContainer, FMOD, движковые presentation-либы. Это и есть headless-ядро. ## Четыре правила, нарушение которых = переделка (HARD) Каждое закрывает конкретный способ, которым бой незаметно загнивает. Пойми «почему» — тогда не придётся заучивать «нельзя». 1. **Бой headless: `Guildmaster.Combat` не зависит от презентации и движка.** Combat-код видит только `Core` и `Data`. Никаких `MonoBehaviour`, `GameObject`, `Time.*`, VContainer, MessagePipe, FMOD внутри `Combat`. Единственный `Time.deltaTime` во всём бою — в `CombatLoopService` (реалтайм-драйвер в слое `Game`). *Почему:* как только sim дёргает движок, он перестаёт быть тестируемым без сцены и воспроизводимым — а на этом стоят и ~29 EditMode-тестов, и кооп-детерминизм. *Граница:* презентация СМОТРИТ на sim (подписка, чтение) — это нормально; sim на презентацию не смотрит НИКОГДА. 2. **Детерминизм тика.** Внутри `Combat` запрещены источники недетерминизма: `UnityEngine.Random`, `System.Random`-своя, `Time.*`, `DateTime.Now`, недетерминированный порядок (нестабильная сортировка, обход `HashSet`/`Dictionary` как источник порядка). RNG — только `ICombatContext.Rng`; шаг времени — только `SimConstants.TickDelta`; порядок систем в `Tick` — фиксирован и менять его нельзя без явного решения. *Почему:* два клиента (host-authoritative кооп) обязаны прогнать одинаковый тик одинаково; `ComputeChecksum()` ловит рассинхрон, но только если источник детерминирован. *Инструмент:* правишь sim-систему — прогони checksum/replay-проверку (рекомендуется, см. `references/simulation-and-determinism.md`). 3. **Мир мутируется только через шов.** Состояние боя меняется ТОЛЬКО внутри `CombatSimulation.Tick` (в фиксированном порядке систем) и через `ICombatContext` (`DealDamage`/`Heal`/`ApplyEffect`/`Dispel`/`Displace`/`SpawnProjectile`/…). Никто снаружи не пишет в `RuntimeUnit` напрямую; способности и эффекты трогают мир только через контекст. *Почему:* единая точка мутации = единый порядок, единые события, единый checksum. Прямая запись в обход контекста — это молчаливый источник рассинхрона и багов «эффект сработал, а событие не поднялось». 4. **Эффект = stateless-компонент, состояние — в `RuntimeEffect`.** Новый эффект — это класс по одному из контрактов `IRuntimeEffectComponent` (OnApply/OnExpire, `IPeriodicComponent`, `IReactiveComponent`, `IPreDamageComponent`, `IStackableComponent`, `IScalablePotency`), БЕЗ полей-состояния (компонент шарится между носителями). Всё изменяемое живёт в `RuntimeEffect` (`RemainingTicks`, `Stacks`, `ScaledPotency[]`, …). Обязательны теги (`EffectTag`) и правило стака (`StackRule`). *Почему:* stateless-компонент безопасно переиспользуется на сотнях юнитов; поле в компоненте — это общий mutable-стейт и мгновенный кросс-юнит-баг. **Плюс два сквозных инварианта (тоже HARD):** - **Реактив, требующий ДЕЙСТВИЯ носителя, гейтится дееспособностью — и читает СНИМОК на начало тика.** Маркер `IRequiresAgencyComponent` на компоненте, одна проверка в диспатче (`RunPreDamage` + реактивная очередь) по `RuntimeUnit.CanActAtTickStart`. Помечены «Оплот» и «Изворотливость»; НЕ помечены шипы, вампиризм, горение — это свойства, а не действия, и под станом они обязаны работать. *Почему снимок:* `RecomputeControl` зовётся синхронно при наложении эффекта, то есть живой `CanAct` меняется ПОСРЕДИ тика, а урон проходит раньше фазы эффектов. Живой флаг сделал реакцию зависимой от места юнита в обходе, и зеркальные команды разошлись (`MirrorMatchTests`, тик 300). *Почему маркер, а не список эффектов:* дееспособность уже имеет владельца (`CanAct`), список стал бы вторым и разошёлся бы на первом новом контроле. *Ловушка:* не помечать то, чья недееспособность вызвана СОБСТВЕННОЙ механикой. Комбо монаха сделано смещением, смещение снимает дееспособность у летящего — гейт отменял фазы своей же способности. - **Состояние, которое читают решения внутри тика, обязано быть снимком.** Это тот же закон, что двухфазность движения и `PreviousPosition`: список эффектов и флаги контроля меняются немедленно, поэтому любое «посмотреть, что сейчас на юните» посреди тика зависит от порядка обхода. Признак дефекта — зеркальные тесты падают на конкретном тике, а не «иногда». - **Стороны — только `teamId` (int).** Никакой «команды игрока» в бою. Исход — «победила команда N» (`BattleOutcome`), сторон может быть >2 (шов под PvP). Принадлежность игрока живёт выше боя (`ILocalPlayer.Team`, `_localViewerTeam` в презентере). - **Значения — из данных/конфигов, не хардкод.** Тюнеры боя — `SimTuning` (dev `gm_*`), статы — через `StatsConfig`/`Override`, feel — `CombatFeelConfig`. Магические числа в sim-коде = двойная работа при балансе. (Как в UI: не хардкодить, чтобы не переделывать.) ## Граница с data-authoring (эффект живёт на два дома) Эффект — стык двух скиллов, режем чётко: - **combat-sim владеет ПОВЕДЕНИЕМ:** компонент-логика (`IRuntimeEffectComponent`), тик, стакинг-механика, реактивы, порядок применения, `CreateRuntime` для системных эффектов в коде. - **data-authoring владеет ОПРЕДЕЛЕНИЕМ:** `EffectData` SO, `id` (`domain.name`), баланс-цифры, `[SerializeReference]`-состав компонентов, loc-ключи. Задача «новый эффект» обычно трогает оба: логику пишу здесь, определение/баланс — по контуру data-authoring. На стыке — взаимная ссылка «см. другой скилл», а не спор за задачу. ## Развязка sim → presentation (шов, не визуал) Скилл держит КОНТРАКТ развязки, но не визуальный полиш (его правит Макс): - **sim поднимает C#-события** (`OnDamageDealt`, `OnUnitDied`, …); **`CombatPresenter`** — единственный, кто на них подписан со стороны презентации, спавнит views и **ретранслирует в MessagePipe** (`CombatEvents.cs`). Audio/UI/feel слушают MessagePipe, не sim. - **Джус и фидбэк — контур `gamefeel-vfx`, не combat-sim.** Global-feel (kill-slowmo, shake, финишер) в `CombatFeelDirector`, per-hit фидбэк в презентере — их держит скилл `gamefeel-vfx`. combat-sim владеет только боевым ВРЕМЕНЕМ (`TimeScaleService`), которое джус потребляет. - **`Time.timeScale` пишет только `TimeScaleService`.** Он же не трогает sim-время (`ElapsedSeconds = currentTick * TickDelta`): slowmo/пауза меняют реальное время на тик, но не детерминизм. Детали контракта и антипаттерны — `references/presentation-seam.md`. ## Как я авторю боевой код — ГИБРИД (файл + проверка через MCP) 1. **Пишу файлы напрямую** (`Write`/`Edit`) — контролирую код и его слой. 2. **После C#-правок — `read_console`** (Unity MCP): дождаться компиляции, ноль ошибок, только потом использовать новые типы. 3. **Перед «готово» — `run_tests`** по Combat-подмножеству (EditMode/Combat) — быстро; полный прогон отдаём CI. 4. **Проверяю слой:** новый код в `Combat` не тянет запрещённые зависимости (правило 1). ## Чеклист сдачи боевой задачи Прогнать перед тем, как сказать «готово»: - [ ] Новый код в `Combat` не зависит от Presentation/движка (headless цел) - [ ] Ноль источников недетерминизма; RNG через `ICombatContext.Rng`, dt через `TickDelta` - [ ] Мутация мира только через `Tick`/`ICombatContext`, не прямой записью в `RuntimeUnit` - [ ] Новый эффект — stateless-компонент; состояние в `RuntimeEffect`; теги + `StackRule` заданы - [ ] Стороны — `teamId`; никакой «команды игрока»; значения — из конфигов, не хардкод - [ ] Развязка цела: sim не смотрит на presentation; `timeScale`/global-feel — в своих местах - [ ] На каждый новый эффект/способность/систему — свой EditMode-тест (тесты под игру, не наоборот) - [ ] `read_console` чист (компиляция); `run_tests` по Combat зелёный - [ ] Правил sim-систему → прогнал checksum/replay-проверку ## Справочные файлы (читать по надобности) - `references/simulation-and-determinism.md` — тик, фиксированный порядок систем, `ICombatContext`, `SimConstants`, `CombatLoopService`, детерминизм, checksum/replay. Читать перед правкой любой sim-системы. - `references/effects-and-events.md` — контракт эффектов, компоненты, `RuntimeEffect`, теги/стакинг, шина `CombatEvent`, реактивы, displacement-как-эффект. Читать перед созданием эффекта. - `references/presentation-seam.md` — развязка sim→presentation, MessagePipe-события, `CombatPresenter`, `TimeScaleService` (боевое время), граница с джусом/фидбэком (`gamefeel-vfx`).
Auf GitHub ansehen