diff --git a/Common.ruleset b/Common.ruleset
index 62a51e1eb9d..d14cbf4f1bb 100644
--- a/Common.ruleset
+++ b/Common.ruleset
@@ -28,6 +28,9 @@
+
+
+
diff --git a/ExternalProjects/AnalyzersCommon/Extensions.cs b/ExternalProjects/AnalyzersCommon/Extensions.cs
new file mode 100644
index 00000000000..fde05992483
--- /dev/null
+++ b/ExternalProjects/AnalyzersCommon/Extensions.cs
@@ -0,0 +1,14 @@
+namespace BizHawk.Analyzers;
+
+public static class Extensions
+{
+ public static string RemovePrefix(this string str, string prefix)
+ => str.StartsWith(prefix) ? str.Substring(prefix.Length, str.Length - prefix.Length) : str;
+
+ public static void SwapReferences(ref T a, ref T b)
+ {
+ ref T c = ref a; // using var results in CS8619 warning?
+ a = ref b;
+ b = ref c;
+ }
+}
diff --git a/ExternalProjects/AnalyzersCommon/RoslynUtils.cs b/ExternalProjects/AnalyzersCommon/RoslynUtils.cs
index 7c7dea0b7b4..45297075e51 100644
--- a/ExternalProjects/AnalyzersCommon/RoslynUtils.cs
+++ b/ExternalProjects/AnalyzersCommon/RoslynUtils.cs
@@ -1,5 +1,8 @@
namespace BizHawk.Analyzers;
+using System.Collections.Generic;
+using System.Linq;
+
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -13,6 +16,67 @@ public static class RoslynUtils
return parent;
}
+ public static string FullNamespace(this ISymbol? sym)
+ {
+ if (sym is null) return string.Empty;
+ var s = sym.Name;
+ var ns = sym.ContainingNamespace;
+ while (ns is { IsGlobalNamespace: false })
+ {
+ s = $"{ns.Name}.{s}";
+ ns = ns.ContainingNamespace;
+ }
+ return s;
+ }
+
+ /// required to differentiate record class and record struct (later Roslyn versions will make this redundant)
+ ///
+ /// one of:
+ ///
+ /// - { "abstract", "class" }
+ /// - { "abstract", "partial", "class" }
+ /// - { "class" }
+ /// - { "enum" }
+ /// - { "interface" }
+ /// - { "partial", "class" }
+ /// - { "partial", "interface" }
+ /// - { "partial", "record", "class" }
+ /// - { "partial", "record", "struct" }
+ /// - { "partial", "struct" }
+ /// - { "record", "class" }
+ /// - { "record", "struct" }
+ /// - { "sealed", "class" }
+ /// - { "sealed", "partial", "class" }
+ /// - { "static", "class" }
+ /// - { "static", "partial", "class" }
+ /// - { "struct" }
+ ///
+ ///
+ /// this list is correct and complete as of C# 10, despite what the official documentation of these keywords might say (static partial class nowhere in sight)
+ public static IReadOnlyList GetTypeKeywords(this BaseTypeDeclarationSyntax btds, INamedTypeSymbol sym)
+ {
+ // maybe it would make more sense to have a [Flags] enum (Abstract | Concrete | Delegate | Enum | Partial | Record | Sealed | ValueType) okay I've overengineered this
+ // what about using ONLY cSym? I think that's more correct anyway as it combines partial interfaces
+ if (btds is EnumDeclarationSyntax) return new[] { /*eds.EnumKeyword.Text*/"enum" };
+ var tds = (TypeDeclarationSyntax) btds;
+ List keywords = new() { tds.Keyword.Text };
+#if true
+ if (tds is RecordDeclarationSyntax) keywords.Add(sym.IsValueType ? "struct" : "class");
+#else // requires newer Roslyn
+ if (tds is RecordDeclarationSyntax rds)
+ {
+ var s = rds.ClassOrStructKeyword.Text;
+ keywords.Add(s is "" ? "class" : s);
+ }
+#endif
+ var mods = tds.Modifiers.Select(static st => st.Text).ToList();
+ if (mods.Contains("partial")) keywords.Insert(0, "partial");
+ if (mods.Contains("abstract")) keywords.Insert(0, "abstract");
+ else if (mods.Contains("sealed")) keywords.Insert(0, "sealed");
+ else if (mods.Contains("static")) keywords.Insert(0, "static");
+ return keywords;
+ }
+
private static ITypeSymbol? GetThrownExceptionType(this SemanticModel model, ExpressionSyntax exprSyn)
=> exprSyn is ObjectCreationExpressionSyntax
? model.GetTypeInfo(exprSyn).Type
diff --git a/ExternalProjects/BizHawk.SrcGen.VIM/BizHawk.SrcGen.VIM.csproj b/ExternalProjects/BizHawk.SrcGen.VIM/BizHawk.SrcGen.VIM.csproj
new file mode 100644
index 00000000000..584b93fea02
--- /dev/null
+++ b/ExternalProjects/BizHawk.SrcGen.VIM/BizHawk.SrcGen.VIM.csproj
@@ -0,0 +1,9 @@
+
+
+ netstandard2.0
+
+
+
+
+
+
diff --git a/ExternalProjects/BizHawk.SrcGen.VIM/VIMGenerator.cs b/ExternalProjects/BizHawk.SrcGen.VIM/VIMGenerator.cs
new file mode 100644
index 00000000000..b0bf41c0288
--- /dev/null
+++ b/ExternalProjects/BizHawk.SrcGen.VIM/VIMGenerator.cs
@@ -0,0 +1,239 @@
+namespace BizHawk.SrcGen.VIM;
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using BizHawk.Analyzers;
+using BizHawk.Common;
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Text;
+
+using ImplNotesList = System.Collections.Generic.Dictionary>;
+
+[Generator]
+public sealed class VIMGenerator : ISourceGenerator
+{
+ internal readonly struct ImplNotes
+ {
+ public readonly string AccessorKeyword;
+
+ public readonly string BaseImplNamePrefix;
+
+ public readonly string InvokeCall;
+
+ public readonly bool IsSetOrRemove
+ => MethodSym.MethodKind is MethodKind.PropertySet or MethodKind.EventRemove;
+
+ public readonly string MemberFullNameArgs;
+
+ public readonly IMethodSymbol MethodSym;
+
+ public readonly string ReturnType;
+
+ public ImplNotes(IMethodSymbol methodSym, string memberFullNameArgs, string baseImplNamePrefix)
+ {
+ BaseImplNamePrefix = baseImplNamePrefix;
+ MemberFullNameArgs = memberFullNameArgs;
+ MethodSym = methodSym;
+ switch (methodSym.MethodKind)
+ {
+ case MethodKind.Ordinary:
+ AccessorKeyword = string.Empty;
+ InvokeCall = $"(this{string.Concat(methodSym.Parameters.Select(static pSym => $", {pSym.Name}"))})";
+ MemberFullNameArgs += $"({string.Join(", ", methodSym.Parameters.Select(static pSym => $"{pSym.Type.ToDisplayString()} {pSym.Name}"))})";
+ ReturnType = methodSym.ReturnType.ToDisplayString();
+ break;
+ case MethodKind.PropertyGet:
+ AccessorKeyword = "get";
+ InvokeCall = "(this)";
+ ReturnType = methodSym.ReturnType.ToDisplayString();
+ break;
+ case MethodKind.PropertySet:
+ AccessorKeyword = "set";
+ InvokeCall = "(this, value)";
+ ReturnType = ((IPropertySymbol) methodSym.AssociatedSymbol!).Type.ToDisplayString(); // only used for set-only props
+ break;
+ case MethodKind.EventAdd:
+ AccessorKeyword = "add";
+ InvokeCall = "(this, value)";
+ ReturnType = $"event {((IEventSymbol) methodSym.AssociatedSymbol!).Type.ToDisplayString()}";
+ break;
+ case MethodKind.EventRemove:
+ AccessorKeyword = "remove";
+ InvokeCall = "(this, value)";
+ ReturnType = string.Empty; // unused
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+ if (!string.IsNullOrEmpty(AccessorKeyword)) BaseImplNamePrefix += $"_{AccessorKeyword}";
+ }
+ }
+
+ private sealed class VIMGenSyntaxReceiver : ISyntaxReceiver
+ {
+ public readonly List Candidates = new();
+
+ public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
+ {
+ if (syntaxNode is TypeDeclarationSyntax syn) Candidates.Add(syn);
+ }
+ }
+
+ private static readonly DiagnosticDescriptor DiagCantMakeVirtual = new(
+ id: "BHI2000",
+ title: "Only apply [VirtualMethod] to (abstract) methods and property/event accessors",
+ messageFormat: "Can't apply [VirtualMethod] to this kind of member, only methods and property/event accessors",
+ category: "Usage",
+ defaultSeverity: DiagnosticSeverity.Warning,
+ isEnabledByDefault: true);
+
+#if false
+ private static readonly DiagnosticDescriptor DiagDebug = new(
+ id: "BHI2099",
+ title: "debug",
+ messageFormat: "{0}",
+ category: "Usage",
+ defaultSeverity: DiagnosticSeverity.Warning,
+ isEnabledByDefault: true);
+#endif
+
+ //TODO warning for attr used on member of class/struct/record?
+
+ //TODO warning for only one of get/set/add/remove pair has attr?
+
+ //TODO warning for unused base implementation (i.e. impl/override exists in every direct implementor)? ofc the attribute can be pointing to any static method, so the base implementation itself shouldn't be marked unused
+
+ public void Initialize(GeneratorInitializationContext context)
+ => context.RegisterForSyntaxNotifications(static () => new VIMGenSyntaxReceiver());
+
+ public void Execute(GeneratorExecutionContext context)
+ {
+ if (context.SyntaxReceiver is not VIMGenSyntaxReceiver receiver) return;
+
+ // boilerplate to get attr working
+ var compilation = context.Compilation;
+ var vimAttrSymbol = compilation.GetTypeByMetadataName("BizHawk.Common." + nameof(VirtualMethodAttribute));
+ if (vimAttrSymbol is null)
+ {
+ var attributesSource = SourceText.From(typeof(VIMGenerator).Assembly.GetManifestResourceStream("BizHawk.SrcGen.VIM.VirtualMethodAttribute.cs")!, Encoding.UTF8, canBeEmbedded: true);
+ context.AddSource("VirtualMethodAttribute.cs", attributesSource);
+ compilation = context.Compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(attributesSource, (CSharpParseOptions) ((CSharpCompilation) context.Compilation).SyntaxTrees[0].Options));
+ vimAttrSymbol = compilation.GetTypeByMetadataName("BizHawk.Common." + nameof(VirtualMethodAttribute))!;
+ }
+
+ Dictionary vimDict = new();
+ ImplNotesList Lookup(INamedTypeSymbol intfSym)
+ {
+ var fqn = intfSym.FullNamespace();
+ if (vimDict.TryGetValue(fqn, out var implNotes)) return implNotes;
+ // else cache miss
+ ImplNotesList implNotes1 = new();
+ static (string? ImplsClassFullName, string? BaseImplMethodName) ParseVIMAttr(AttributeData vimAttr)
+ {
+ string? baseImplMethodName = null;
+ string? implsClassFullName = null;
+ foreach (var kvp in vimAttr.NamedArguments) switch (kvp.Key)
+ {
+ case nameof(VirtualMethodAttribute.BaseImplMethodName):
+ baseImplMethodName = kvp.Value.Value?.ToString();
+ break;
+ case nameof(VirtualMethodAttribute.ImplsClassFullName):
+ implsClassFullName = kvp.Value.Value?.ToString();
+ break;
+ }
+ return (implsClassFullName, baseImplMethodName);
+ }
+ void AddMethodNotes(IMethodSymbol methodSym, (string? ImplsClassFullName, string? BaseImplMethodName) attrProps)
+ {
+ var memberName = methodSym.MethodKind is MethodKind.Ordinary ? methodSym.Name : methodSym.AssociatedSymbol!.Name;
+ var memberFullNameArgs = $"{intfSym.FullNamespace()}.{memberName}";
+ var baseImplNamePrefix = $"{(attrProps.ImplsClassFullName ?? $"{intfSym.FullNamespace()}.MethodDefaultImpls")}.{attrProps.BaseImplMethodName ?? memberName}";
+ if (!implNotes1.TryGetValue(memberFullNameArgs, out var parts)) parts = implNotes1[memberFullNameArgs] = new();
+ parts.Add(new(methodSym, memberFullNameArgs: memberFullNameArgs, baseImplNamePrefix: baseImplNamePrefix));
+ }
+ foreach (var memberSym in intfSym.GetMembers())
+ {
+ var vimAttr = memberSym.GetAttributes().FirstOrDefault(ad => vimAttrSymbol.Matches(ad.AttributeClass));
+ switch (memberSym)
+ {
+ case IMethodSymbol methodSym: // methods and prop accessors (accessors in interface events are an error without DIM)
+ if (vimAttr is null) continue;
+ if (methodSym.MethodKind is not (MethodKind.Ordinary or MethodKind.PropertyGet or MethodKind.PropertySet))
+ {
+ // no idea what would actually trigger this
+ context.ReportDiagnostic(Diagnostic.Create(DiagCantMakeVirtual, vimAttr.ApplicationSyntaxReference!.GetSyntax().GetLocation()));
+ continue;
+ }
+ AddMethodNotes(methodSym, ParseVIMAttr(vimAttr));
+ continue;
+ case IPropertySymbol propSym: // props
+ if (vimAttr is null) continue;
+ var parsed = ParseVIMAttr(vimAttr);
+ if (propSym.GetMethod is {} getter) AddMethodNotes(getter, parsed);
+ if (propSym.SetMethod is {} setter) AddMethodNotes(setter, parsed);
+ continue;
+ case IEventSymbol eventSym: // events
+ if (vimAttr is null) continue;
+ var parsed1 = ParseVIMAttr(vimAttr);
+ AddMethodNotes(eventSym.AddMethod!, parsed1);
+ AddMethodNotes(eventSym.RemoveMethod!, parsed1);
+ continue;
+ }
+ }
+
+ return vimDict[fqn] = implNotes1;
+ }
+
+ List seen = new();
+ foreach (var tds in receiver.Candidates)
+ {
+ var cSym = compilation.GetSemanticModel(tds.SyntaxTree).GetDeclaredSymbol(tds)!;
+ if (seen.Contains(cSym)) continue; // dedup partial classes
+ seen.Add(cSym);
+ var typeKeywords = tds.GetTypeKeywords(cSym);
+ if (typeKeywords.Contains("enum") || typeKeywords.Contains("interface") || typeKeywords.Contains("static")) continue;
+
+ var nSpace = cSym.ContainingNamespace.ToDisplayString();
+ var nSpaceDot = $"{nSpace}.";
+ List innerText = new();
+ var intfsToImplement = cSym.BaseType is not null
+ ? cSym.AllInterfaces.Except(cSym.BaseType.AllInterfaces) // superclass (or its superclass, etc.) already has the delegated base implementations of these interfaces' virtual methods
+ : cSym.AllInterfaces;
+ //TODO let an interface override a superinterface's virtual method -- may need to order intfsToImplement somehow
+ foreach (var methodParts in intfsToImplement.SelectMany(intfSym => Lookup(intfSym).Values))
+ {
+ var methodSym = methodParts[0].MethodSym;
+ if (cSym.FindImplementationForInterfaceMember(methodSym) is not null) continue; // overridden
+ var memberImplText = $"{methodParts[0].ReturnType} {methodParts[0].MemberFullNameArgs.RemovePrefix(nSpaceDot)}";
+ if (methodSym.MethodKind is MethodKind.Ordinary)
+ {
+ memberImplText += $"\n\t\t\t=> {methodParts[0].BaseImplNamePrefix.RemovePrefix(nSpaceDot)}{methodParts[0].InvokeCall};";
+ }
+ else
+ {
+ if (methodParts[0].IsSetOrRemove) methodParts.Reverse();
+ memberImplText += $"\n\t\t{{{string.Concat(methodParts.Select(methodNotes => $"\n\t\t\t{methodNotes.AccessorKeyword} => {methodNotes.BaseImplNamePrefix.RemovePrefix(nSpaceDot)}{methodNotes.InvokeCall};"))}\n\t\t}}";
+ }
+ innerText.Add(memberImplText);
+ }
+ if (innerText.Count is not 0) context.AddSource(
+ source: $@"#nullable enable
+
+namespace {nSpace}
+{{
+ public {string.Join(" ", typeKeywords)} {cSym.Name}
+ {{
+ {string.Join("\n\n\t\t", innerText)}
+ }}
+}}
+",
+ hintName: $"{cSym.Name}.VIMDelegation.cs");
+ }
+ }
+}
diff --git a/ExternalProjects/BizHawk.SrcGen.VIM/VirtualMethodAttribute.cs b/ExternalProjects/BizHawk.SrcGen.VIM/VirtualMethodAttribute.cs
new file mode 100644
index 00000000000..b661cf99912
--- /dev/null
+++ b/ExternalProjects/BizHawk.SrcGen.VIM/VirtualMethodAttribute.cs
@@ -0,0 +1,26 @@
+#nullable enable // for when this file is embedded
+
+using System;
+
+namespace BizHawk.Common
+{
+ ///
+ /// Allows methods in interfaces to be treated like methods, similar to how they behave in classes.
+ /// And the same for property accessors and events (accessors in interface events are an error without DIM, apply to event).
+ ///
+ ///
+ /// The base implementation can't be written into the interface, so it needs to be in a separate (usually inner) static class. A Source Generator will then add the necessary delegating method implementations at compile-time.
+ /// These faux- methods support the same / mechanisms that you'd expect of classes: just apply the keyword as usual.
+ ///
+ ///
+ ///
+ [AttributeUsage(AttributeTargets.Event | AttributeTargets.Property | AttributeTargets.Method, Inherited = false)]
+ public sealed class VirtualMethodAttribute : Attribute
+ {
+ /// if unset, uses annotated method's name (with _get/_set/_add/_remove suffix for props/events)
+ public string? BaseImplMethodName { get; set; } = null;
+
+ /// if unset, uses $"{interfaceFullName}.MethodDefaultImpls"
+ public string? ImplsClassFullName { get; set; } = null;
+ }
+}
diff --git a/ExternalProjects/BizHawk.SrcGen.VIM/build_debug.sh b/ExternalProjects/BizHawk.SrcGen.VIM/build_debug.sh
new file mode 120000
index 00000000000..c2127aded12
--- /dev/null
+++ b/ExternalProjects/BizHawk.SrcGen.VIM/build_debug.sh
@@ -0,0 +1 @@
+../.build_debug.sh
\ No newline at end of file
diff --git a/ExternalProjects/BizHawk.SrcGen.VIM/build_release.sh b/ExternalProjects/BizHawk.SrcGen.VIM/build_release.sh
new file mode 120000
index 00000000000..801b8e5998a
--- /dev/null
+++ b/ExternalProjects/BizHawk.SrcGen.VIM/build_release.sh
@@ -0,0 +1 @@
+../.build_release.sh
\ No newline at end of file
diff --git a/References/BizHawk.SrcGen.VIM.dll b/References/BizHawk.SrcGen.VIM.dll
new file mode 100644
index 00000000000..5dc9bc06a8c
Binary files /dev/null and b/References/BizHawk.SrcGen.VIM.dll differ
diff --git a/src/BizHawk.Emulation.Common/Base Implementations/LinkedDebuggable.cs b/src/BizHawk.Emulation.Common/Base Implementations/LinkedDebuggable.cs
index d6dde3a173e..c45d2299e2d 100644
--- a/src/BizHawk.Emulation.Common/Base Implementations/LinkedDebuggable.cs
+++ b/src/BizHawk.Emulation.Common/Base Implementations/LinkedDebuggable.cs
@@ -8,7 +8,7 @@ namespace BizHawk.Emulation.Common
/// A generic linked implementation of IDebuggable that can be used by any link core
///
///
- public class LinkedDebuggable : IDebuggable
+ public partial class LinkedDebuggable : IDebuggable
{
private readonly IEmulator[] _linkedCores;
private readonly int _numCores;
@@ -46,8 +46,6 @@ public void SetCpuRegister(string register, int value)
public IMemoryCallbackSystem MemoryCallbacks { get; }
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Common/Interfaces/Services/IDebuggable.cs b/src/BizHawk.Emulation.Common/Interfaces/Services/IDebuggable.cs
index 54d52b19bb0..6d15bda219f 100644
--- a/src/BizHawk.Emulation.Common/Interfaces/Services/IDebuggable.cs
+++ b/src/BizHawk.Emulation.Common/Interfaces/Services/IDebuggable.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
+using BizHawk.Common;
+
namespace BizHawk.Emulation.Common
{
///
@@ -12,6 +14,12 @@ namespace BizHawk.Emulation.Common
///
public interface IDebuggable : IEmulatorService
{
+ public static class MethodDefaultImpls
+ {
+ public static bool CanStep(IDebuggable self, StepType type)
+ => false;
+ }
+
///
/// Returns a list of CPU registers and their current state
///
@@ -31,6 +39,7 @@ public interface IDebuggable : IEmulatorService
/// Informs the calling code whether or not the given step type is implemented,
/// if false, a NotImplementedException will be thrown if Step is called with the given value
///
+ [VirtualMethod]
bool CanStep(StepType type);
///
diff --git a/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IDebuggable.cs
index a62c5fc1f86..6ab35c6baf2 100644
--- a/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Calculators/Emu83/Emu83.IDebuggable.cs
@@ -30,8 +30,6 @@ public IDictionary GetCpuFlagsAndRegisters()
[FeatureNotImplemented]
public void SetCpuRegister(string register, int value) => throw new NotImplementedException();
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IDebuggable.cs
index b55e40fac32..f0821e89632 100644
--- a/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Calculators/TI83/TI83.IDebuggable.cs
@@ -15,8 +15,6 @@ public partial class TI83 : IDebuggable
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
- public bool CanStep(StepType type) => false;
-
public long TotalExecutedCycles => _cpu.TotalExecutedCycles;
}
}
diff --git a/src/BizHawk.Emulation.Cores/Computers/AmstradCPC/AmstradCPC.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Computers/AmstradCPC/AmstradCPC.IDebuggable.cs
index d1316422177..3670fe68eb2 100644
--- a/src/BizHawk.Emulation.Cores/Computers/AmstradCPC/AmstradCPC.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Computers/AmstradCPC/AmstradCPC.IDebuggable.cs
@@ -16,8 +16,6 @@ public partial class AmstradCPC : IDebuggable
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.IDebuggable.cs
index 9d514199964..a0dee57fc6c 100644
--- a/src/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.IDebuggable.cs
@@ -16,8 +16,6 @@ public partial class ZXSpectrum : IDebuggable
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IDebuggable.cs
index 71cf6cf9844..6289a6f2762 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IDebuggable.cs
@@ -12,8 +12,6 @@ public partial class Atari2600 : IDebuggable
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IDebuggable.cs
index 30476662481..cdadd9aa4cb 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IDebuggable.cs
@@ -12,8 +12,6 @@ public partial class A7800Hawk : IDebuggable
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/jaguar/VirtualJaguar.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/jaguar/VirtualJaguar.IDebuggable.cs
index e7ab377025c..fc0aa1ff5d2 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Atari/jaguar/VirtualJaguar.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/jaguar/VirtualJaguar.IDebuggable.cs
@@ -79,9 +79,6 @@ public void SetCpuRegister(string register, int value)
}
}
- public bool CanStep(StepType type)
- => false;
-
[FeatureNotImplemented]
public void Step(StepType type)
=> throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IDebuggable.cs
index 9913fad561a..4232f43fca4 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IDebuggable.cs
@@ -12,8 +12,6 @@ public partial class ColecoVision : IDebuggable
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IDebuggable.cs
index 1e66f2539a8..9bb37860821 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IDebuggable.cs
@@ -14,8 +14,6 @@ public void SetCpuRegister(string register, int value)
public IMemoryCallbackSystem MemoryCallbacks { get; }
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/GCE/Vectrex/VectrexHawk.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/GCE/Vectrex/VectrexHawk.IDebuggable.cs
index f3a3b273021..28050bdd97f 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/GCE/Vectrex/VectrexHawk.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/GCE/Vectrex/VectrexHawk.IDebuggable.cs
@@ -14,8 +14,6 @@ public void SetCpuRegister(string register, int value)
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IDebuggable.cs
index eb3b68a1d49..8f23cde541f 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IDebuggable.cs
@@ -15,8 +15,6 @@ public void SetCpuRegister(string register, int value)
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IDebuggable.cs
index ab564bf940f..f0410334ff5 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IDebuggable.cs
@@ -14,8 +14,6 @@ public void SetCpuRegister(string register, int value)
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Ares64/Ares64.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Ares64/Ares64.IDebuggable.cs
index 028037eb2a0..cdbf758ddb2 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Ares64/Ares64.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Ares64/Ares64.IDebuggable.cs
@@ -49,8 +49,6 @@ public IDictionary GetCpuFlagsAndRegisters()
[FeatureNotImplemented]
public IMemoryCallbackSystem MemoryCallbacks => throw new NotImplementedException();
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public long TotalExecutedCycles => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.IDebuggable.cs
index f6da1336b16..9564a46e1c3 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.IDebuggable.cs
@@ -52,8 +52,6 @@ public void SetCpuRegister(string register, int value)
public IMemoryCallbackSystem MemoryCallbacks { get; }
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IDebuggable.cs
index f3d71a4c0e1..f42513474cb 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IDebuggable.cs
@@ -14,8 +14,6 @@ public void SetCpuRegister(string register, int value)
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IDebuggable.cs
index 7a906844801..615b5bf3748 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IDebuggable.cs
@@ -32,8 +32,6 @@ public void SetCpuRegister(string register, int value)
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.IDebuggable.cs
index 4807ec60b03..77013da690c 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.IDebuggable.cs
@@ -39,8 +39,6 @@ public void SetCpuRegister(string register, int value)
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.IDebuggable.cs
index 5b275e55f36..588b0137b6d 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.IDebuggable.cs
@@ -46,8 +46,6 @@ public void SetCpuRegister(string register, int value)
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IDebuggable.cs
index ae3fde7c99b..2b182a1ea8e 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IDebuggable.cs
@@ -51,8 +51,6 @@ public void SetCpuRegister(string register, int value)
}
}
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.IDebuggable.cs
index 183fa02e9e2..b057a4c9a66 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.IDebuggable.cs
@@ -43,8 +43,6 @@ public void SetCpuRegister(string register, int value)
_core.SetReg(ncpu == 9 ? 0 : 1, index, value);
}
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IDebuggable.cs
index d19298777b8..96ea0034bab 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IDebuggable.cs
@@ -10,8 +10,6 @@ public partial class NES : IDebuggable
public void SetCpuRegister(string register, int value) => cpu.SetCpuRegister(register, value);
- public bool CanStep(StepType type) => false;
-
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
[FeatureNotImplemented]
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.IDebuggable.cs
index c102a3b1145..9500ead74dd 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.IDebuggable.cs
@@ -27,8 +27,6 @@ public void SetCpuRegister(string register, int value)
throw new NotImplementedException();
}
- public bool CanStep(StepType type) { return false; }
-
[FeatureNotImplemented]
public void Step(StepType type) { throw new NotImplementedException(); }
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IDebuggable.cs
index 6f95426cd23..919dd3afa38 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IDebuggable.cs
@@ -51,11 +51,6 @@ public void SetCpuRegister(string register, int value)
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
- public bool CanStep(StepType type)
- {
- return false;
- }
-
[FeatureNotImplemented]
public void Step(StepType type)
{
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.IDebuggable.cs
index f242e717616..b92d0e52079 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.IDebuggable.cs
@@ -46,8 +46,6 @@ public void SetCpuRegister(string register, int value)
value);
}
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SubGBHawk/SubGBHawk.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SubGBHawk/SubGBHawk.cs
index f39d1d2b573..91cd982afaf 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SubGBHawk/SubGBHawk.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SubGBHawk/SubGBHawk.cs
@@ -73,8 +73,6 @@ public void SetCpuRegister(string register, int value)
public IMemoryCallbackSystem MemoryCallbacks => _GBCore.MemoryCallbacks;
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.IDebuggable.cs
index e2416cf9225..0f909039e56 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.IDebuggable.cs
@@ -14,8 +14,6 @@ public void SetCpuRegister(string register, int value)
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Sega/GGHawkLink/GGHawkLink.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Sega/GGHawkLink/GGHawkLink.IDebuggable.cs
index d6a2348f829..655ab4281cf 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Sega/GGHawkLink/GGHawkLink.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Sega/GGHawkLink/GGHawkLink.IDebuggable.cs
@@ -133,11 +133,6 @@ public void SetCpuRegister(string register, int value)
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
- public bool CanStep(StepType type)
- {
- return false;
- }
-
[FeatureNotImplemented]
public void Step(StepType type)
{
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IDebuggable.cs
index 9d8a340ad46..ee0197b5283 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IDebuggable.cs
@@ -10,8 +10,6 @@ public partial class SMS : IDebuggable
public void SetCpuRegister(string register, int value) => Cpu.SetCpuRegister(register, value);
- public bool CanStep(StepType type) => false;
-
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
[FeatureNotImplemented]
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IDebuggable.cs
index 9235960e4b6..d5e5242a5c9 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IDebuggable.cs
@@ -41,8 +41,6 @@ public void SetCpuRegister(string register, int value)
public IMemoryCallbackSystem MemoryCallbacks => _memoryCallbacks;
- public bool CanStep(StepType type) { return false; }
-
[FeatureNotImplemented]
public void Step(StepType type) { throw new NotImplementedException(); }
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.IDebuggable.cs
index 9fa74b08389..5ad9287b494 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.IDebuggable.cs
@@ -80,8 +80,6 @@ public void SetCpuRegister(string register, int value)
private readonly MemoryCallbackSystem _memoryCallbacks = new MemoryCallbackSystem(new[] { "System Bus" }); // Note: there is no system bus memory domain, but there's also no hard rule that the memory callback system domains have to correspond to actual domains in MemoryDomains, that could be good, or bad, but something to be careful about
public IMemoryCallbackSystem MemoryCallbacks => _memoryCallbacks;
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs b/src/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs
index 3bfb16f81e9..bd280b5e0f6 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs
@@ -123,8 +123,6 @@ public void SetCpuRegister(string register, int value)
throw new NotImplementedException();
}
- public bool CanStep(StepType type) => false;
-
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
diff --git a/src/MainSlnCommon.props b/src/MainSlnCommon.props
index 7883543fa46..c4915902f10 100644
--- a/src/MainSlnCommon.props
+++ b/src/MainSlnCommon.props
@@ -12,5 +12,6 @@
+