Settings/GameSettingsSystem.cs
using Sandbox.Audio;

namespace Opium;

public class GameSettings
{
	[Title( "Field Of View" ), Description( "Effects the camera's vision." ), Group( "Gameplay" ), Icon( "grid_view" ), Range( 60, 85, 1 )]
	public float FieldOfView { get; set; } = 85;

	[Title( "Weapon Field Of View" ), Description( "Independently affects the weapon's FOV." ), Group( "Gameplay" ), Icon( "grid_view" ), Range( 65, 90, 1 )]
	public float WeaponFieldOfView { get; set; } = 85;

	[Title( "Dithering" ), Description( "Turns on or off the dithering effect." ), Group( "Graphics" ), Icon( "grid_view" )]
	public bool EnableDitheringShader { get; set; } = true;

	[Title( "Post Processing" ), Description( "Turns on or off the Post Processing effect." ), Group( "Graphics" ), Icon( "grid_view" )]
	public bool EnablePostProcessing { get; set; } = true;

	[Title( "Vertex Snapping" ), Description( "Turns on or off Vertex Snapping." ), Group( "Graphics" ), Icon( "grid_view" )]
	public bool EnableVertexSnapping { get; set; } = true;

	[Title( "Crosshair" ), Description( "Should we show the crosshair always, or just when aiming?" ), Group( "Accessibility" ), Icon( "grid_view" )]
	public bool Crosshair { get; set; } = false;

	[Title( "View Bobbing" ), Description( "How intense should the camera viewbob be?" ), Group( "Accessibility" ), Icon( "grid_view" ), Range( 0.25f, 2, 0.1f )]
	public float ViewbobScale { get; set; } = 1f;

	[Title("Master Volume"), Description("The master volume of the game."), Group("Audio"), Icon("grid_view"), Range(0, 1, 0.1f)]
	public float MasterVolume { get; set; } = 1f;

	[Title("Music Volume"), Description("The music volume of the game."), Group("Audio"), Icon("grid_view"), Range(0, 1, 0.1f)]
	public float MusicVolume { get; set; } = 1f;

	[Title("SFX Volume"), Description("The sound effects volume of the game."), Group("Audio"), Icon("grid_view"), Range(0, 1, 0.1f)]
	public float SFXVolume { get; set; } = 1f;
	[Title("UI Volume"), Description("The UI volume of the game."), Group("Audio"), Icon("grid_view"), Range(0, 1, 0.1f)]
	public float UIVolume { get; set; } = 1f;

	[Title("NPC Volume"), Description("The NPC volume of the game."), Group("Audio"), Icon("grid_view"), Range(0, 1, 0.1f)]
	public float NPCVolume { get; set; } = 1f;
}

public partial class GameSettingsSystem
{
	private static GameSettings current { get; set; }
	public static GameSettings Current
	{
		get
		{
			if ( current is null ) Load();
			return current;
		}
		set
		{
			current = value;
		}
	}

	public static string FilePath => "op_gamesettings.json";

	public static void Save()
	{
		Mixer.Master.Volume = Current.MasterVolume;
		var channel = Mixer.Master.GetChildren();
		channel[0].Volume = Current.MusicVolume;
		channel[1].Volume = Current.SFXVolume;
		channel[2].Volume = Current.UIVolume;
		channel[3].Volume = Current.NPCVolume;

		FileSystem.Data.WriteJson<GameSettings>( FilePath, Current );
	}

	public static void Load()
	{
		Current = FileSystem.Data.ReadJson<GameSettings>( FilePath, new() );
	}
}