using Cysharp.Threading.Tasks; using Unity.Mathematics; using UnityEngine; namespace DanieleMarotta.RiversongCodeShowcase { [UpdateAfter(typeof(PopulationNeedsSystem))] public class PopulationUpdateSystem : GameSystem, IInitializable, IUpdatable { [InjectService] private ISignalBus _signalBus; [InjectService] private World _world; [InjectService] private IEntityCache _entityCache; [InjectService] private GameConfig _config; public PopulationUpdateSystem(IServiceLocator serviceLocator) : base(serviceLocator) { } public UniTask InitializeAsync() { _world.PopulationState.Happiness = _config.Population.InitialeOverallHappiness; return UniTask.CompletedTask; } public void Update() { if (_world.TimeState.DayNightCycleStep != DayNightCycleStep.Day) return; UpdateOverallHappiness(); UpdatePopulation(); } private void UpdateOverallHappiness() { var targetHappiness = 0f; var totalWeight = 0f; foreach (var house in _entityCache.GetHouses()) { ref var needsState = ref house.GetNeedsStateRW(); targetHappiness += needsState.OverallHappinessWeight * needsState.Happiness; totalWeight += needsState.OverallHappinessWeight; } if (totalWeight > 0) targetHappiness = math.saturate(targetHappiness / totalWeight); var grace = _world.TimeState.TotalWeeks < _config.Population.GraceWeekCount; if (grace) targetHappiness = math.max(targetHappiness, _config.Population.GraceMinHappiness); var populationState = _world.PopulationState; var delta = math.abs(targetHappiness - populationState.Happiness); const float halfOnePercent = 0.005f; populationState.Sentiment = delta > halfOnePercent ? math.sign(targetHappiness - populationState.Happiness) : 0; populationState.Happiness = Mathf.MoveTowards(populationState.Happiness, targetHappiness, _config.Population.OverallHappinessChangeRate * Time.deltaTime); populationState.Happiness = math.saturate(populationState.Happiness); } private void UpdatePopulation() { var populationState = _world.PopulationState; populationState.PopulationCapacity = 0; foreach (var house in _entityCache.GetHouses()) populationState.PopulationCapacity += house.PopulationCapacity; var growthRate = _config.Population.GrowthRatePeakValue * _config.Population.GrowthRateCurve.Evaluate(populationState.Happiness); if (populationState.Sentiment > 0) growthRate = math.max(growthRate, 0); populationState.GrowthAccumulator += growthRate * Time.deltaTime; if (math.abs(populationState.GrowthAccumulator) < 1) return; var delta = (int)math.sign(populationState.GrowthAccumulator); populationState.GrowthAccumulator -= delta; var updatedPopulation = math.clamp(populationState.Population + delta, 0, populationState.PopulationCapacity); if (updatedPopulation == populationState.Population) return; populationState.Population = updatedPopulation; _signalBus.Raise(new PopulationChangedSignal(updatedPopulation)); } } }