From 422f55f22eaf28824ae21e2e167e858ba6f49790 Mon Sep 17 00:00:00 2001 From: Alexander Date: Thu, 5 Nov 2026 17:45:12 +0100 Subject: [PATCH] =?UTF-8?q?=D0=A1=D1=82=D1=80=D0=BE=D0=B9=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=BD=D0=B5=20=D0=B2=D0=B8=D1=81=D0=B8=D1=82=20=D0=BD=D0=B0=20?= =?UTF-8?q?00:00=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=20=C2=AB=D0=A1=D0=B1?= =?UTF-8?q?=D1=80=D0=BE=D1=81=D0=B8=D1=82=D1=8C=20=D0=BF=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D0=BC=D0=BE=D1=82=D0=BA=D1=83=C2=BB:=20=D1=80=D0=B0=D1=81?= =?UTF-8?q?=D1=87=D1=91=D1=82=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B0=D0=B5?= =?UTF-8?q?=D1=82=20=D1=82=D0=B5=D0=BA=D1=83=D1=89=D0=B5=D0=B5=20=D0=B2?= =?UTF-8?q?=D1=80=D0=B5=D0=BC=D1=8F=20=D0=B8=20=D0=BF=D1=80=D0=B8=20=D1=87?= =?UTF-8?q?=D0=B0=D1=81=D0=B0=D1=85=20=D0=BD=D0=B0=D0=B7=D0=B0=D0=B4=20(?= =?UTF-8?q?=D0=B1=D0=B5=D0=B7=20=D0=BD=D0=B0=D1=87=D0=B8=D1=81=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- .../Modules/Population/PopulationService.cs | 4 ++++ .../Scripts/Modules/Tests/ProductionTests.cs | 21 +++++++++++++++++++ Docs/Modules/Population.md | 1 + 3 files changed, 26 insertions(+) diff --git a/Assets/Scripts/Modules/Population/PopulationService.cs b/Assets/Scripts/Modules/Population/PopulationService.cs index 11e48d6..6282d68 100644 --- a/Assets/Scripts/Modules/Population/PopulationService.cs +++ b/Assets/Scripts/Modules/Population/PopulationService.cs @@ -243,6 +243,10 @@ public sealed class PopulationService : IPopulation, ISaveParticipant { // Часы ушли назад (сброс отладочной перемотки, перевод часов на телефоне). Метку НЕ двигаем назад: // это время уже посчитано, и когда часы снова дойдут до него, оно не начислится второй раз (04.11). + // Но сообщить «расчёт дошёл до сейчас» нужно: время до сейчас тоже уже посчитано, и стройки, у которых оно + // вышло, завершаются. Иначе после «Сбросить перемотку» все стройки висели на 00:00, пока реальное время + // не догонит перемотку (05.11). Ресурсы здесь не начисляются + SimulatedUntil(unixNow); return; } if (elapsed == 0) { SimulatedUntil(unixNow); return; } diff --git a/Assets/Scripts/Modules/Tests/ProductionTests.cs b/Assets/Scripts/Modules/Tests/ProductionTests.cs index 847641a..3afd0ca 100644 --- a/Assets/Scripts/Modules/Tests/ProductionTests.cs +++ b/Assets/Scripts/Modules/Tests/ProductionTests.cs @@ -292,6 +292,27 @@ public class ProductionTests Assert.AreEqual(130 / 60f * 60 + 110 / 60f * 66, wood, 0.01f, "с ближайшего шага расчёта после конца стройки"); } + [Test] + public void Tick_ClockWentBack_StillReportsSimulatedTime_NoResources() + { + // «+1 час», потом «Сбросить перемотку»: часы ушли назад. Стройка, у которой время вышло, должна завершиться + // (событие о расчёте приходит), а ресурсы за уже посчитанный час второй раз не начисляются (05.11) + economy.Set(ResourceType.Food, 100000); + economy.Set(ResourceType.Wood, 0); + production.SetBuildings(Buildings((WorkJob.Woodcutter, 1))); + population.SetWorkers(WorkJob.Woodcutter, 30); + population.Tick(T0); + population.Tick(T0 + Hour); + float wood = economy.Get(ResourceType.Wood); + + long reported = 0; + EventBus.Subscribe(e => reported = e.UnixNow); + population.Tick(T0 + 60); + + Assert.AreEqual(T0 + 60, reported, "расчёт сообщает, до какого момента дошло время -- стройки завершаются"); + Assert.AreEqual(wood, economy.Get(ResourceType.Wood), 0.01f, "за уже посчитанное время ресурсов не прибавилось"); + } + [Test] public void Tick_SameMomentTwice_NoExtraResources() { diff --git a/Docs/Modules/Population.md b/Docs/Modules/Population.md index 757e4f6..7e50760 100644 --- a/Docs/Modules/Population.md +++ b/Docs/Modules/Population.md @@ -112,6 +112,7 @@ | Дата | Кто | Что | | --- | --- | --- | +| 05.11.2026 | Claude (Саша) | Часы назад (после «+1 час» и «Сбросить перемотку»): `Tick` всё равно публикует `GameTimeSimulatedEvent` на текущий момент — стройки, у которых время вышло, завершаются (раньше висели на «Стройка 00:00», пока реальное время не догонит перемотку). Ресурсы за уже посчитанное время по-прежнему не начисляются. Тест `Tick_ClockWentBack_StillReportsSimulatedTime_NoResources`. | | 04.11.2026 | Claude (Валдемар) | Решения 04.11 (офлайн по временным меткам): событие `GameTimeSimulatedEvent` на каждом шаге расчёта и в конце `Tick` — стройка, закончившаяся офлайн, вступает в силу в свой момент, добыча с момента завершения. Часы назад: метка последнего расчёта не уходит назад — закрыто повторное начисление. Тесты в `ProductionTests` (офлайн-стройка, повторный Tick, загрузка), обновлён тест про часы назад. Побочный эффект: после «DEV +10 часов» и перезапуска расчёт стоит, пока реальное время не догонит перемотку. | | 04.11.2026 | Claude (Саша) | Пропавшие без вести (решения 01.11, п. 5) занимают места в населении (`Soldiers` включает `IArmy.MissingTotal`), но не едят. | | 04.11.2026 | Claude (Саша) | Решения по отчёту Саши от 01.11, п. 4: воины едят по норме типа — пехота 0,15, лучники 0,20, кавалерия 0,15, осадные 0,15 в час (`PopulationRules.FoodPerTroopTypePerHour`, `EconomyConfig.population.foodPerTroopTypePerHour`); раненые — полную норму своего типа, даже ожидая койку (`IArmy.GetAllTroops`). Новобранцы — по `foodPerSoldierPerHour`. Без таблицы — как раньше (тесты Населения не менялись). Час — тот же, что у остальной еды (переход еды на игровые часы — открытый вопрос). |