Spending/Upgrades/ValueAggregator.cs
using System;
using System.Numerics;

namespace PlanetMeat;

public class ValueAggregator<T> where T : IComparable<T>, IAdditionOperators<T, T, T>, ISubtractionOperators<T, T, T>, IMinMaxValue<T>
{
	private readonly Dictionary<string, T> sources = [];
	private readonly T baseValue;
	public T Total { get; private set; }

	public ValueAggregator( T startingValue = default )
	{
		Total = baseValue = startingValue;
	}

	public static ValueAggregator<T> FromImprovement( string ident, T fallback = default )
	{
		return new( ident is null ? fallback : Research.Current.GetImprovementEffect( ident, fallback ) );
	}

	private static string GetSourceIdent( Component comp ) => "comp_" + comp.Id;

	private void BakeAggregate()
	{
		var agg = baseValue;
		foreach ( var value in sources.Values )
			agg = agg.AddCapped( value );
		Total = agg;
	}

	public void SetContribution( string source, T amount )
	{
		sources[source] = amount;
		BakeAggregate();
	}
	public void SetContribution( Component comp, T amount ) => SetContribution( GetSourceIdent( comp ), amount );

	public void RemoveContribution( string source )
	{
		if ( sources.Remove( source ) )
			BakeAggregate();
	}
	public void RemoveContribution( Component comp ) => RemoveContribution( GetSourceIdent( comp ) );

	public T Without( string source ) => Total - sources.GetValueOrDefault( source );
	public T Without( Component comp ) => Without( GetSourceIdent( comp ) );
}