Files
2026-05-21 16:04:49 +02:00

126 lines
4.4 KiB
C#

using System;
using Cysharp.Threading.Tasks;
using Unity.Mathematics;
using UnityEngine;
namespace DanieleMarotta.RiversongCodeShowcase
{
public class PopulationNeedsSystem : GameSystem, IInitializable, IDisposable, IUpdatable
{
private const float MaxHappinessScoreChangeRate = 0.1f;
[InjectService]
private ISignalBus _signalBus;
[InjectService]
private IEntityCache _entityCache;
[InjectService]
private World _world;
[InjectService]
private GameConfig _config;
public PopulationNeedsSystem(IServiceLocator serviceLocator) : base(serviceLocator)
{
}
public UniTask InitializeAsync()
{
_signalBus.Subscribe<EndOfWeekSignal>(OnEndOfWeek);
return UniTask.CompletedTask;
}
public void Dispose()
{
_signalBus.Unsubscribe<EndOfWeekSignal>(OnEndOfWeek);
}
public void Update()
{
if (_world.TimeState.DayNightCycleStep != DayNightCycleStep.Day) return;
foreach (var house in _entityCache.GetHouses())
{
ref var needsState = ref house.GetNeedsStateRW();
ref var storage = ref house.GetStorageRW();
var targetHappiness = 1f;
var happinessScore = 0;
var maxHappinessScore = 0;
needsState.AllNeedsMet = true;
for (var i = 0; i < needsState.Needs.Length; i++)
{
var need = needsState.Needs[i];
if (need.TierIndex > house.TierIndex) break;
if (need.Type != PopulationNeedType.Product) throw new NotImplementedException();
if (need.Current < need.YieldOnFetch)
{
var productCount = storage.AvailableNow(need.ProductHandle);
if (productCount > 0)
{
storage.Take(need.ProductHandle, productCount);
need.Current += (ushort)math.min(productCount * need.YieldOnFetch, ushort.MaxValue);
}
}
var needMet = need.Current > 0;
if (needMet) happinessScore += need.HappinessScore;
maxHappinessScore += need.HappinessScore;
needsState.AllNeedsMet &= needMet;
needsState.Needs[i] = need;
}
if (maxHappinessScore > 0)
{
needsState.MaxHappinessScore += MaxHappinessScoreChangeRate * Time.deltaTime;
needsState.MaxHappinessScore = math.min(needsState.MaxHappinessScore, maxHappinessScore);
targetHappiness = needsState.MaxHappinessScore > 0 ? math.saturate(happinessScore / needsState.MaxHappinessScore) : 1;
}
else
{
needsState.MaxHappinessScore = 0;
}
needsState.Happiness = Mathf.MoveTowards(needsState.Happiness, targetHappiness, _config.Population.OverallHappinessChangeRate * Time.deltaTime);
needsState.Happiness = math.saturate(needsState.Happiness);
needsState.OverallHappinessWeight = math.saturate((float)(_world.TimeState.TotalWeeks - house.WeekCreated) / _config.Population.HouseWeightRampUpWeekCount);
}
}
private void OnEndOfWeek(EndOfWeekSignal signal)
{
foreach (var house in _entityCache.GetHouses())
{
ref var needsState = ref house.GetNeedsStateRW();
if (needsState.AllNeedsMet)
needsState.NeedsMetForWeeks++;
else
needsState.NeedsMetForWeeks = 0;
for (var i = 0; i < needsState.Needs.Length; i++)
{
var need = needsState.Needs[i];
if (need.TierIndex > house.TierIndex) break;
if (need.Type != PopulationNeedType.Product) continue;
if (need.Current >= need.ConsumptionRate)
need.Current -= need.ConsumptionRate;
else
need.Current = 0;
needsState.Needs[i] = need;
}
}
}
}
}