AI/Staff/Staff.Persistence.cs
using HC3.Persistence;
using System;
using System.Collections.Immutable;
using System.Text.Json.Nodes;

namespace HC3;

public partial class Staff
{
	public sealed record SaveData( string FullName, bool IsWorking, string ResourcePath, Vector3 Position, float Rotation, JsonObject Metadata = null );

	public SaveData GetSaveData()
	{
		return new( FullName, IsWorking, Definition.ResourcePath, WorldPosition, WorldRotation.Yaw(), GetPersistentMetadata() );
	}

	public void SetSaveData( SaveData saveData )
	{
		FullName = saveData.FullName ?? FullName;
		IsWorking = saveData.IsWorking;
		Definition = ResourceLibrary.Get<StaffDefinition>( saveData.ResourcePath );
		WorldPosition = saveData.Position;
		WorldRotation = Rotation.FromYaw( saveData.Rotation );

		SetWorkingState( IsWorking );
		SetPersistentMetadata( saveData.Metadata );
	}

	protected virtual JsonObject GetPersistentMetadata()
	{
		var obj = new JsonObject();
		var stats = new JsonObject();

		foreach ( var (stat, value) in Stats )
		{
			stats.Add( stat.ToString(), value );
		}

		obj["Stats"] = stats;

		return obj;
	}

	protected virtual void SetPersistentMetadata( JsonObject obj )
	{
		if ( obj == null )
			return;

		if ( obj.TryGetPropertyValue( "Stats", out var statsNode ) )
		{
			var statsObj = statsNode.AsObject();
			foreach ( var (k, v) in statsObj )
			{
				if ( Enum.TryParse<StaffStats>( k, out var stat ) )
				{
					Stats[stat] = v.GetValue<int>();
				}
			}
		}
	}
}

public partial class StaffManager : ISaveDataProperty<ImmutableArray<Staff.SaveData>>
{
	string ISaveDataProperty.PropertyName => "Staff";
	int ISaveDataProperty.PropertyOrder => 1_000;

	ImmutableArray<Staff.SaveData> ISaveDataProperty<ImmutableArray<Staff.SaveData>>.WriteValue( Scene scene )
	{
		return Scene.GetAll<Staff>()
			.Select( x => x.GetSaveData() )
			.ToImmutableArray();
	}

	void ISaveDataProperty<ImmutableArray<Staff.SaveData>>.ReadValue( Scene scene, ImmutableArray<Staff.SaveData> array )
	{
		foreach ( var staff in Scene.GetAll<Staff>().ToArray() )
		{
			staff.GameObject.Destroy();
		}

		foreach ( var saveData in array )
		{
			CreateStaffMember(
				ResourceLibrary.Get<StaffDefinition>( saveData.ResourcePath ),
				staff => staff.SetSaveData( saveData )
				);
		}
	}
}