PartituraStore.cs

Static store for per-character "partituras" (face charts) saved as JSON under FileSystem.Data/sprunki_partituras/<personaje>.json. It loads factory defaults if no local file, saves edits, normalizes tracks to fixed length, and applies data copies to a live PartituraCaras component.

File Access
namespace SBH;

using Sandbox;
using System.Collections.Generic;

/// <summary>
/// [SBHBase] Guardado de partituras de caras, una por personaje, en
/// FileSystem.Data (sprunki_partituras/&lt;personaje&gt;.json). El editor del
/// menú C guarda acá en cada pincelada; PartituraInyector carga al inyectar.
/// </summary>
public static class PartituraStore
{
	public class Datos
	{
		public List<int> LoopA { get; set; } = PartituraCaras.PistaVacia();
		public List<int> LoopB { get; set; } = PartituraCaras.PistaVacia();
		public List<int> HorrorA { get; set; } = PartituraCaras.PistaVacia();
		public List<int> HorrorB { get; set; } = PartituraCaras.PistaVacia();
	}

	const string Carpeta = "sprunki_partituras";

	static string Ruta( string personaje ) => $"{Carpeta}/{personaje}.json";

	public static Datos Cargar( string personaje )
	{
		if ( string.IsNullOrEmpty( personaje ) ) return null;

		// El JSON local (lo último pintado en el editor) manda; sin él, las
		// partituras de fábrica horneadas en la librería (tools/hornear_partituras)
		if ( !FileSystem.Data.FileExists( Ruta( personaje ) ) )
			return DeFabrica( personaje );

		var datos = FileSystem.Data.ReadJson<Datos>( Ruta( personaje ) );
		if ( datos == null ) return DeFabrica( personaje );

		Normalizar( datos );
		return datos;
	}

	static Datos DeFabrica( string personaje )
	{
		var datos = PartiturasDeFabrica.Obtener( personaje );
		if ( datos != null ) Normalizar( datos );
		return datos;
	}

	public static void Guardar( string personaje, Datos datos )
	{
		if ( string.IsNullOrEmpty( personaje ) || datos == null ) return;

		FileSystem.Data.CreateDirectory( Carpeta );
		FileSystem.Data.WriteJson( Ruta( personaje ), datos );
	}

	/// <summary> Vuelca los datos al componente vivo (copias, no referencias compartidas). </summary>
	public static void AplicarA( PartituraCaras partitura, Datos datos )
	{
		if ( !partitura.IsValid() || datos == null ) return;

		partitura.LoopA = new List<int>( datos.LoopA );
		partitura.LoopB = new List<int>( datos.LoopB );
		partitura.HorrorA = new List<int>( datos.HorrorA );
		partitura.HorrorB = new List<int>( datos.HorrorB );
	}

	/// <summary> Pistas siempre de 48 casilleros, venga como venga el JSON. </summary>
	static void Normalizar( Datos datos )
	{
		datos.LoopA = Ajustar( datos.LoopA );
		datos.LoopB = Ajustar( datos.LoopB );
		datos.HorrorA = Ajustar( datos.HorrorA );
		datos.HorrorB = Ajustar( datos.HorrorB );
	}

	static List<int> Ajustar( List<int> pista )
	{
		pista ??= new List<int>();
		while ( pista.Count < PartituraCaras.Casilleros ) pista.Add( -1 );
		if ( pista.Count > PartituraCaras.Casilleros )
			pista.RemoveRange( PartituraCaras.Casilleros, pista.Count - PartituraCaras.Casilleros );
		return pista;
	}
}