Park/Progression/Stats/Stats.cs
using HC3.Persistence;
namespace HC3;
/// <summary>
/// A collection of events for stats.
/// </summary>
public interface IStatEvents : ISceneEvent<IStatEvents>
{
/// <summary>
/// Called when a stat changes
/// </summary>
/// <param name="identifier"></param>
/// <param name="value"></param>
public void OnStatChanged( string identifier, float value );
/// <summary>
/// Called when stats are loaded from a save game
/// </summary>
public void OnStatsLoaded() { }
}
/// <summary>
/// This is a stats wrapper that allows us to store stats local to a save game. It's a GameObjectSystem so it always exists.
/// </summary>
public partial class Stats : GameObjectSystem<Stats>, ISaveDataProperty<Stats.SaveData>
{
[ConVar( "hc3.debug.stats" )]
public static bool Debug { get; set; } = false;
public Stats( Scene scene ) : base( scene ) { }
// ISaveDataProperty
public sealed record SaveData( Dictionary<string, float> Store );
string ISaveDataProperty.PropertyName => "Stats";
int ISaveDataProperty.PropertyOrder => 1_000;
/// <summary>
/// A list of stats that we'll store.
/// </summary>
[Sync( SyncFlags.FromHost )]
public NetDictionary<string, float> Values { get; private set; } = new();
SaveData ISaveDataProperty<SaveData>.WriteValue( Scene scene )
{
return new( Values.ToDictionary() );
}
void ISaveDataProperty<SaveData>.ReadValue( Scene scene, SaveData value )
{
Values = [.. value.Store];
IStatEvents.Post( x => x.OnStatsLoaded() );
}
/// <summary>
/// Get a stat
/// </summary>
/// <param name="identifier"></param>
/// <param name="defaultValue"></param>
/// <returns></returns>
public static float Get( string identifier, float defaultValue = 0f )
{
if ( !Current.Values.TryGetValue( identifier, out var value ) )
{
value = defaultValue;
Current.Values[identifier] = value;
}
return value;
}
/// <summary>
/// Set a stat
/// </summary>
/// <param name="identifier"></param>
/// <param name="value"></param>
public static void Set( string identifier, float value )
{
if ( !Networking.IsHost ) return;
if ( Current.Values.ContainsKey( identifier ) )
{
Current.Values[identifier] = value;
}
else
{
Current.Values.Add( identifier, value );
}
Sandbox.Services.Stats.SetValue( identifier, value );
IStatEvents.Post( x => x.OnStatChanged( identifier, value ) );
}
/// <summary>
/// Increment a stat
/// </summary>
/// <param name="identifier"></param>
/// <param name="value"></param>
public static void Increment( string identifier, float value = 1f )
{
if ( !Networking.IsHost ) return;
if ( Debug ) Log.Info( $"Incrementing {identifier} by {value}" );
if ( Current.Values.ContainsKey( identifier ) )
{
Current.Values[identifier] += value;
}
else
{
Current.Values.Add( identifier, value );
}
Sandbox.Services.Stats.Increment( identifier, value );
IStatEvents.Post( x => x.OnStatChanged( identifier, value ) );
}
/// <summary>
/// Clear a stat
/// </summary>
/// <param name="identifier"></param>
public static void Clear( string identifier )
{
if ( !Networking.IsHost ) return;
if ( Current.Values.ContainsKey( identifier ) )
{
Current.Values.Remove( identifier );
}
else
{
Log.Warning( $"Tried to clear stat {identifier} but it doesn't exist." );
}
IStatEvents.Post( x => x.OnStatChanged( identifier, 0 ) );
}
[ConCmd( "hc3.debug.clearstats", ConVarFlags.Cheat )]
public static void Clear()
{
if ( !Networking.IsHost ) return;
// So all events are fired
foreach ( var kv in Current.Values )
{
Clear( kv.Key );
}
}
}