AI/Needs/NeedSystem.cs
using System;
using System.Text.Json.Nodes;
namespace HC3;
public class NeedSystem : Component
{
/// <summary>
/// How happy this agent is, affected by leaving needs unfulfilled.
/// </summary>
[Sync( SyncFlags.FromHost )]
[Property, ReadOnly]
public float Happiness
{
get => _happiness;
set
{
_happiness = value.Clamp( 0, 1f );
}
}
private float _happiness;
private Need[] _cachedNeeds;
public IEnumerable<Need> GetNeeds()
{
if ( _cachedNeeds == null || _cachedNeeds.Length == 0 )
_cachedNeeds = GetComponents<Need>().ToArray();
return _cachedNeeds;
}
public Need GetNeed( string name )
{
var needs = GetNeeds();
foreach ( var n in needs )
{
if ( n.Template.ResourceName.Equals( name, StringComparison.OrdinalIgnoreCase ) )
return n;
}
return null;
}
public Need GetNeed( NeedDefinition need )
{
var needs = GetNeeds();
foreach ( var n in needs )
{
if ( n.Template == need ) return n;
}
return null;
}
[Property]
public List<NeedDefinition> Needs { get; set; }
protected override void OnAwake()
{
if ( !Networking.IsHost )
return;
foreach ( var template in Needs )
{
var need = GameObject.AddComponent<Need>();
need.Init( template );
}
Happiness = Random.Shared.Float( 0.75f, 0.95f );
}
public void Tick()
{
if ( !Networking.IsHost )
return;
foreach ( var need in GetNeeds() )
{
need.Level += Time.Delta * (need.Template.BaseRate / 60.0f);
if ( need.Level > 0.95f ) // failing!
{
Happiness -= Time.Delta * 0.01f;
}
}
}
public JsonNode ToJson()
{
var needs = GetNeeds();
var array = new JsonArray();
foreach ( var need in needs )
{
var obj = new JsonObject
{
{ need.Template.ResourceName, need.Level }
};
array.Add( obj );
}
return array;
}
public void LoadFromJson( JsonNode json )
{
if ( json is not JsonArray array )
return;
var needs = new Dictionary<string, Need>( StringComparer.OrdinalIgnoreCase );
// Lookup table to speed this up
foreach ( var need in GetNeeds() )
{
needs[need.Template.ResourceName] = need;
}
for ( int i = 0; i < array.Count; i++ )
{
if ( array[i] is not JsonObject obj )
continue;
foreach ( var kvp in obj )
{
if ( !needs.TryGetValue( kvp.Key, out var need ) )
continue;
if ( kvp.Value is JsonValue value && value.TryGetValue( out float level ) )
{
need.Level = level;
}
}
}
}
}