Use source generation for SettingsUtil.SetDefaultValues

This commit is contained in:
CasualPokePlayer 2023-10-25 22:50:17 -07:00
parent 5ce0aa24a5
commit f2a4794105
42 changed files with 229 additions and 186 deletions

View File

@ -1,9 +1,9 @@
namespace BizHawk.Analyzers;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace BizHawk.Analyzers;
public static class RoslynUtils
{
public static SyntaxNode? EnclosingTypeDeclarationSyntax(this CSharpSyntaxNode node)

View File

@ -0,0 +1,2 @@
/bin
/obj

View File

@ -0,0 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<Import Project="../AnalyzersCommon.props" />
</Project>

View File

@ -0,0 +1,117 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace BizHawk.SrcGen.SettingsUtil;
[Generator]
public class DefaultSetterGenerator : ISourceGenerator
{
public class SyntaxReceiver : ISyntaxContextReceiver
{
public readonly List<(ClassDeclarationSyntax, SemanticModel)> ClassDeclarations = new();
public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
{
if (context.Node is ClassDeclarationSyntax cds)
{
ClassDeclarations.Add((cds, context.SemanticModel));
}
}
}
public void Initialize(GeneratorInitializationContext context)
=> context.RegisterForSyntaxNotifications(() => new SyntaxReceiver());
private static void CreateDefaultSetter(StringBuilder source, INamespaceOrTypeSymbol symbol)
{
var props = symbol
.GetMembers()
.Where(m => m.Kind == SymbolKind.Property)
.ToImmutableArray();
source.Append($@"
public static void SetDefaultValues({symbol} settings)
{{");
foreach (var prop in props)
{
var defaultValueAttribute = prop
.GetAttributes()
.FirstOrDefault(
a => a.AttributeClass?.Name == "DefaultValueAttribute");
var ctorArgs = defaultValueAttribute?.ConstructorArguments;
if (!ctorArgs.HasValue)
{
continue;
}
switch (ctorArgs.Value.Length)
{
case 1:
// this single arg is just the value assigned to the default value
var arg = ctorArgs.Value[0];
// a bit lame, but it'll work
// TODO: do we even want to handle arrays? do we even have any arrays in default values???
var converionStr = arg.Kind == TypedConstantKind.Array
? $"new {arg.Type} " // new T[]
: ""; // do we need a cast (i.e. (T)) here? probably not?
source.Append($@"
settings.{prop.Name} = {converionStr}{arg.ToCSharpString()};");
break;
case 2:
// first arg is the type, the second arg is a string which converts it
source.Append($@"
settings.{prop.Name} = ({ctorArgs.Value[0].Value})System.ComponentModel.TypeDescriptor
.GetConverter({ctorArgs.Value[0].ToCSharpString()})
.ConvertFromInvariantString({ctorArgs.Value[1].ToCSharpString()});");
break;
}
}
source.Append(@"
}
");
}
public void Execute(GeneratorExecutionContext context)
{
if (context.SyntaxContextReceiver is not SyntaxReceiver syntaxReceiver)
{
return;
}
// Generated source code
var source = new StringBuilder(@"
namespace BizHawk.Common
{
public static partial class SettingsUtil
{");
foreach (var (cds, semanticModel) in syntaxReceiver.ClassDeclarations)
{
if (cds.AttributeLists.SelectMany(e => e.Attributes)
.Any(e => e.Name.NormalizeWhitespace().ToFullString() == "CoreSettings"))
{
var symbol = semanticModel.GetDeclaredSymbol(cds);
if (symbol is not null) // probably never happens?
{
CreateDefaultSetter(source, symbol);
}
}
}
source.Append(@"
}
}");
// Add the source code to the compilation
context.AddSource("DefaultSetters.g.cs", source.ToString());
}
}

View File

@ -0,0 +1 @@
../.build_debug.sh

View File

@ -0,0 +1 @@
../.build_release.sh

Binary file not shown.

View File

@ -10,7 +10,6 @@
<PackageReference Include="Microsoft.Bcl.HashCode" Version="1.1.1" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" PrivateAssets="all" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
</ItemGroup>
<ItemGroup>

View File

@ -1,111 +0,0 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Concurrent;
using System.ComponentModel;
using BizHawk.Common.CollectionExtensions;
namespace BizHawk.Common
{
public static class SettingsUtil
{
private sealed class DefaultValueSetter
{
public readonly Action<object, object[]> SetDefaultValues;
public readonly object[] DefaultValues;
public DefaultValueSetter(Action<object, object[]> setDefaultValues, object[] defaultValues)
{
SetDefaultValues = setDefaultValues;
DefaultValues = defaultValues;
}
}
private static readonly IDictionary<Type, DefaultValueSetter> DefaultValueSetters = new ConcurrentDictionary<Type, DefaultValueSetter>();
/// <summary>
/// set all properties (not fields!) of obj with a DefaultValueAttribute to that value
/// </summary>
/// <param name="obj">the obj to act on</param>
public static void SetDefaultValues<T>(T obj)
where T : notnull
{
var f = DefaultValueSetters.GetValueOrPut(typeof(T), CreateSetter);
f.SetDefaultValues(obj, f.DefaultValues);
}
private static readonly Dictionary<Type, OpCode> IntTypes = new Dictionary<Type,OpCode>
{
{ typeof(byte), OpCodes.Conv_U1 },
{ typeof(sbyte), OpCodes.Conv_I1 },
{ typeof(ushort), OpCodes.Conv_U2 },
{ typeof(short), OpCodes.Conv_I2 },
{ typeof(uint), OpCodes.Conv_U4 },
{ typeof(int), OpCodes.Conv_I4 },
{ typeof(ulong), OpCodes.Conv_U8 },
{ typeof(long), OpCodes.Conv_I8 },
{ typeof(UIntPtr), OpCodes.Conv_U },
{ typeof(IntPtr), OpCodes.Conv_I },
};
private static DefaultValueSetter CreateSetter(Type t)
{
var dyn = new DynamicMethod($"SetDefaultValues_{t.Name}", null, new[] { typeof(object), typeof(object[]) }, false);
var il = dyn.GetILGenerator();
List<object> DefaultValues = new List<object>();
il.Emit(OpCodes.Ldarg_0); // arg0: object to set properties of
il.Emit(OpCodes.Castclass, t); // cast to appropriate type
foreach (var prop in t.GetProperties())
{
if (!prop.CanWrite)
continue;
MethodInfo method = prop.GetSetMethod(true);
foreach (object attr in prop.GetCustomAttributes(true))
{
if (attr is DefaultValueAttribute dvAttr)
{
var value = dvAttr.Value;
Type desiredType = method.GetParameters()[0].ParameterType;
Type sourceType = value.GetType();
int idx = DefaultValues.Count;
DefaultValues.Add(value);
il.Emit(OpCodes.Dup); // object to act on
il.Emit(OpCodes.Ldarg_1); // arg1: array of default values
il.Emit(OpCodes.Ldc_I4, idx); // load index
il.Emit(OpCodes.Ldelem, typeof(object)); // get default value at appropriate index
// cast to the expected type of the set method
if (desiredType.IsAssignableFrom(sourceType))
{
il.Emit(OpCodes.Unbox_Any, desiredType);
}
else if (IntTypes.ContainsKey(sourceType) && IntTypes.TryGetValue(desiredType, out var desiredOpcode))
{
il.Emit(OpCodes.Unbox_Any, sourceType);
il.Emit(desiredOpcode);
}
else
{
throw new InvalidOperationException($"Default value assignment will fail for {t.Name}.{prop.Name}");
}
il.Emit(OpCodes.Callvirt, method);
}
}
}
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ret);
return new DefaultValueSetter(
(Action<object, object[]>) dyn.CreateDelegate(typeof(Action<object, object[]>)),
DefaultValues.ToArray()
);
}
}
}

View File

@ -16,6 +16,8 @@ namespace BizHawk.Emulation.Common
/// <typeparam name="TSettings">The Type of the object that represent regular settings (settings that can be changed during the lifespan of a core instance</typeparam>
/// <typeparam name="TSync">The Type of the object that represents sync settings (settings that can not change during the lifespan of the core and are required for movie sync</typeparam>
public interface ISettable<TSettings, TSync> : IEmulatorService
where TSettings : class, new()
where TSync : class, new()
{
// in addition to these methods, it's expected that the constructor or Load() method
// will take a Settings and SyncSettings object to set the initial state of the core
@ -54,6 +56,15 @@ namespace BizHawk.Emulation.Common
PutSettingsDirtyBits PutSyncSettings(TSync o);
}
/// <summary>
/// Place this attribute for TSettings and TSync classes which use System.ComponentModel.DefaultValue
/// Classes with this attribute will have a BizHawk.Common.SettingsUtil.SetDefaultValues(T) function generated
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class CoreSettings : Attribute
{
}
//note: this is a bit of a frail API. If a frontend wants a new flag, cores won't know to yea or nay it
//this could be solved by adding a KnownSettingsDirtyBits on the settings interface
//or, in a pinch, the same thing could be done with THESE flags, so that the interface doesn't

View File

@ -29,6 +29,7 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
}
[CoreSettings]
public class MAMERTCSettings
{
[DisplayName("Initial Time")]

View File

@ -11,6 +11,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Google.FlatBuffers" Version="22.9.24" Private="true" />
<Analyzer Include="$(ProjectDir)../../References/BizHawk.SrcGen.SettingsUtil.dll" Private="true" />
<Reference Include="FlatBuffers.GenOutput" HintPath="$(ProjectDir)../../References/FlatBuffers.GenOutput.dll" Private="true" />
<Reference Include="Virtu" HintPath="$(ProjectDir)../../References/Virtu.dll" Private="true" />
<ProjectReference Include="$(ProjectDir)../BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj" />

View File

@ -52,6 +52,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
}
[CoreSettings]
public class AmstradCPCSettings
{
[DisplayName("AY-3-8912 Panning Config")]
@ -85,6 +86,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
}
}
[CoreSettings]
public class AmstradCPCSyncSettings
{
[DisplayName("Deterministic Emulation")]

View File

@ -11,6 +11,7 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
private Settings _settings;
private SyncSettings _syncSettings;
[CoreSettings]
public class Settings
{
[DisplayName("Monochrome")]
@ -25,6 +26,7 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
=> (Settings)MemberwiseClone();
}
[CoreSettings]
public class SyncSettings
{
[DisplayName("Initial Time")]

View File

@ -1,4 +1,6 @@
using System.ComponentModel;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Computers.Commodore64
@ -31,6 +33,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
internal C64Settings Settings { get; private set; }
internal C64SyncSettings SyncSettings { get; private set; }
[CoreSettings]
public class C64Settings
{
[DisplayName("Border type")]
@ -50,10 +53,11 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
public C64Settings()
{
BizHawk.Common.SettingsUtil.SetDefaultValues(this);
SettingsUtil.SetDefaultValues(this);
}
}
[CoreSettings]
public class C64SyncSettings
{
[DisplayName("VIC type")]
@ -93,7 +97,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
public C64SyncSettings()
{
BizHawk.Common.SettingsUtil.SetDefaultValues(this);
SettingsUtil.SetDefaultValues(this);
}
}

View File

@ -33,6 +33,7 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
internal MSXSettings Settings { get; private set; }
internal MSXSyncSettings SyncSettings { get; private set; }
[CoreSettings]
public class MSXSettings
{
// graphics settings
@ -62,6 +63,7 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
}
}
[CoreSettings]
public class MSXSyncSettings
{
public enum ContrType

View File

@ -49,6 +49,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
}
[CoreSettings]
public class ZXSpectrumSettings
{
[DisplayName("AY-3-8912 Panning Config")]
@ -97,6 +98,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
}
}
[CoreSettings]
public class ZXSpectrumSyncSettings
{
[DisplayName("Deterministic Emulation")]

View File

@ -30,6 +30,7 @@ namespace BizHawk.Emulation.Cores.Computers.TIC80
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
}
[CoreSettings]
public class TIC80Settings
{
[DisplayName("Crop")]
@ -44,6 +45,7 @@ namespace BizHawk.Emulation.Cores.Computers.TIC80
=> (TIC80Settings)MemberwiseClone();
}
[CoreSettings]
public class TIC80SyncSettings
{
[DisplayName("Gamepad 1 Enable")]

View File

@ -42,6 +42,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
internal A2600Settings Settings { get; private set; }
internal A2600SyncSettings SyncSettings { get; private set; }
[CoreSettings]
public class A2600Settings
{
[JsonIgnore]
@ -147,6 +148,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
}
[CoreSettings]
public class A2600SyncSettings
{
[DefaultValue(Atari2600ControllerTypes.Joystick)]

View File

@ -6,59 +6,33 @@ using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{
public partial class A7800Hawk : IEmulator, ISettable<A7800Hawk.A7800Settings, A7800Hawk.A7800SyncSettings>
public partial class A7800Hawk : IEmulator, ISettable<object, A7800Hawk.A7800SyncSettings>
{
public A7800Settings GetSettings()
{
return _settings.Clone();
}
public object GetSettings()
=> null;
public A7800SyncSettings GetSyncSettings()
{
return _syncSettings.Clone();
}
=> _syncSettings.Clone();
public PutSettingsDirtyBits PutSettings(A7800Settings o)
{
_settings = o;
return PutSettingsDirtyBits.None;
}
public PutSettingsDirtyBits PutSettings(object o)
=> PutSettingsDirtyBits.None;
public PutSettingsDirtyBits PutSyncSettings(A7800SyncSettings o)
{
bool ret = A7800SyncSettings.NeedsReboot(_syncSettings, o);
var ret = A7800SyncSettings.NeedsReboot(_syncSettings, o);
_syncSettings = o;
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
}
private A7800Settings _settings = new A7800Settings();
public A7800SyncSettings _syncSettings = new A7800SyncSettings();
public class A7800Settings
{
public A7800Settings Clone()
{
return (A7800Settings)MemberwiseClone();
}
public A7800Settings()
{
SettingsUtil.SetDefaultValues(this);
}
}
public A7800SyncSettings _syncSettings = new();
public class A7800SyncSettings
{
private string _port1 = A7800HawkControllerDeck.DefaultControllerName;
private string _port2 = A7800HawkControllerDeck.DefaultControllerName;
private string _Filter = "None";
[JsonIgnore]
public string Filter
{
get => _Filter;
set => _Filter = value;
}
public string Filter { get; set; } = "None";
[JsonIgnore]
public string Port1
@ -91,19 +65,10 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
}
public A7800SyncSettings Clone()
{
return (A7800SyncSettings)MemberwiseClone();
}
public A7800SyncSettings()
{
SettingsUtil.SetDefaultValues(this);
}
=> (A7800SyncSettings)MemberwiseClone();
public static bool NeedsReboot(A7800SyncSettings x, A7800SyncSettings y)
{
return !DeepEquality.DeepEquals(x, y);
}
=> !DeepEquality.DeepEquals(x, y);
}
}
}

View File

@ -10,7 +10,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
[Core(CoreNames.A7800Hawk, "")]
[ServiceNotApplicable(new[] { typeof(IDriveLight), typeof(ISettable<,>) })]
public partial class A7800Hawk : IEmulator, ISaveRam, IDebuggable, IInputPollable,
IRegionable, IBoardInfo, ISettable<A7800Hawk.A7800Settings, A7800Hawk.A7800SyncSettings>
IRegionable, IBoardInfo, ISettable<object, A7800Hawk.A7800SyncSettings>
{
internal static class RomChecksums
{
@ -76,7 +76,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
}
[CoreConstructor(VSystemID.Raw.A78)]
public A7800Hawk(CoreComm comm, byte[] rom, A7800Hawk.A7800Settings settings, A7800Hawk.A7800SyncSettings syncSettings)
public A7800Hawk(CoreComm comm, byte[] rom, A7800SyncSettings syncSettings)
{
var ser = new BasicServiceProvider(this);
@ -94,7 +94,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
_blip.SetRates(1789773, 44100);
_settings = settings ?? new A7800Settings();
_syncSettings = syncSettings ?? new A7800SyncSettings();
_controllerDeck = new A7800HawkControllerDeck(_syncSettings.Port1, _syncSettings.Port2);

View File

@ -30,6 +30,7 @@ namespace BizHawk.Emulation.Cores.Atari.Jaguar
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
}
[CoreSettings]
public class VirtualJaguarSettings
{
[DisplayName("Trace M68K (CPU)")]
@ -54,6 +55,7 @@ namespace BizHawk.Emulation.Cores.Atari.Jaguar
=> (VirtualJaguarSettings)MemberwiseClone();
}
[CoreSettings]
public class VirtualJaguarSyncSettings
{
[DisplayName("Player 1 Connected")]

View File

@ -32,6 +32,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
}
[CoreSettings]
public class ChannelFSettings
{
[DisplayName("Default Background Color")]
@ -50,6 +51,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
}
}
[CoreSettings]
public class ChannelFSyncSettings
{
[DisplayName("Deterministic Emulation")]

View File

@ -32,6 +32,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Vectrex
private object _settings = new object();
public VectrexSyncSettings _syncSettings = new VectrexSyncSettings();
[CoreSettings]
public class VectrexSyncSettings
{
[JsonIgnore]

View File

@ -32,6 +32,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
public O2Settings _settings = new O2Settings();
public O2SyncSettings _syncSettings = new O2SyncSettings();
[CoreSettings]
public class O2Settings
{
[DisplayName("Display Characters")]
@ -70,6 +71,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
}
}
[CoreSettings]
public class O2SyncSettings
{
[DisplayName("Use G7400 Enhanemants")]

View File

@ -109,6 +109,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.N3DS
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
}
[CoreSettings]
public class CitraSettings
{
[DisplayName("Resolution Scale Factor")]
@ -240,6 +241,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.N3DS
=> SettingsUtil.SetDefaultValues(this);
}
[CoreSettings]
public class CitraSyncSettings
{
[DisplayName("Use CPU JIT")]

View File

@ -30,6 +30,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
}
[CoreSettings]
public class Ares64Settings
{
[DisplayName("Deinterlacer")]
@ -50,6 +51,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64
=> (Ares64Settings)MemberwiseClone();
}
[CoreSettings]
public class Ares64SyncSettings
{
[DisplayName("Initial Time")]

View File

@ -55,6 +55,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
private Settings _settings;
[CoreSettings]
public class Settings
{
[DisplayName("Display BG Layer 0")]
@ -143,6 +144,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
private SyncSettings _syncSettings;
[CoreSettings]
public class SyncSettings
{
[DisplayName("Skip BIOS")]

View File

@ -37,6 +37,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public GBSettings _settings = new GBSettings();
public GBSyncSettings _syncSettings = new GBSyncSettings();
[CoreSettings]
public class GBSettings
{
public enum PaletteType
@ -82,6 +83,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
}
}
[CoreSettings]
public class GBSyncSettings
{
public enum ConsoleModeType

View File

@ -30,6 +30,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink
private GBLinkSettings linkSettings = new GBLinkSettings();
public GBLinkSyncSettings linkSyncSettings = new GBLinkSyncSettings();
[CoreSettings]
public class GBLinkSettings
{
[DisplayName("Color Mode")]
@ -71,6 +72,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink
public GBLinkSettings() => SettingsUtil.SetDefaultValues(this);
}
[CoreSettings]
public class GBLinkSyncSettings
{
[DisplayName("Console Mode L")]

View File

@ -30,6 +30,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
private GBLink3xSettings Link3xSettings = new GBLink3xSettings();
private GBLink3xSyncSettings Link3xSyncSettings = new GBLink3xSyncSettings();
[CoreSettings]
public class GBLink3xSettings
{
[DisplayName("Color Mode")]
@ -65,6 +66,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
public GBLink3xSettings() => SettingsUtil.SetDefaultValues(this);
}
[CoreSettings]
public class GBLink3xSyncSettings
{
[DisplayName("Console Mode L")]

View File

@ -30,6 +30,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink4x
private GBLink4xSettings Link4xSettings = new GBLink4xSettings();
public GBLink4xSyncSettings Link4xSyncSettings = new GBLink4xSyncSettings();
[CoreSettings]
public class GBLink4xSettings
{
[DisplayName("Color Mode A")]
@ -71,6 +72,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink4x
public GBLink4xSettings() => SettingsUtil.SetDefaultValues(this);
}
[CoreSettings]
public class GBLink4xSyncSettings
{
[DisplayName("Console Mode A")]

View File

@ -97,6 +97,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
}
}
[CoreSettings]
public class GambatteSyncSettings
{
[DisplayName("Use official Nintendo BootROM")]

View File

@ -122,6 +122,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
Rotate270,
}
[CoreSettings]
public class NDSSettings
{
[DisplayName("Screen Layout")]
@ -226,6 +227,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
private static readonly DateTime minDate = new(2000, 1, 1);
private static readonly DateTime maxDate = new(2099, 12, 31, 23, 59, 59);
[CoreSettings]
public class NDSSyncSettings
{
public enum ThreeDeeRendererType : int

View File

@ -50,6 +50,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
/// </summary>
private QuickNESSyncSettings _syncSettingsNext;
[CoreSettings]
public class QuickNESSettings
{
[DefaultValue(8)]
@ -150,6 +151,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
}
}
[CoreSettings]
public class QuickNESSyncSettings
{
[DefaultValue(true)]

View File

@ -149,6 +149,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
}
[CoreSettings]
public class Settings
{
[DefaultValue(true)]
@ -234,6 +235,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
}
}
[CoreSettings]
public class SyncSettings
{
[DefaultValue(LibSnes9x.LeftPortDevice.Joypad)]

View File

@ -45,6 +45,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
}
[CoreSettings]
public class SameboySettings
{
public enum GBPaletteType : uint
@ -192,6 +193,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
=> _customPal = (int[])pal.Clone();
}
[CoreSettings]
public class SameboySyncSettings
{
[DisplayName("Use official BIOS")]

View File

@ -1,4 +1,5 @@
using System.ComponentModel;
using BizHawk.Common;
using BizHawk.Emulation.Common;
@ -7,14 +8,10 @@ namespace BizHawk.Emulation.Cores.Sega.GGHawkLink
public partial class GGHawkLink : IEmulator, IStatable, ISettable<GGHawkLink.GGLinkSettings, GGHawkLink.GGLinkSyncSettings>
{
public GGLinkSettings GetSettings()
{
return linkSettings.Clone();
}
=> linkSettings.Clone();
public GGLinkSyncSettings GetSyncSettings()
{
return linkSyncSettings.Clone();
}
=> linkSyncSettings.Clone();
public PutSettingsDirtyBits PutSettings(GGLinkSettings o)
{
@ -24,14 +21,15 @@ namespace BizHawk.Emulation.Cores.Sega.GGHawkLink
public PutSettingsDirtyBits PutSyncSettings(GGLinkSyncSettings o)
{
bool ret = GGLinkSyncSettings.NeedsReboot(linkSyncSettings, o);
var ret = GGLinkSyncSettings.NeedsReboot(linkSyncSettings, o);
linkSyncSettings = o;
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
}
private GGLinkSettings linkSettings = new GGLinkSettings();
public GGLinkSyncSettings linkSyncSettings = new GGLinkSyncSettings();
private GGLinkSettings linkSettings = new();
public GGLinkSyncSettings linkSyncSettings = new();
[CoreSettings]
public class GGLinkSettings
{
public enum AudioSrc
@ -46,29 +44,29 @@ namespace BizHawk.Emulation.Cores.Sega.GGHawkLink
[DefaultValue(AudioSrc.Left)]
public AudioSrc AudioSet { get; set; }
public GGLinkSettings()
=> SettingsUtil.SetDefaultValues(this);
public GGLinkSettings Clone()
{
return (GGLinkSettings)MemberwiseClone();
}
=> (GGLinkSettings)MemberwiseClone();
}
[CoreSettings]
public class GGLinkSyncSettings
{
[DisplayName("Use Existing SaveRAM")]
[Description("When true, existing SaveRAM will be loaded at boot up")]
[DefaultValue(true)]
public bool Use_SRAM { get; set; }
public GGLinkSyncSettings()
=> SettingsUtil.SetDefaultValues(this);
public GGLinkSyncSettings Clone()
{
return (GGLinkSyncSettings)MemberwiseClone();
}
=> (GGLinkSyncSettings)MemberwiseClone();
public static bool NeedsReboot(GGLinkSyncSettings x, GGLinkSyncSettings y)
{
return !DeepEquality.DeepEquals(x, y);
}
=> !DeepEquality.DeepEquals(x, y);
}
}
}

View File

@ -179,6 +179,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
_core.SetCDReadCallback(_cdcallback);
}
[CoreSettings]
public class SyncSettings
{
[DefaultValue(LibPicoDrive.Region.Auto)]

View File

@ -116,6 +116,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
private GPGXSyncSettings _syncSettings;
private GPGXSettings _settings;
[CoreSettings]
public class GPGXSettings
{
[DeepEqualsIgnore]
@ -239,6 +240,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
}
[CoreSettings]
public class GPGXSyncSettings
{
[DisplayName("Use Six Button Controllers")]

View File

@ -1142,6 +1142,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
BobOffset
}
[CoreSettings]
public class Settings
{
[DisplayName("Determine Lag from GPU Frames")]

View File

@ -1,9 +1,10 @@
using System;
using BizHawk.Emulation.Common;
using System.ComponentModel;
using BizHawk.Common;
using System.Drawing;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.WonderSwan
{
partial class WonderSwan : ISettable<WonderSwan.Settings, WonderSwan.SyncSettings>
@ -11,6 +12,7 @@ namespace BizHawk.Emulation.Cores.WonderSwan
private Settings _settings;
private SyncSettings _syncSettings;
[CoreSettings]
public class Settings
{
[DisplayName("Background Layer")]
@ -83,6 +85,7 @@ namespace BizHawk.Emulation.Cores.WonderSwan
}
}
[CoreSettings]
public class SyncSettings
{
[DisplayName("Initial Time")]