SaveGame.cs

Static SaveGame helper for persisting and loading game state to FileSystem.Data. It assembles a SaveData object by invoking many subsystem WriteToSave methods and writes JSON, and reads JSON then validates and applies it by calling subsystem Load/Write methods.

File Access
namespace NoChillquarium;

/// <summary>
/// Persist wallet + tank fish to FileSystem.Data.
/// </summary>
public static class SaveGame
{
	public static bool HasSave
	{
		get
		{
			try
			{
				return FileSystem.Data.FileExists( SaveData.FileName );
			}
			catch
			{
				return false;
			}
		}
	}

	/// <param name="quiet">When true (autosave), skip console chatter.</param>
	public static bool TrySave( bool quiet = false )
	{
		if ( !TankSim.IsActive )
			return false;

		try
		{
			var data = new SaveData
			{
				Version = SaveData.CurrentVersion
			};

			Economy.WriteToSave( data );
			Chaos.WriteToSave( data );
			Karma.WriteToSave( data );
			Shop.WriteInventory( data );
			FeedSystem.WriteToSave( data );
			TrainingSystem.WriteToSave( data );
			MethRush.WriteToSave( data );
			BattleSystem.WriteToSave( data );
			SharkSystem.WriteToSave( data );
			EndingSystem.WriteToSave( data );
			StorySystem.WriteToSave( data );
			GrandmaGifts.WriteToSave( data );
			GrandmaReact.WriteToSave( data );
			LotRunSystem.WriteToSave( data );
			CrimeSystem.WriteToSave( data );
			AchievementSystem.WriteToSave( data );
			TankSim.WriteToSave( data );
			FileSystem.Data.WriteJson( SaveData.FileName, data );
			if ( !quiet )
				Log.Info( $"[NO-CHILLquarium] Saved. Ð{Economy.BalanceText} · {TankSim.FishCount} fish." );
			return true;
		}
		catch ( Exception e )
		{
			Log.Warning( $"[NO-CHILLquarium] Save failed: {e.Message}" );
			return false;
		}
	}

	public static bool TryLoad( out SaveData data )
	{
		data = null;

		try
		{
			if ( !FileSystem.Data.FileExists( SaveData.FileName ) )
				return false;

			data = FileSystem.Data.ReadJsonOrDefault<SaveData>( SaveData.FileName, null );
			if ( data is null )
				return false;

			var hasFish =
				(data.FreshFish is { Count: > 0 })
				|| (data.SaltFish is { Count: > 0 })
				|| (data.Fish is { Count: > 0 });

			// Allow empty-but-valid dual-tank unlock saves.
			if ( !hasFish && !data.SaltUnlocked && data.Dogecoin <= 0 )
				return false;

			return true;
		}
		catch ( Exception e )
		{
			Log.Warning( $"[NO-CHILLquarium] Load failed: {e.Message}" );
			data = null;
			return false;
		}
	}

	public static bool ApplyLoadedSave()
	{
		if ( !TryLoad( out var data ) )
			return false;

		Economy.LoadFromSave( data );
		Chaos.LoadFromSave( data );
		Karma.LoadFromSave( data );
		Shop.LoadInventory( data.MethBags, data.M80Bags );
		FeedSystem.Load( data.UnlockedFoods, data.SelectedFoodId );
		TrainingSystem.Load( data.Syringes );
		MethRush.Load( data.TankCracks );
		BattleSystem.Load( data.BattleWins, data.BattleLosses, data.BattlesBeaten, data.PrizeHabitatsWon, data.ChampionshipTitles );
		SharkSystem.Load( data.SharkKills, data.SharkEaten, data.SharkEverSpawned );
		EndingSystem.Load( data.HasWmd, data.HasWhale, data.EndingReached );
		TankSim.LoadFromSave( data );
		StorySystem.Load( data );
		GrandmaGifts.Load( data );
		GrandmaReact.Load( data );
		LotRunSystem.Load( data );
		CrimeSystem.Load( data );
		AchievementSystem.Load( data );
		return TankSim.IsActive;
	}
}