Армия (п. 2.1): - ReturnFromMarch / ReturnUnits возвращают bool и зачисляют воинов только по известному походу и только один раз (раньше неизвестный поход добавлял выживших пехотой, ReturnUnits — без ограничения) - вернуться может не больше, чем ушло - TakeForMarch отклоняет повторный номер похода (раньше перезапись теряла воинов первого) - загрузка сохранения и перенос старых данных пропускают дубликаты походов Мир (п. 2.2): - TryStartMarch проверяет TakeForMarch; при отказе поход откатывается (WorldSimulation.CancelMarch) - если Армия не знает возвращающийся поход — ни воинов, ни добычи, предупреждение в консоли Тесты (п. 2.1, 2.2, 2.4): - неизвестный поход, повторное возвращение, повторный номер, откат похода - крайние случаи боя: 1×1, 1×10, 10×1, 0×0, пустая сторона, бонусы −100% / −500% / +100000%, бой числом Формула потерь не менялась. Найдено и записано в Battle.md как открытый вопрос: одиночный проигравший не гибнет (потери округляются вниз) — правило округления решает команда. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
72 lines
8.2 KiB
Markdown
72 lines
8.2 KiB
Markdown
# Игровое ядро
|
|
|
|
Общие данные, игровые правила взаимодействия и связь модулей. Ядро не содержит игровой логики — только «язык», на котором модули говорят друг с другом.
|
|
|
|
- **Сборки:**
|
|
- `Bogatyri.Core` — чистый C#, без Unity (его можно взять на сервер);
|
|
- `Bogatyri.Core.Unity` — тонкая прослойка к движку.
|
|
- **Папки:** `Assets/Scripts/Modules/Core`, `Assets/Scripts/Modules/Core.Unity`.
|
|
- **Зависимости:** нет. От ядра зависят все модули.
|
|
|
|
## Что внутри
|
|
|
|
| Файл | Что это |
|
|
| --- | --- |
|
|
| `Core/ResourceType.cs` | Перечисление ресурсов `ResourceType` и структура `ResourceAmount` (тип + количество). Числа enum не менять: они в сохранениях. |
|
|
| `Core/LocalPlayer.cs` | Id и имя локального игрока (пока без аккаунтов). |
|
|
| `Core/GameServices.cs` | Реестр модулей: `Register<T>`, `Get<T>`, `TryGet<T>`, `Has<T>`, `Unregister<T>`. |
|
|
| `Core/WorkJob.cs` | Профессии рабочих `WorkJob` и `WorkJobs` (какой ресурс добывает профессия, русское название). Числа enum не менять: они в сохранениях. |
|
|
| `Core/GameClock.cs` | Часы игры: `UnixNow` = реальное время + сдвиг. `Advance(секунд)` — перемотка для отладки, публикует `GameTimeAdvancedEvent`. Сдвиг не сохраняется. Модули берут время только отсюда. |
|
|
| `Core/EventBus.cs` | Шина событий: `Subscribe<T>`, `Unsubscribe<T>`, `Publish<T>`. Ошибка одного подписчика не мешает остальным (уходит в `OnHandlerError`). |
|
|
| `Core/Contracts/ModuleContracts.cs` | Контракты всех модулей и `SaveRegistry` — см. таблицу ниже. |
|
|
| `Core/Events/GameEvents.cs` | Все события модулей. |
|
|
| `Core.Unity/CoreUnityBootstrap.cs` | При старте игры очищает реестр, шину и список сохраняемых, сбрасывает перемотку `GameClock`, подключает ошибки шины к `Debug.LogException`. |
|
|
| `Core.Unity/UIBlocker.cs` | «Палец над интерфейсом?» — общая проверка для кликов по миру. |
|
|
|
|
## Контракты
|
|
|
|
| Контракт | Реализует | Что умеет |
|
|
| --- | --- | --- |
|
|
| `IEconomy` | Экономика (`ResourceManager`) | Узнать, добавить, потратить ресурс; проверить и списать цену целиком; лимит склада. |
|
|
| `IProduction` | Экономика (`ProductionService`) | Места для рабочих по профессиям, эффективность, добыча в час; `Produce` — добыть за время. |
|
|
| `ISettlement` | Поселение (`SettlementModule`) | Уровень Ратуши, число построек, открыт ли город. |
|
|
| `ILeveledBuilding` | Здания с уровнем (`ResourceCollector`) | Уровень здания — его сохраняет Поселение. |
|
|
| `IPopulation` | Население (`PopulationService`) | Жители, рабочие по профессиям, воины, предел жилья, расход еды и прирост в час, голод; `Tick` — досчитать до момента. |
|
|
| `IArmy` | Армия (`ArmyService`) | Войска по типам, в городе и в походах; обучение, потери; забрать в поход, вернуть выживших. |
|
|
| `IWorld` | Мир (`MarchManager`) | Сколько походов в пути; начать поход. |
|
|
| `IBattleSystem` | Бой (`BattleSystem`) | Посчитать исход боя по `BattleRequest`: состав сторон по типам, стены, бонусы. |
|
|
| `IChat` | Чат (`ChatService`) | История каналов, можно ли писать в канал, отправка сообщения от локального игрока. |
|
|
| `ICircle` | Круг (`CircleService`) | Круг игрока, список Кругов; основать, вступить, выйти. |
|
|
| `ISaveSystem` | Сохранения (`SaveManager`) | Есть ли сохранение; сохранить сейчас; стереть; сбросить всё (`ResetAll`). |
|
|
| `ISaveParticipant` | Любой модуль с данными | Секция сохранения: ключ, `Capture()`, `Restore(json)`, `ResetState()` — новая игра. |
|
|
|
|
## Порядок запуска
|
|
|
|
1. `SubsystemRegistration` — `CoreUnityBootstrap` очищает ядро.
|
|
2. `AfterAssembliesLoaded` — `App/GameModules` и `SettlementModule` регистрируют сервисы и подписки.
|
|
3. `BeforeSceneLoad` — создаётся `MarchManager` (Мир).
|
|
4. `Awake` объектов сцены — `ResourceManager`, `SaveManager` регистрируются сами.
|
|
5. `AfterSceneLoad` — перенос старых походов из `progress.json`.
|
|
6. `Start` — `GameBootstrap` загружает сохранение или, если файла нет, публикует `NewGameStartedEvent`.
|
|
7. Раз в 2 секунды — `App/PopulationTicker` досчитывает Население.
|
|
|
|
## Решения и план
|
|
|
|
- **Решение команды от 19.10.2026:** единый источник истины для населения, армии и ресурсов. Новые контракты для этапов 1, 2 и 5 — население, гарнизон, голод, лимиты хранения — добавляются сюда, когда начинается соответствующий этап.
|
|
|
|
## Журнал изменений
|
|
|
|
| Дата | Кто | Что |
|
|
| --- | --- | --- |
|
|
| 28.10.2026 | Claude | `IArmy.ReturnFromMarch` и `IArmy.ReturnUnits` возвращают `bool`: зачисление только по известному походу и один раз. `TakeForMarch` отклоняет повторный номер похода. |
|
|
| 27.10.2026 | Claude | `IArmy`: гарнизон (`GarrisonTotal`, `GetGarrison`, `AvailableForMarch`, `SetGarrison`); `TroopsChangedEvent.Garrison`. |
|
|
| 27.10.2026 | Claude | `MarchReturnedEvent.TargetEmpty`: войско пришло к уже разбитому лагерю. |
|
|
| 27.10.2026 | Claude | `TroopType` (типы войск), `BattleRequest` / `BattleOutcome` с составом по типам, силой сторон и бонусами; `IArmy.GetMarchUnits`, `IArmy.ReturnUnits`. |
|
|
| 27.10.2026 | Claude | `WorkJob`; контракт `IProduction`; `IEconomy.GetCapacity`; `IPopulation`: `Workforce`, `FreeWorkers`, `GetWorkers`, `SetWorkers`; событие `WorkersChangedEvent`. |
|
|
| 26.10.2026 | Claude | `GameClock`; контракт `IPopulation`; события `GameTimeAdvancedEvent`, `PopulationChangedEvent`, `StarvationChangedEvent`, `NewGameStartedEvent`. |
|
|
| 23.10.2026 | Claude | `IArmy` расширен (типы, `AddTroops`, `LoseFraction`, `TroopsInMarches`), событие `TroopsChangedEvent`. `GameLoadedEvent` публикуется и когда файла сохранения нет. |
|
|
| 19.10.2026 | Claude | Контракт `ICircle` и типы `CircleInfo`, `CircleMember`, `CircleRole`; события `CircleJoinedEvent`, `CircleLeftEvent`; `IChat.CanWrite`. |
|
|
| 19.10.2026 | Claude | Контракт `IChat`, типы `ChatChannel` и `ChatMessage`, событие `ChatMessageReceivedEvent`, `LocalPlayer`. |
|
|
| 19.10.2026 | Claude | Сброс сохранений: `ISaveSystem.ResetAll()`, `ISaveParticipant.ResetState()`, событие `GameResetEvent`. |
|
|
| 19.10.2026 | Claude | Создано ядро: реестр, шина событий, контракты шести модулей, события, `SaveRegistry`. `ResourceType` перенесён сюда из `ResourceManager.cs`, `UIBlocker` — из `Meta/Core`. |
|