163 lines
4.4 KiB
C#
163 lines
4.4 KiB
C#
// Copyright (C) 2026 SharpEmu Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace SharpEmu.GUI;
|
|
|
|
public sealed class PerGameSettings
|
|
{
|
|
private static readonly JsonSerializerOptions SerializerOptions = new()
|
|
{
|
|
WriteIndented = true,
|
|
};
|
|
|
|
public string? LogLevel { get; set; }
|
|
|
|
public int? ImportTraceLimit { get; set; }
|
|
|
|
public bool? StrictDynlibResolution { get; set; }
|
|
|
|
public bool? LogToFile { get; set; }
|
|
|
|
public string? WindowMode { get; set; }
|
|
|
|
public string? Resolution { get; set; }
|
|
|
|
public int? DisplayIndex { get; set; }
|
|
|
|
public int? RefreshRate { get; set; }
|
|
|
|
public string? ScalingMode { get; set; }
|
|
|
|
public bool? VSync { get; set; }
|
|
|
|
public string? HdrMode { get; set; }
|
|
|
|
public List<string>? EnvironmentToggles { get; set; }
|
|
|
|
[JsonIgnore]
|
|
public bool IsEmpty =>
|
|
LogLevel is null &&
|
|
ImportTraceLimit is null &&
|
|
StrictDynlibResolution is null &&
|
|
LogToFile is null &&
|
|
WindowMode is null &&
|
|
Resolution is null &&
|
|
DisplayIndex is null &&
|
|
RefreshRate is null &&
|
|
ScalingMode is null &&
|
|
VSync is null &&
|
|
HdrMode is null &&
|
|
EnvironmentToggles is null;
|
|
|
|
public static string DirectoryPath =>
|
|
Path.Combine(AppContext.BaseDirectory, "user", "custom_configs");
|
|
|
|
public static string PathFor(string titleId) =>
|
|
Path.Combine(DirectoryPath, SanitizeTitleId(titleId) + ".json");
|
|
|
|
public static PerGameSettings? Load(string? titleId)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(titleId))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
try
|
|
{
|
|
var path = PathFor(titleId);
|
|
if (File.Exists(path))
|
|
{
|
|
return NormalizeFromJson(File.ReadAllText(path));
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// A null list inherits global settings; only entries in a present list are sanitized.
|
|
internal static PerGameSettings? NormalizeFromJson(string json)
|
|
{
|
|
var settings = JsonSerializer.Deserialize<PerGameSettings>(json, SerializerOptions);
|
|
if (settings?.EnvironmentToggles is { } toggles)
|
|
{
|
|
settings.EnvironmentToggles = toggles.Where(entry => !string.IsNullOrEmpty(entry)).ToList();
|
|
}
|
|
|
|
return settings;
|
|
}
|
|
|
|
public void Save(string titleId)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(titleId))
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
var path = PathFor(titleId);
|
|
if (IsEmpty)
|
|
{
|
|
if (File.Exists(path))
|
|
{
|
|
File.Delete(path);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
Directory.CreateDirectory(DirectoryPath);
|
|
File.WriteAllText(path, JsonSerializer.Serialize(this, SerializerOptions));
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
private static string SanitizeTitleId(string titleId)
|
|
{
|
|
var trimmed = titleId.Trim();
|
|
foreach (var invalid in Path.GetInvalidFileNameChars())
|
|
{
|
|
trimmed = trimmed.Replace(invalid, '_');
|
|
}
|
|
|
|
return trimmed.Length == 0 ? "UNKNOWN" : trimmed;
|
|
}
|
|
}
|
|
|
|
public sealed record EffectiveLaunchSettings(
|
|
string LogLevel,
|
|
int ImportTraceLimit,
|
|
bool StrictDynlibResolution,
|
|
bool LogToFile,
|
|
string WindowMode,
|
|
string Resolution,
|
|
int DisplayIndex,
|
|
int RefreshRate,
|
|
string ScalingMode,
|
|
bool VSync,
|
|
string HdrMode,
|
|
IReadOnlyList<string> EnvironmentToggles)
|
|
{
|
|
public static EffectiveLaunchSettings Resolve(GuiSettings global, PerGameSettings? perGame) => new(
|
|
perGame?.LogLevel ?? global.LogLevel,
|
|
perGame?.ImportTraceLimit ?? global.ImportTraceLimit,
|
|
perGame?.StrictDynlibResolution ?? global.StrictDynlibResolution,
|
|
perGame?.LogToFile ?? global.LogToFile,
|
|
perGame?.WindowMode ?? global.WindowMode,
|
|
perGame?.Resolution ?? global.Resolution,
|
|
Math.Max(0, perGame?.DisplayIndex ?? global.DisplayIndex),
|
|
Math.Clamp(perGame?.RefreshRate ?? global.RefreshRate, 0, 1000),
|
|
perGame?.ScalingMode ?? global.ScalingMode,
|
|
perGame?.VSync ?? global.VSync,
|
|
perGame?.HdrMode ?? global.HdrMode,
|
|
perGame?.EnvironmentToggles ?? global.EnvironmentToggles);
|
|
}
|