From d4b4c06f0c6abe4a8b63462886046d8d8e56d4b5 Mon Sep 17 00:00:00 2001 From: Hathor86 Date: Thu, 26 Nov 2015 23:05:29 +0100 Subject: [PATCH] Draft of API So, I create a new dll named BizHawk.Client.ApiHawk and moved few stuff to it. Also moved some stuff to BizHawk.Client.Common. Don't think it can be desiociated. I started comment Watch and rearrange code (put some #region etc... It compiles and it seems working :) --- .gitignore | 5 +- .../Attributes/ConfigPersistAttribute.cs | 15 + .../BizHawk.Client.ApiHawk.csproj | 77 + .../Interfaces}/IExternalToolForm.cs | 0 .../Interfaces}/IToolForm.cs | 111 +- .../Interfaces/IToolFormAutoConfig.cs | 15 + .../Properties/AssemblyInfo.cs | 36 + .../Resources/ApiClassDiagram.cd | 79 ++ .../BizHawk.Client.Common.csproj | 12 +- BizHawk.Client.Common/tools/Watch.cs | 1235 ----------------- .../tools/Watch/ByteWatch.cs | 243 ++++ .../tools/Watch/DisplayType.cs | 62 + .../tools/Watch/DwordWatch.cs | 253 ++++ .../tools/Watch/PreviousType.cs | 18 + .../tools/Watch/SeparatorWatch.cs | 91 ++ BizHawk.Client.Common/tools/Watch/Watch.cs | 548 ++++++++ .../tools/{ => Watch}/WatchList.cs | 1120 +++++++-------- .../tools/Watch/WatchSize.cs | 37 + .../tools/Watch/WordWatch.cs | 234 ++++ .../BizHawk.Client.EmuHawk.csproj | 10 +- BizHawk.Client.EmuHawk/tools/ToolManager.cs | 7 +- .../tools/Watch/RamSearch.cs | 2 +- .../tools/Watch/RamWatch.cs | 2 +- BizHawk.sln | 57 +- 24 files changed, 2396 insertions(+), 1873 deletions(-) create mode 100644 BizHawk.Client.ApiHawk/Attributes/ConfigPersistAttribute.cs create mode 100644 BizHawk.Client.ApiHawk/BizHawk.Client.ApiHawk.csproj rename {BizHawk.Client.EmuHawk/tools => BizHawk.Client.ApiHawk/Interfaces}/IExternalToolForm.cs (100%) rename {BizHawk.Client.EmuHawk/tools => BizHawk.Client.ApiHawk/Interfaces}/IToolForm.cs (84%) create mode 100644 BizHawk.Client.ApiHawk/Interfaces/IToolFormAutoConfig.cs create mode 100644 BizHawk.Client.ApiHawk/Properties/AssemblyInfo.cs create mode 100644 BizHawk.Client.ApiHawk/Resources/ApiClassDiagram.cd delete mode 100644 BizHawk.Client.Common/tools/Watch.cs create mode 100644 BizHawk.Client.Common/tools/Watch/ByteWatch.cs create mode 100644 BizHawk.Client.Common/tools/Watch/DisplayType.cs create mode 100644 BizHawk.Client.Common/tools/Watch/DwordWatch.cs create mode 100644 BizHawk.Client.Common/tools/Watch/PreviousType.cs create mode 100644 BizHawk.Client.Common/tools/Watch/SeparatorWatch.cs create mode 100644 BizHawk.Client.Common/tools/Watch/Watch.cs rename BizHawk.Client.Common/tools/{ => Watch}/WatchList.cs (95%) create mode 100644 BizHawk.Client.Common/tools/Watch/WatchSize.cs create mode 100644 BizHawk.Client.Common/tools/Watch/WordWatch.cs diff --git a/.gitignore b/.gitignore index ead275a6c1..eb1c604da1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ /BizHawk.Client.Common/bin /BizHawk.Client.Common/obj /BizHawk.Client.Common/Properties/svnrev.cs +/BizHawk.Client.ApiHawk/bin +/BizHawk.Client.ApiHawk/obj /BizHawk.Client.DBMan/obj /BizHawk.Client.DiscoHawk/obj /BizHawk.Client.DiscoHawk/Properties/svnrev.cs @@ -247,7 +249,7 @@ /References/*.xml /output/ELFSharp.dll /output/dll/ELFSharp.dll -/output/ExternalTools/*.* +/output/ExternalTools *.opensdf *.user *.suo @@ -263,3 +265,4 @@ /LuaInterface/Lua/src/.libs /LuaInterface/Lua/src/Release-LUAPERKS /LuaInterface/Release-LUAPERKS +output/BizHawk.Client.ApiHawk.dll diff --git a/BizHawk.Client.ApiHawk/Attributes/ConfigPersistAttribute.cs b/BizHawk.Client.ApiHawk/Attributes/ConfigPersistAttribute.cs new file mode 100644 index 0000000000..ed1fbb1148 --- /dev/null +++ b/BizHawk.Client.ApiHawk/Attributes/ConfigPersistAttribute.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BizHawk.Client.EmuHawk +{ + /// + /// Define if the property has to be persisted in config + /// + [AttributeUsage(AttributeTargets.Property)] + public class ConfigPersistAttribute : Attribute + { + } +} diff --git a/BizHawk.Client.ApiHawk/BizHawk.Client.ApiHawk.csproj b/BizHawk.Client.ApiHawk/BizHawk.Client.ApiHawk.csproj new file mode 100644 index 0000000000..040a7ad46f --- /dev/null +++ b/BizHawk.Client.ApiHawk/BizHawk.Client.ApiHawk.csproj @@ -0,0 +1,77 @@ + + + + + Debug + AnyCPU + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA} + Library + Properties + BizHawk.Client.ApiHawk + BizHawk.Client.ApiHawk + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + {24a0aa3c-b25f-4197-b23d-476d6462dba0} + BizHawk.Client.Common + + + {866f8d13-0678-4ff9-80a4-a3993fd4d8a3} + BizHawk.Common + + + {e1a23168-b571-411c-b360-2229e7225e0e} + BizHawk.Emulation.Common + + + + + + + + + + + \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/tools/IExternalToolForm.cs b/BizHawk.Client.ApiHawk/Interfaces/IExternalToolForm.cs similarity index 100% rename from BizHawk.Client.EmuHawk/tools/IExternalToolForm.cs rename to BizHawk.Client.ApiHawk/Interfaces/IExternalToolForm.cs diff --git a/BizHawk.Client.EmuHawk/tools/IToolForm.cs b/BizHawk.Client.ApiHawk/Interfaces/IToolForm.cs similarity index 84% rename from BizHawk.Client.EmuHawk/tools/IToolForm.cs rename to BizHawk.Client.ApiHawk/Interfaces/IToolForm.cs index e743ca98df..02ca163b93 100644 --- a/BizHawk.Client.EmuHawk/tools/IToolForm.cs +++ b/BizHawk.Client.ApiHawk/Interfaces/IToolForm.cs @@ -1,61 +1,50 @@ -using System; -using System.Linq; -using System.Collections.Generic; - -namespace BizHawk.Client.EmuHawk -{ - public interface IToolForm - { - /// - /// Will be called by the client anytime an Update needs to occur, such as after an emulated frame, a loadstate, or a related dialog has made a relevant change - /// - void UpdateValues(); - - /// - /// Will be called by the client when performance is critical, - /// The tool should only do the minimum to still function, - /// Drawing should not occur if possible, during a fast update - /// - void FastUpdate(); - - /// - /// Will be called anytime the dialog needs to be restarted, such as when a new ROM is loaded - /// The tool implementing this needs to account for a Game and Core change - /// - void Restart(); - - /// - /// This gives the opportunity for the tool dialog to ask the user to save changes (such is necessary when - /// This tool dialog edits a file. Returning false will tell the client the user wants to cancel the given action, - /// Return false to tell the client to back out of an action (such as closing the emulator) - /// - /// - bool AskSaveChanges(); - - /// - /// Indicates whether the tool should be updated before a frame loop or after. - /// In general, tools that draw graphics from the core should update before the loop, - /// Information tools such as those that display core ram values should be after. - /// - bool UpdateBefore { get; } - - //Necessary winform calls - bool Focus(); - void Show(); - void Close(); - bool IsDisposed { get; } - bool IsHandleCreated { get; } - } - - /// - /// toolform that takes automatic common configuration infrastructure - /// - public interface IToolFormAutoConfig : IToolForm - { - } - - [AttributeUsage(AttributeTargets.Property)] - public class ConfigPersistAttribute : Attribute - { - } -} +using System; +using System.Linq; +using System.Collections.Generic; + +namespace BizHawk.Client.EmuHawk +{ + public interface IToolForm + { + /// + /// Will be called by the client anytime an Update needs to occur, such as after an emulated frame, a loadstate, or a related dialog has made a relevant change + /// + void UpdateValues(); + + /// + /// Will be called by the client when performance is critical, + /// The tool should only do the minimum to still function, + /// Drawing should not occur if possible, during a fast update + /// + void FastUpdate(); + + /// + /// Will be called anytime the dialog needs to be restarted, such as when a new ROM is loaded + /// The tool implementing this needs to account for a Game and Core change + /// + void Restart(); + + /// + /// This gives the opportunity for the tool dialog to ask the user to save changes (such is necessary when + /// This tool dialog edits a file. Returning false will tell the client the user wants to cancel the given action, + /// Return false to tell the client to back out of an action (such as closing the emulator) + /// + /// + bool AskSaveChanges(); + + /// + /// Indicates whether the tool should be updated before a frame loop or after. + /// In general, tools that draw graphics from the core should update before the loop, + /// Information tools such as those that display core ram values should be after. + /// + bool UpdateBefore { get; } + + //Necessary winform calls + bool Focus(); + void Show(); + void Close(); + bool IsDisposed { get; } + bool IsHandleCreated { get; } + } +} + diff --git a/BizHawk.Client.ApiHawk/Interfaces/IToolFormAutoConfig.cs b/BizHawk.Client.ApiHawk/Interfaces/IToolFormAutoConfig.cs new file mode 100644 index 0000000000..5def3b37be --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/IToolFormAutoConfig.cs @@ -0,0 +1,15 @@ +using BizHawk.Client.EmuHawk; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BizHawk.Client.EmuHawk +{ + /// + /// toolform that takes automatic common configuration infrastructure + /// + public interface IToolFormAutoConfig : IToolForm + { + } +} diff --git a/BizHawk.Client.ApiHawk/Properties/AssemblyInfo.cs b/BizHawk.Client.ApiHawk/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..66ceacbb35 --- /dev/null +++ b/BizHawk.Client.ApiHawk/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("BizHawk.Client.ApiHawk")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BizHawk.Client.ApiHawk")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8e2f11f2-3955-4382-8c3a-ceba1276caea")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/BizHawk.Client.ApiHawk/Resources/ApiClassDiagram.cd b/BizHawk.Client.ApiHawk/Resources/ApiClassDiagram.cd new file mode 100644 index 0000000000..721fa5defc --- /dev/null +++ b/BizHawk.Client.ApiHawk/Resources/ApiClassDiagram.cd @@ -0,0 +1,79 @@ + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Attributes\ConfigPersistAttribute.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Interfaces\IExternalToolForm.cs + + + + + + ECAAAAAAAABACAAgAAEAABAAAAAEAAAAAAAAAACAQAA= + Interfaces\IToolForm.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Interfaces\IToolFormAutoConfig.cs + + + + \ No newline at end of file diff --git a/BizHawk.Client.Common/BizHawk.Client.Common.csproj b/BizHawk.Client.Common/BizHawk.Client.Common.csproj index c35c7ad9d1..c4dc2d0063 100644 --- a/BizHawk.Client.Common/BizHawk.Client.Common.csproj +++ b/BizHawk.Client.Common/BizHawk.Client.Common.csproj @@ -232,9 +232,16 @@ + + + + - - + + + + + @@ -267,6 +274,7 @@ BizHawk.Bizware.BizwareGL + diff --git a/BizHawk.Client.Common/tools/Watch.cs b/BizHawk.Client.Common/tools/Watch.cs deleted file mode 100644 index 87786391d9..0000000000 --- a/BizHawk.Client.Common/tools/Watch.cs +++ /dev/null @@ -1,1235 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; - -using BizHawk.Common; -using BizHawk.Common.NumberExtensions; -using BizHawk.Common.StringExtensions; -using BizHawk.Emulation.Common; - -namespace BizHawk.Client.Common -{ - public abstract class Watch - { - public enum WatchSize { Byte = 1, Word = 2, DWord = 4, Separator = 0 } - public enum DisplayType { Separator, Signed, Unsigned, Hex, Binary, FixedPoint_12_4, FixedPoint_20_12, FixedPoint_16_16, Float } - public enum PreviousType { Original = 0, LastSearch = 1, LastFrame = 2, LastChange = 3 } - - public static Watch FromString(string line, IMemoryDomains domains) - { - try - { - var parts = line.Split(new[] { '\t' }, 6); - - if (parts.Length < 6) - { - if (parts.Length >= 3 && parts[2] == "_") - { - return SeparatorWatch.Instance; - } - - return null; - } - - var address = long.Parse(parts[0], NumberStyles.HexNumber); - var size = Watch.SizeFromChar(parts[1][0]); - var type = Watch.DisplayTypeFromChar(parts[2][0]); - var bigEndian = parts[3] == "0" ? false : true; - var domain = domains[parts[4]]; - var notes = parts[5].Trim(new[] { '\r', '\n' }); - - return Watch.GenerateWatch( - domain, - address, - size, - type, - notes, - bigEndian - ); - } - catch - { - return null; - } - } - - public static string ToString(Watch watch, MemoryDomain domain) - { - var numDigits = (domain.Size - 1).NumHexDigits(); - - var sb = new StringBuilder(); - - sb - .Append((watch.Address ?? 0).ToHexString(numDigits)).Append('\t') - .Append(watch.SizeAsChar).Append('\t') - .Append(watch.TypeAsChar).Append('\t') - .Append(watch.BigEndian ? '1' : '0').Append('\t') - .Append(watch.DomainName).Append('\t') - .Append(watch.Notes.Trim(new[] { '\r', '\n' })); - - return sb.ToString(); - } - - public static string DisplayTypeToString(DisplayType type) - { - switch (type) - { - default: - return type.ToString(); - case DisplayType.FixedPoint_12_4: - return "Fixed Point 12.4"; - case DisplayType.FixedPoint_20_12: - return "Fixed Point 20.12"; - case DisplayType.FixedPoint_16_16: - return "Fixed Point 16.16"; - } - } - - public static DisplayType StringToDisplayType(string name) - { - switch (name) - { - default: - return (DisplayType)Enum.Parse(typeof(DisplayType), name); - case "Fixed Point 12.4": - return DisplayType.FixedPoint_12_4; - case "Fixed Point 20.12": - return DisplayType.FixedPoint_20_12; - case "Fixed Point 16.16": - return DisplayType.FixedPoint_16_16; - } - } - - protected long _address; - protected MemoryDomain _domain; - protected DisplayType _type; - protected bool _bigEndian; - protected int _changecount; - protected string _notes = string.Empty; - - public abstract int? Value { get; } - public abstract string ValueString { get; } - public abstract WatchSize Size { get; } - - //zero 15-nov-2015 - bypass LIAR LOGIC, see fdc9ea2aa922876d20ba897fb76909bf75fa6c92 https://github.com/TASVideos/BizHawk/issues/326 - public abstract int? ValueNoFreeze { get; } - - public abstract uint MaxValue { get; } - - public abstract int? Previous { get; } - public abstract string PreviousStr { get; } - public abstract void ResetPrevious(); - - public abstract bool Poke(string value); - - public virtual DisplayType Type { get { return _type; } set { _type = value; } } - public virtual bool BigEndian { get { return _bigEndian; } set { _bigEndian = value; } } - - public MemoryDomain Domain { get { return _domain; } set { _domain = value; } } - - public string DomainName { get { return _domain != null ? _domain.Name : string.Empty; } } - - public virtual long? Address { get { return _address; } } - - public virtual string AddressString { get { return _address.ToString(AddressFormatStr); } } - - public virtual bool IsSeparator { get { return false; } } - - public char SizeAsChar - { - get - { - switch (Size) - { - default: - case WatchSize.Separator: - return 'S'; - case WatchSize.Byte: - return 'b'; - case WatchSize.Word: - return 'w'; - case WatchSize.DWord: - return 'd'; - } - } - } - - public static WatchSize SizeFromChar(char c) - { - switch (c) - { - default: - case 'S': - return WatchSize.Separator; - case 'b': - return WatchSize.Byte; - case 'w': - return WatchSize.Word; - case 'd': - return WatchSize.DWord; - } - } - - public char TypeAsChar - { - get - { - switch (Type) - { - default: - case DisplayType.Separator: - return '_'; - case DisplayType.Unsigned: - return 'u'; - case DisplayType.Signed: - return 's'; - case DisplayType.Hex: - return 'h'; - case DisplayType.Binary: - return 'b'; - case DisplayType.FixedPoint_12_4: - return '1'; - case DisplayType.FixedPoint_20_12: - return '2'; - case DisplayType.FixedPoint_16_16: - return '3'; - case DisplayType.Float: - return 'f'; - } - } - } - - public static DisplayType DisplayTypeFromChar(char c) - { - switch (c) - { - default: - case '_': - return DisplayType.Separator; - case 'u': - return DisplayType.Unsigned; - case 's': - return DisplayType.Signed; - case 'h': - return DisplayType.Hex; - case 'b': - return DisplayType.Binary; - case '1': - return DisplayType.FixedPoint_12_4; - case '2': - return DisplayType.FixedPoint_20_12; - case '3': - return DisplayType.FixedPoint_16_16; - case 'f': - return DisplayType.Float; - } - } - - public string AddressFormatStr - { - get - { - if (_domain != null) - { - return "X" + (_domain.Size - 1).NumHexDigits(); - } - - return string.Empty; - } - } - - protected byte GetByte(bool bypassFreeze = false) - { - if (!bypassFreeze && Global.CheatList.IsActive(_domain, _address)) - { - //LIAR logic - return Global.CheatList.GetByteValue(_domain, _address).Value; - } - else - { - if (_domain.Size == 0) - { - return _domain.PeekByte(_address); - } - else - { - return _domain.PeekByte(_address % _domain.Size); - } - } - } - - protected ushort GetWord(bool bypassFreeze = false) - { - if (!bypassFreeze && Global.CheatList.IsActive(_domain, _address)) - { - //LIAR logic - return (ushort)Global.CheatList.GetCheatValue(_domain, _address, WatchSize.Word).Value; - } - else - { - if (_domain.Size == 0) - { - return _domain.PeekWord(_address, _bigEndian); - } - else - { - return _domain.PeekWord(_address % _domain.Size, _bigEndian); // TODO: % size stil lisn't correct since it could be the last byte of the domain - } - } - } - - protected uint GetDWord(bool bypassFreeze = false) - { - if (!bypassFreeze && Global.CheatList.IsActive(_domain, _address)) - { - //LIAR logic - return (uint)Global.CheatList.GetCheatValue(_domain, _address, WatchSize.DWord).Value; - } - else - { - if (_domain.Size == 0) - { - return _domain.PeekDWord(_address, _bigEndian); // TODO: % size stil lisn't correct since it could be the last byte of the domain - } - else - { - return _domain.PeekDWord(_address % _domain.Size, _bigEndian); // TODO: % size stil lisn't correct since it could be the last byte of the domain - } - } - } - - protected void PokeByte(byte val) - { - if(_domain.Size == 0) - _domain.PokeByte(_address, val); - else _domain.PokeByte(_address % _domain.Size, val); - } - - protected void PokeWord(ushort val) - { - if (_domain.Size == 0) - _domain.PokeWord(_address, val, _bigEndian); // TODO: % size stil lisn't correct since it could be the last byte of the domain - else _domain.PokeWord(_address % _domain.Size, val, _bigEndian); // TODO: % size stil lisn't correct since it could be the last byte of the domain - } - - protected void PokeDWord(uint val) - { - if (_domain.Size == 0) - _domain.PokeDWord(_address, val, _bigEndian); // TODO: % size stil lisn't correct since it could be the last byte of the domain - else _domain.PokeDWord(_address % _domain.Size, val, _bigEndian); // TODO: % size stil lisn't correct since it could be the last byte of the domain - } - - public void ClearChangeCount() { _changecount = 0; } - - public bool IsOutOfRange - { - get - { - return !IsSeparator && (Domain.Size != 0 && Address.Value >= Domain.Size); - } - } - - public string Notes { get { return _notes; } set { _notes = value; } } - - public static Watch GenerateWatch(MemoryDomain domain, long address, WatchSize size, DisplayType type, string notes, bool bigEndian) - { - switch (size) - { - default: - case WatchSize.Separator: - return SeparatorWatch.Instance; - case WatchSize.Byte: - return new ByteWatch(domain, address, type, bigEndian, notes); - case WatchSize.Word: - return new WordWatch(domain, address, type, bigEndian, notes); - case WatchSize.DWord: - return new DWordWatch(domain, address, type, bigEndian, notes); - } - } - - public static Watch GenerateWatch(MemoryDomain domain, long address, WatchSize size, DisplayType type, bool bigendian, long prev, int changecount) - { - switch (size) - { - default: - case WatchSize.Separator: - return SeparatorWatch.Instance; - case WatchSize.Byte: - return new ByteWatch(domain, address, type, bigendian, (byte)prev, changecount); - case WatchSize.Word: - return new WordWatch(domain, address, type, bigendian, (ushort)prev, changecount); - case WatchSize.DWord: - return new DWordWatch(domain, address, type, bigendian, (uint)prev, changecount); - } - } - - public static List AvailableTypes(WatchSize size) - { - switch (size) - { - default: - case WatchSize.Separator: - return SeparatorWatch.ValidTypes; - case WatchSize.Byte: - return ByteWatch.ValidTypes; - case WatchSize.Word: - return WordWatch.ValidTypes; - case WatchSize.DWord: - return DWordWatch.ValidTypes; - } - } - - public int ChangeCount { get { return _changecount; } } - - public abstract string Diff { get; } - - public abstract void Update(); - - public override bool Equals(object obj) - { - if (obj is Watch) - { - var watch = obj as Watch; - - return this.Domain == watch.Domain && - this.Address == watch.Address && - this.Size == watch.Size && - this.Type == watch.Type && - this.Notes == watch.Notes; - } - - if (obj is Cheat) - { - var cheat = obj as Cheat; - return this.Domain == cheat.Domain && this.Address == cheat.Address; - } - - return base.Equals(obj); - } - - public override int GetHashCode() - { - return this.Domain.GetHashCode() + (int)(this.Address ?? 0); - } - - public static bool operator ==(Watch a, Watch b) - { - // If one is null, but not both, return false. - if (((object)a == null) || ((object)b == null)) - { - return false; - } - - return a.Equals(b); - } - - public static bool operator !=(Watch a, Watch b) - { - return !a.Equals(b); - } - - public static bool operator ==(Watch a, Cheat b) - { - // If one is null, but not both, return false. - if (((object)a == null) || ((object)b == null)) - { - return false; - } - - return a.Domain == b.Domain && a.Address == b.Address; - } - - public static bool operator !=(Watch a, Cheat b) - { - return !(a == b); - } - } - - public sealed class SeparatorWatch : Watch - { - public static SeparatorWatch Instance - { - get { return new SeparatorWatch(); } - } - - public override long? Address - { - get { return null; } - } - - public override int? Value - { - get { return null; } - } - - public override int? ValueNoFreeze - { - get { return null; } - } - - public override int? Previous - { - get { return null; } - } - - public override string AddressString - { - get { return string.Empty; } - } - - public override string ValueString - { - get { return string.Empty; } - } - - public override string PreviousStr - { - get { return string.Empty; } - } - - public override string ToString() - { - return "----"; - } - - public override bool IsSeparator - { - get { return true; } - } - - public override WatchSize Size - { - get { return WatchSize.Separator; } - } - - public static List ValidTypes - { - get { return new List { DisplayType.Separator }; } - } - - public override DisplayType Type - { - get { return DisplayType.Separator; } - } - - public override bool Poke(string value) - { - return false; - } - - public override void ResetPrevious() - { - return; - } - - public override string Diff { get { return string.Empty; } } - - public override uint MaxValue - { - get { return 0; } - } - - public override void Update() { return; } - } - - public sealed class ByteWatch : Watch - { - private byte _previous; - private byte _value; - - public ByteWatch(MemoryDomain domain, long address, DisplayType type, bool bigEndian, string notes) - { - _address = address; - _domain = domain; - _value = _previous = GetByte(); - if (AvailableTypes(WatchSize.Byte).Contains(type)) - { - _type = type; - } - - _bigEndian = bigEndian; - if (notes != null) - { - Notes = notes; - } - } - - public ByteWatch(MemoryDomain domain, long address, DisplayType type, bool bigEndian, byte prev, int changeCount, string notes = null) - : this(domain, address, type, bigEndian, notes) - { - _previous = prev; - _changecount = changeCount; - } - - public override long? Address - { - get { return _address; } - } - - public override int? Value - { - get { return GetByte(); } - } - - public override int? ValueNoFreeze - { - get { return GetByte(true); } - } - - public override string ValueString - { - get { return FormatValue(GetByte()); } - } - - public override int? Previous - { - get { return _previous; } - } - - public override string PreviousStr - { - get { return FormatValue(_previous); } - } - - public override void ResetPrevious() - { - _previous = GetByte(); - } - - public override string ToString() - { - return Notes + ": " + ValueString; - } - - public override bool IsSeparator - { - get { return false; } - } - - public override WatchSize Size - { - get { return WatchSize.Byte; } - } - - public static List ValidTypes - { - get - { - return new List - { - DisplayType.Unsigned, DisplayType.Signed, DisplayType.Hex, DisplayType.Binary - }; - } - } - - public override uint MaxValue - { - get { return byte.MaxValue; } - } - - public string FormatValue(byte val) - { - switch (Type) - { - default: - case DisplayType.Unsigned: - return val.ToString(); - case DisplayType.Signed: - return ((sbyte)val).ToString(); - case DisplayType.Hex: - return val.ToHexString(2); - case DisplayType.Binary: - return Convert.ToString(val, 2).PadLeft(8, '0').Insert(4, " "); - } - } - - public override bool Poke(string value) - { - try - { - byte val = 0; - switch (Type) - { - case DisplayType.Unsigned: - if ( value.IsUnsigned()) - { - val = (byte)int.Parse(value); - } - else - { - return false; - } - - break; - case DisplayType.Signed: - if (value.IsSigned()) - { - val = (byte)(sbyte)int.Parse(value); - } - else - { - return false; - } - - break; - case DisplayType.Hex: - if (value.IsHex()) - { - val = (byte)int.Parse(value, NumberStyles.HexNumber); - } - else - { - return false; - } - - break; - case DisplayType.Binary: - if (value.IsBinary()) - { - val = (byte)Convert.ToInt32(value, 2); - } - else - { - return false; - } - - break; - } - - if (Global.CheatList.Contains(Domain, _address)) - { - var cheat = Global.CheatList.FirstOrDefault(c => c.Address == _address && c.Domain == Domain); - - if (cheat != (Cheat)null) - { - cheat.PokeValue(val); - PokeByte(val); - return true; - } - } - - PokeByte(val); - return true; - } - catch - { - return false; - } - } - - public override string Diff - { - get - { - var diff = string.Empty; - var diffVal = _value - _previous; - if (diffVal > 0) - { - diff = "+"; - } - else if (diffVal < 0) - { - diff = "-"; - } - - return diff + FormatValue((byte)(_previous - _value)); - } - } - - public override void Update() - { - switch (Global.Config.RamWatchDefinePrevious) - { - case PreviousType.Original: - return; - case PreviousType.LastChange: - var temp = _value; - _value = GetByte(); - if (_value != temp) - { - _previous = _value; - _changecount++; - } - - break; - case PreviousType.LastFrame: - _previous = _value; - _value = GetByte(); - if (_value != Previous) - { - _changecount++; - } - - break; - } - } - } - - public sealed class WordWatch : Watch - { - private ushort _previous; - private ushort _value; - - public WordWatch(MemoryDomain domain, long address, DisplayType type, bool bigEndian, string notes) - { - _domain = domain; - _address = address; - _value = _previous = GetWord(); - - if (AvailableTypes(WatchSize.Word).Contains(type)) - { - _type = type; - } - - _bigEndian = bigEndian; - - if (notes != null) - { - Notes = notes; - } - } - - public WordWatch(MemoryDomain domain, long address, DisplayType type, bool bigEndian, ushort prev, int changeCount, string notes = null) - : this(domain, address, type, bigEndian, notes) - { - _previous = prev; - _changecount = changeCount; - } - - public override uint MaxValue - { - get { return ushort.MaxValue; } - } - - public override int? Value - { - get { return GetWord(); } - } - - public override int? ValueNoFreeze - { - get { return GetWord(true); } - } - - public override int? Previous - { - get { return _previous; } - } - - public override string PreviousStr - { - get { return FormatValue(_previous); } - } - - public override void ResetPrevious() - { - _previous = GetWord(); - } - - public override WatchSize Size - { - get { return WatchSize.Word; } - } - - public static List ValidTypes - { - get - { - return new List - { - DisplayType.Unsigned, DisplayType.Signed, DisplayType.Hex, DisplayType.FixedPoint_12_4, DisplayType.Binary - }; - } - } - - public override string ValueString - { - get { return FormatValue(GetWord()); } - } - - public override string ToString() - { - return Notes + ": " + ValueString; - } - - public string FormatValue(ushort val) - { - switch (Type) - { - default: - case DisplayType.Unsigned: - return val.ToString(); - case DisplayType.Signed: - return ((short)val).ToString(); - case DisplayType.Hex: - return val.ToHexString(4); - case DisplayType.FixedPoint_12_4: - return string.Format("{0:F4}", val / 16.0); - case DisplayType.Binary: - return Convert.ToString(val, 2).PadLeft(16, '0').Insert(8, " ").Insert(4, " ").Insert(14, " "); - } - } - - public override bool Poke(string value) - { - try - { - ushort val = 0; - switch (Type) - { - case DisplayType.Unsigned: - if (value.IsUnsigned()) - { - val = (ushort)int.Parse(value); - } - else - { - return false; - } - - break; - case DisplayType.Signed: - if (value.IsSigned()) - { - val = (ushort)(short)int.Parse(value); - } - else - { - return false; - } - - break; - case DisplayType.Hex: - if (value.IsHex()) - { - val = (ushort)int.Parse(value, NumberStyles.HexNumber); - } - else - { - return false; - } - - break; - case DisplayType.Binary: - if (value.IsBinary()) - { - val = (ushort)Convert.ToInt32(value, 2); - } - else - { - return false; - } - - break; - case DisplayType.FixedPoint_12_4: - if (value.IsFixedPoint()) - { - val = (ushort)(double.Parse(value) * 16.0); - } - else - { - return false; - } - - break; - } - - if (Global.CheatList.Contains(Domain, _address)) - { - var cheat = Global.CheatList.FirstOrDefault(c => c.Address == _address && c.Domain == Domain); - if (cheat != (Cheat)null) - { - cheat.PokeValue(val); - PokeWord(val); - return true; - } - } - - PokeWord(val); - return true; - } - catch - { - return false; - } - } - - public override string Diff - { - get { return FormatValue((ushort)(_previous - _value)); } - } - - public override void Update() - { - switch (Global.Config.RamWatchDefinePrevious) - { - case PreviousType.Original: - return; - case PreviousType.LastChange: - var temp = _value; - _value = GetWord(); - - if (_value != temp) - { - _previous = temp; - _changecount++; - } - - break; - case PreviousType.LastFrame: - _previous = _value; - _value = GetWord(); - if (_value != Previous) - { - _changecount++; - } - - break; - } - } - } - - public sealed class DWordWatch : Watch - { - private uint _value; - private uint _previous; - - public DWordWatch(MemoryDomain domain, long address, DisplayType type, bool bigEndian, string notes) - { - _domain = domain; - _address = address; - _value = _previous = GetDWord(); - - if (AvailableTypes(WatchSize.DWord).Contains(type)) - { - _type = type; - } - - _bigEndian = bigEndian; - - if (notes != null) - { - Notes = notes; - } - } - - public DWordWatch(MemoryDomain domain, long address, DisplayType type, bool bigEndian, uint prev, int changeCount, string notes = null) - : this(domain, address, type, bigEndian, notes) - { - _previous = prev; - _changecount = changeCount; - _type = type; - _bigEndian = bigEndian; - } - - public override int? Value - { - get { return (int)GetDWord(); } - } - - public override int? ValueNoFreeze - { - get { return (int)GetDWord(true); } - } - - public override int? Previous - { - get { return (int)_previous; } - } - - public override string PreviousStr - { - get { return FormatValue(_previous); } - } - - public override void ResetPrevious() - { - _previous = GetWord(); - } - - public override WatchSize Size - { - get { return WatchSize.DWord; } - } - - public static List ValidTypes - { - get - { - return new List - { - DisplayType.Unsigned, DisplayType.Signed, DisplayType.Hex, DisplayType.FixedPoint_20_12, DisplayType.FixedPoint_16_16, DisplayType.Float - }; - } - } - - public override uint MaxValue - { - get { return uint.MaxValue; } - } - - public override string ValueString - { - get { return FormatValue(GetDWord()); } - } - - public override string ToString() - { - return Notes + ": " + ValueString; - } - - public string FormatValue(uint val) - { - switch (Type) - { - default: - case DisplayType.Unsigned: - return val.ToString(); - case DisplayType.Signed: - return ((int)val).ToString(); - case DisplayType.Hex: - return val.ToHexString(8); - case DisplayType.FixedPoint_20_12: - return string.Format("{0:0.######}", val / 4096.0); - case DisplayType.FixedPoint_16_16: - return string.Format("{0:0.######}", val / 65536.0); - case DisplayType.Float: - var bytes = BitConverter.GetBytes(val); - var _float = BitConverter.ToSingle(bytes, 0); - //return string.Format("{0:0.######}", _float); - return _float.ToString(); // adelikat: decided that we like sci notation instead of spooky rounding - } - } - - public override bool Poke(string value) - { - try - { - uint val = 0; - switch (Type) - { - case DisplayType.Unsigned: - if (value.IsUnsigned()) - { - val = (uint)int.Parse(value); - } - else - { - return false; - } - - break; - case DisplayType.Signed: - if (value.IsSigned()) - { - val = (uint)int.Parse(value); - } - else - { - return false; - } - - break; - case DisplayType.Hex: - if (value.IsHex()) - { - val = (uint)int.Parse(value, NumberStyles.HexNumber); - } - else - { - return false; - } - - break; - case DisplayType.FixedPoint_20_12: - if (value.IsFixedPoint()) - { - val = (uint)(int)(double.Parse(value) * 4096.0); - } - else - { - return false; - } - - break; - case DisplayType.FixedPoint_16_16: - if (value.IsFixedPoint()) - { - val = (uint)(int)(double.Parse(value) * 65536.0); - } - else - { - return false; - } - - break; - case DisplayType.Float: - if (value.IsFloat()) - { - var bytes = BitConverter.GetBytes(float.Parse(value)); - val = BitConverter.ToUInt32(bytes, 0); - } - else - { - return false; - } - - break; - } - - if (Global.CheatList.Contains(Domain, _address)) - { - var cheat = Global.CheatList.FirstOrDefault(c => c.Address == _address && c.Domain == Domain); - if (cheat != (Cheat)null) - { - cheat.PokeValue((int)val); - PokeDWord(val); - return true; - } - } - - PokeDWord(val); - return true; - } - catch - { - return false; - } - } - - public override string Diff - { - get { return FormatValue(_previous - _value); } - } - - public override void Update() - { - switch (Global.Config.RamWatchDefinePrevious) - { - case PreviousType.Original: - return; - case PreviousType.LastChange: - var temp = _value; - _value = GetDWord(); - if (_value != temp) - { - _previous = _value; - _changecount++; - } - - break; - case PreviousType.LastFrame: - _previous = _value; - _value = GetDWord(); - if (_value != Previous) - { - _changecount++; - } - - break; - } - } - } -} diff --git a/BizHawk.Client.Common/tools/Watch/ByteWatch.cs b/BizHawk.Client.Common/tools/Watch/ByteWatch.cs new file mode 100644 index 0000000000..9bfe89a6e4 --- /dev/null +++ b/BizHawk.Client.Common/tools/Watch/ByteWatch.cs @@ -0,0 +1,243 @@ +using BizHawk.Common.NumberExtensions; +using BizHawk.Common.StringExtensions; +using BizHawk.Emulation.Common; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; + +namespace BizHawk.Client.Common +{ + public sealed class ByteWatch : Watch + { + private byte _previous; + private byte _value; + + public ByteWatch(MemoryDomain domain, long address, DisplayType type, bool bigEndian, string notes) + { + _address = address; + _domain = domain; + _value = _previous = GetByte(); + if (AvailableTypes(WatchSize.Byte).Contains(type)) + { + _type = type; + } + + _bigEndian = bigEndian; + if (notes != null) + { + Notes = notes; + } + } + + public ByteWatch(MemoryDomain domain, long address, DisplayType type, bool bigEndian, byte prev, int changeCount, string notes = null) + : this(domain, address, type, bigEndian, notes) + { + _previous = prev; + _changecount = changeCount; + } + + public override long? Address + { + get { return _address; } + } + + public override int? Value + { + get { return GetByte(); } + } + + public override int? ValueNoFreeze + { + get { return GetByte(true); } + } + + public override string ValueString + { + get { return FormatValue(GetByte()); } + } + + public override int? Previous + { + get { return _previous; } + } + + public override string PreviousStr + { + get { return FormatValue(_previous); } + } + + public override void ResetPrevious() + { + _previous = GetByte(); + } + + public override string ToString() + { + return Notes + ": " + ValueString; + } + + public override bool IsSeparator + { + get { return false; } + } + + public override WatchSize Size + { + get { return WatchSize.Byte; } + } + + public static List ValidTypes + { + get + { + return new List + { + DisplayType.Unsigned, DisplayType.Signed, DisplayType.Hex, DisplayType.Binary + }; + } + } + + public override uint MaxValue + { + get { return byte.MaxValue; } + } + + public string FormatValue(byte val) + { + switch (Type) + { + default: + case DisplayType.Unsigned: + return val.ToString(); + case DisplayType.Signed: + return ((sbyte)val).ToString(); + case DisplayType.Hex: + return val.ToHexString(2); + case DisplayType.Binary: + return Convert.ToString(val, 2).PadLeft(8, '0').Insert(4, " "); + } + } + + public override bool Poke(string value) + { + try + { + byte val = 0; + switch (Type) + { + case DisplayType.Unsigned: + if (value.IsUnsigned()) + { + val = (byte)int.Parse(value); + } + else + { + return false; + } + + break; + case DisplayType.Signed: + if (value.IsSigned()) + { + val = (byte)(sbyte)int.Parse(value); + } + else + { + return false; + } + + break; + case DisplayType.Hex: + if (value.IsHex()) + { + val = (byte)int.Parse(value, NumberStyles.HexNumber); + } + else + { + return false; + } + + break; + case DisplayType.Binary: + if (value.IsBinary()) + { + val = (byte)Convert.ToInt32(value, 2); + } + else + { + return false; + } + + break; + } + + if (Global.CheatList.Contains(Domain, _address)) + { + var cheat = Global.CheatList.FirstOrDefault(c => c.Address == _address && c.Domain == Domain); + + if (cheat != (Cheat)null) + { + cheat.PokeValue(val); + PokeByte(val); + return true; + } + } + + PokeByte(val); + return true; + } + catch + { + return false; + } + } + + public override string Diff + { + get + { + var diff = string.Empty; + var diffVal = _value - _previous; + if (diffVal > 0) + { + diff = "+"; + } + else if (diffVal < 0) + { + diff = "-"; + } + + return diff + FormatValue((byte)(_previous - _value)); + } + } + + public override void Update() + { + switch (Global.Config.RamWatchDefinePrevious) + { + case PreviousType.Original: + return; + case PreviousType.LastChange: + var temp = _value; + _value = GetByte(); + if (_value != temp) + { + _previous = _value; + _changecount++; + } + + break; + case PreviousType.LastFrame: + _previous = _value; + _value = GetByte(); + if (_value != Previous) + { + _changecount++; + } + + break; + } + } + } +} diff --git a/BizHawk.Client.Common/tools/Watch/DisplayType.cs b/BizHawk.Client.Common/tools/Watch/DisplayType.cs new file mode 100644 index 0000000000..16f9835364 --- /dev/null +++ b/BizHawk.Client.Common/tools/Watch/DisplayType.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BizHawk.Client.Common +{ + public abstract partial class Watch + { + /// + /// This enum is used to specify how you want your to be displayed + /// + public enum DisplayType + { + /// + /// Separator, only used by + /// + Separator, + /// + /// Display the value as a signed integer + /// Used by , and + /// + Signed, + /// + /// Display the value as an unsigned integer + /// Used by , and + /// + Unsigned, + /// + /// Raw hexadecimal display + /// Used by , and + /// + Hex, + /// + /// Raw binary display + /// Used by , and + /// If you can read it easily, you're probably a computer + /// + Binary, + /// + /// Display the value as fractionnal number. 12 before coma and 4 after + /// Used only by as it is 16 bits length + /// + FixedPoint_12_4, + /// + /// Display the value as fractionnal number. 20 before coma and 12 after + /// Used only by as it is 32 bits length + /// + FixedPoint_20_12, + /// + /// Display the value as fractionnal number. 16 before coma and 16 after + /// Used only by as it is 32 bits length + /// + FixedPoint_16_16, + /// + /// The traditionnal float type as in C++ + /// Used only by as it is 32 bits length + /// + Float + } + } +} diff --git a/BizHawk.Client.Common/tools/Watch/DwordWatch.cs b/BizHawk.Client.Common/tools/Watch/DwordWatch.cs new file mode 100644 index 0000000000..e0a2c2f717 --- /dev/null +++ b/BizHawk.Client.Common/tools/Watch/DwordWatch.cs @@ -0,0 +1,253 @@ +using BizHawk.Common.NumberExtensions; +using BizHawk.Common.StringExtensions; +using BizHawk.Emulation.Common; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace BizHawk.Client.Common +{ + public sealed class DWordWatch : Watch + { + private uint _value; + private uint _previous; + + public DWordWatch(MemoryDomain domain, long address, DisplayType type, bool bigEndian, string notes) + { + _domain = domain; + _address = address; + _value = _previous = GetDWord(); + + if (AvailableTypes(WatchSize.DWord).Contains(type)) + { + _type = type; + } + + _bigEndian = bigEndian; + + if (notes != null) + { + Notes = notes; + } + } + + public DWordWatch(MemoryDomain domain, long address, DisplayType type, bool bigEndian, uint prev, int changeCount, string notes = null) + : this(domain, address, type, bigEndian, notes) + { + _previous = prev; + _changecount = changeCount; + _type = type; + _bigEndian = bigEndian; + } + + public override int? Value + { + get { return (int)GetDWord(); } + } + + public override int? ValueNoFreeze + { + get { return (int)GetDWord(true); } + } + + public override int? Previous + { + get { return (int)_previous; } + } + + public override string PreviousStr + { + get { return FormatValue(_previous); } + } + + public override void ResetPrevious() + { + _previous = GetWord(); + } + + public override WatchSize Size + { + get { return WatchSize.DWord; } + } + + public static List ValidTypes + { + get + { + return new List + { + DisplayType.Unsigned, DisplayType.Signed, DisplayType.Hex, DisplayType.FixedPoint_20_12, DisplayType.FixedPoint_16_16, DisplayType.Float + }; + } + } + + public override uint MaxValue + { + get { return uint.MaxValue; } + } + + public override string ValueString + { + get { return FormatValue(GetDWord()); } + } + + public override string ToString() + { + return Notes + ": " + ValueString; + } + + public string FormatValue(uint val) + { + switch (Type) + { + default: + case DisplayType.Unsigned: + return val.ToString(); + case DisplayType.Signed: + return ((int)val).ToString(); + case DisplayType.Hex: + return val.ToHexString(8); + case DisplayType.FixedPoint_20_12: + return string.Format("{0:0.######}", val / 4096.0); + case DisplayType.FixedPoint_16_16: + return string.Format("{0:0.######}", val / 65536.0); + case DisplayType.Float: + var bytes = BitConverter.GetBytes(val); + var _float = BitConverter.ToSingle(bytes, 0); + //return string.Format("{0:0.######}", _float); + return _float.ToString(); // adelikat: decided that we like sci notation instead of spooky rounding + } + } + + public override bool Poke(string value) + { + try + { + uint val = 0; + switch (Type) + { + case DisplayType.Unsigned: + if (value.IsUnsigned()) + { + val = (uint)int.Parse(value); + } + else + { + return false; + } + + break; + case DisplayType.Signed: + if (value.IsSigned()) + { + val = (uint)int.Parse(value); + } + else + { + return false; + } + + break; + case DisplayType.Hex: + if (value.IsHex()) + { + val = (uint)int.Parse(value, NumberStyles.HexNumber); + } + else + { + return false; + } + + break; + case DisplayType.FixedPoint_20_12: + if (value.IsFixedPoint()) + { + val = (uint)(int)(double.Parse(value) * 4096.0); + } + else + { + return false; + } + + break; + case DisplayType.FixedPoint_16_16: + if (value.IsFixedPoint()) + { + val = (uint)(int)(double.Parse(value) * 65536.0); + } + else + { + return false; + } + + break; + case DisplayType.Float: + if (value.IsFloat()) + { + var bytes = BitConverter.GetBytes(float.Parse(value)); + val = BitConverter.ToUInt32(bytes, 0); + } + else + { + return false; + } + + break; + } + + if (Global.CheatList.Contains(Domain, _address)) + { + var cheat = Global.CheatList.FirstOrDefault(c => c.Address == _address && c.Domain == Domain); + if (cheat != (Cheat)null) + { + cheat.PokeValue((int)val); + PokeDWord(val); + return true; + } + } + + PokeDWord(val); + return true; + } + catch + { + return false; + } + } + + public override string Diff + { + get { return FormatValue(_previous - _value); } + } + + public override void Update() + { + switch (Global.Config.RamWatchDefinePrevious) + { + case PreviousType.Original: + return; + case PreviousType.LastChange: + var temp = _value; + _value = GetDWord(); + if (_value != temp) + { + _previous = _value; + _changecount++; + } + + break; + case PreviousType.LastFrame: + _previous = _value; + _value = GetDWord(); + if (_value != Previous) + { + _changecount++; + } + + break; + } + } + } +} diff --git a/BizHawk.Client.Common/tools/Watch/PreviousType.cs b/BizHawk.Client.Common/tools/Watch/PreviousType.cs new file mode 100644 index 0000000000..05e38ca406 --- /dev/null +++ b/BizHawk.Client.Common/tools/Watch/PreviousType.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BizHawk.Client.Common +{ + public abstract partial class Watch + { + public enum PreviousType + { + Original = 0, + LastSearch = 1, + LastFrame = 2, + LastChange = 3 + } + } +} diff --git a/BizHawk.Client.Common/tools/Watch/SeparatorWatch.cs b/BizHawk.Client.Common/tools/Watch/SeparatorWatch.cs new file mode 100644 index 0000000000..7b6d0d5cc8 --- /dev/null +++ b/BizHawk.Client.Common/tools/Watch/SeparatorWatch.cs @@ -0,0 +1,91 @@ +using System.Collections.Generic; + +namespace BizHawk.Client.Common +{ + public sealed class SeparatorWatch : Watch + { + public static SeparatorWatch Instance + { + get { return new SeparatorWatch(); } + } + + public override long? Address + { + get { return null; } + } + + public override int? Value + { + get { return null; } + } + + public override int? ValueNoFreeze + { + get { return null; } + } + + public override int? Previous + { + get { return null; } + } + + public override string AddressString + { + get { return string.Empty; } + } + + public override string ValueString + { + get { return string.Empty; } + } + + public override string PreviousStr + { + get { return string.Empty; } + } + + public override string ToString() + { + return "----"; + } + + public override bool IsSeparator + { + get { return true; } + } + + public override WatchSize Size + { + get { return WatchSize.Separator; } + } + + public static List ValidTypes + { + get { return new List { DisplayType.Separator }; } + } + + public override DisplayType Type + { + get { return DisplayType.Separator; } + } + + public override bool Poke(string value) + { + return false; + } + + public override void ResetPrevious() + { + return; + } + + public override string Diff { get { return string.Empty; } } + + public override uint MaxValue + { + get { return 0; } + } + + public override void Update() { return; } + } +} diff --git a/BizHawk.Client.Common/tools/Watch/Watch.cs b/BizHawk.Client.Common/tools/Watch/Watch.cs new file mode 100644 index 0000000000..005f8d8b76 --- /dev/null +++ b/BizHawk.Client.Common/tools/Watch/Watch.cs @@ -0,0 +1,548 @@ +using BizHawk.Common.NumberExtensions; +using BizHawk.Emulation.Common; + +using System; +using System.Collections.Generic; +using System.Globalization; + +namespace BizHawk.Client.Common +{ + public abstract partial class Watch + { + #region Fields + + protected long _address; + protected MemoryDomain _domain; + protected DisplayType _type; + protected bool _bigEndian; + protected int _changecount; + protected string _notes = string.Empty; + + #endregion + + #region Methods + + #region Static + + /// + /// Generate a from a given string + /// String is tab separate + /// + /// Entire string, tab seperated for each value Order is: + /// + /// + /// 0x00 + /// Address in hexadecimal + /// + /// + /// b,w or d + /// The , byte, word or double word + /// s, u, h, b, 1, 2, 3, f + /// The signed, unsigned,etc... + /// + /// + /// 0 or 1 + /// Big endian or not + /// + /// + /// RDRAM,ROM,... + /// The + /// + /// + /// Plain text + /// Notes + /// + /// + /// + /// 's memory domain + /// + public static Watch FromString(string line, IMemoryDomains domains) + { + string[] parts = line.Split(new char[] { '\t' }, 6); + + if (parts.Length < 6) + { + if (parts.Length >= 3 && parts[2] == "_") + { + return SeparatorWatch.Instance; + } + + return null; + } + long address; + + if (long.TryParse(parts[0], NumberStyles.HexNumber, CultureInfo.CurrentCulture, out address)) + { + WatchSize size = Watch.SizeFromChar(parts[1][0]); + DisplayType type = Watch.DisplayTypeFromChar(parts[2][0]); + bool bigEndian = parts[3] == "0" ? false : true; + MemoryDomain domain = domains[parts[4]]; + string notes = parts[5].Trim(new char[] { '\r', '\n' }); + + return Watch.GenerateWatch( + domain, + address, + size, + type, + notes, + bigEndian + ); + } + else + { + return null; + } + } + + #endregion Static + + /// + /// Transform the current instance into a string + /// + /// A representation of the current + public override string ToString() + { + return string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}" + , (Address ?? 0).ToHexString((Domain.Size - 1).NumHexDigits()) + , SizeAsChar + , TypeAsChar + , BigEndian + , DomainName + , Notes.Trim('\r', '\n') + ); + } + + #endregion + + #region Properties + + #region Abstracts + + public abstract uint MaxValue { get; } + public abstract int? Value { get; } + //zero 15-nov-2015 - bypass LIAR LOGIC, see fdc9ea2aa922876d20ba897fb76909bf75fa6c92 https://github.com/TASVideos/BizHawk/issues/326 + public abstract int? ValueNoFreeze { get; } + public abstract string ValueString { get; } + public abstract WatchSize Size { get; } + public abstract bool Poke(string value); + public abstract int? Previous { get; } + public abstract string PreviousStr { get; } + public abstract void ResetPrevious(); + + #endregion Abstracts + + #region Virtual + + /// + /// Gets the address in the + /// + public virtual long? Address + { + get + { + return _address; + } + } + + /// + /// Gets or sets the endianess of current + /// True for big endian, flase for little endian + /// + public virtual bool BigEndian + { + get + { + return _bigEndian; + } + set + { + _bigEndian = value; + } + } + + /// + /// Gets or set the way current is displayed + /// + public virtual DisplayType Type + { + get + { + return _type; + } + set + { + _type = value; + } + } + + /// + /// Gets the address in the formatted as string + /// + public virtual string AddressString + { + get + { + return _address.ToString(AddressFormatStr); + } + } + + /// + /// Gets a value that defined if the current is actually a + /// + public virtual bool IsSeparator + { + get + { + return false; + } + } + + #endregion Virtual + + + public MemoryDomain Domain { get { return _domain; } set { _domain = value; } } + + public string DomainName { get { return _domain != null ? _domain.Name : string.Empty; } } + + #endregion + + public static string DisplayTypeToString(DisplayType type) + { + switch (type) + { + default: + return type.ToString(); + case DisplayType.FixedPoint_12_4: + return "Fixed Point 12.4"; + case DisplayType.FixedPoint_20_12: + return "Fixed Point 20.12"; + case DisplayType.FixedPoint_16_16: + return "Fixed Point 16.16"; + } + } + + public static DisplayType StringToDisplayType(string name) + { + switch (name) + { + default: + return (DisplayType)Enum.Parse(typeof(DisplayType), name); + case "Fixed Point 12.4": + return DisplayType.FixedPoint_12_4; + case "Fixed Point 20.12": + return DisplayType.FixedPoint_20_12; + case "Fixed Point 16.16": + return DisplayType.FixedPoint_16_16; + } + } + + public char SizeAsChar + { + get + { + switch (Size) + { + default: + case WatchSize.Separator: + return 'S'; + case WatchSize.Byte: + return 'b'; + case WatchSize.Word: + return 'w'; + case WatchSize.DWord: + return 'd'; + } + } + } + + public static WatchSize SizeFromChar(char c) + { + switch (c) + { + default: + case 'S': + return WatchSize.Separator; + case 'b': + return WatchSize.Byte; + case 'w': + return WatchSize.Word; + case 'd': + return WatchSize.DWord; + } + } + + public char TypeAsChar + { + get + { + switch (Type) + { + default: + case DisplayType.Separator: + return '_'; + case DisplayType.Unsigned: + return 'u'; + case DisplayType.Signed: + return 's'; + case DisplayType.Hex: + return 'h'; + case DisplayType.Binary: + return 'b'; + case DisplayType.FixedPoint_12_4: + return '1'; + case DisplayType.FixedPoint_20_12: + return '2'; + case DisplayType.FixedPoint_16_16: + return '3'; + case DisplayType.Float: + return 'f'; + } + } + } + + public static DisplayType DisplayTypeFromChar(char c) + { + switch (c) + { + default: + case '_': + return DisplayType.Separator; + case 'u': + return DisplayType.Unsigned; + case 's': + return DisplayType.Signed; + case 'h': + return DisplayType.Hex; + case 'b': + return DisplayType.Binary; + case '1': + return DisplayType.FixedPoint_12_4; + case '2': + return DisplayType.FixedPoint_20_12; + case '3': + return DisplayType.FixedPoint_16_16; + case 'f': + return DisplayType.Float; + } + } + + public string AddressFormatStr + { + get + { + if (_domain != null) + { + return "X" + (_domain.Size - 1).NumHexDigits(); + } + + return string.Empty; + } + } + + protected byte GetByte(bool bypassFreeze = false) + { + if (!bypassFreeze && Global.CheatList.IsActive(_domain, _address)) + { + //LIAR logic + return Global.CheatList.GetByteValue(_domain, _address).Value; + } + else + { + if (_domain.Size == 0) + { + return _domain.PeekByte(_address); + } + else + { + return _domain.PeekByte(_address % _domain.Size); + } + } + } + + protected ushort GetWord(bool bypassFreeze = false) + { + if (!bypassFreeze && Global.CheatList.IsActive(_domain, _address)) + { + //LIAR logic + return (ushort)Global.CheatList.GetCheatValue(_domain, _address, WatchSize.Word).Value; + } + else + { + if (_domain.Size == 0) + { + return _domain.PeekWord(_address, _bigEndian); + } + else + { + return _domain.PeekWord(_address % _domain.Size, _bigEndian); // TODO: % size stil lisn't correct since it could be the last byte of the domain + } + } + } + + protected uint GetDWord(bool bypassFreeze = false) + { + if (!bypassFreeze && Global.CheatList.IsActive(_domain, _address)) + { + //LIAR logic + return (uint)Global.CheatList.GetCheatValue(_domain, _address, WatchSize.DWord).Value; + } + else + { + if (_domain.Size == 0) + { + return _domain.PeekDWord(_address, _bigEndian); // TODO: % size stil lisn't correct since it could be the last byte of the domain + } + else + { + return _domain.PeekDWord(_address % _domain.Size, _bigEndian); // TODO: % size stil lisn't correct since it could be the last byte of the domain + } + } + } + + protected void PokeByte(byte val) + { + if (_domain.Size == 0) + _domain.PokeByte(_address, val); + else _domain.PokeByte(_address % _domain.Size, val); + } + + protected void PokeWord(ushort val) + { + if (_domain.Size == 0) + _domain.PokeWord(_address, val, _bigEndian); // TODO: % size stil lisn't correct since it could be the last byte of the domain + else _domain.PokeWord(_address % _domain.Size, val, _bigEndian); // TODO: % size stil lisn't correct since it could be the last byte of the domain + } + + protected void PokeDWord(uint val) + { + if (_domain.Size == 0) + _domain.PokeDWord(_address, val, _bigEndian); // TODO: % size stil lisn't correct since it could be the last byte of the domain + else _domain.PokeDWord(_address % _domain.Size, val, _bigEndian); // TODO: % size stil lisn't correct since it could be the last byte of the domain + } + + public void ClearChangeCount() { _changecount = 0; } + + public bool IsOutOfRange + { + get + { + return !IsSeparator && (Domain.Size != 0 && Address.Value >= Domain.Size); + } + } + + public string Notes { get { return _notes; } set { _notes = value; } } + + public static Watch GenerateWatch(MemoryDomain domain, long address, WatchSize size, DisplayType type, string notes, bool bigEndian) + { + switch (size) + { + default: + case WatchSize.Separator: + return SeparatorWatch.Instance; + case WatchSize.Byte: + return new ByteWatch(domain, address, type, bigEndian, notes); + case WatchSize.Word: + return new WordWatch(domain, address, type, bigEndian, notes); + case WatchSize.DWord: + return new DWordWatch(domain, address, type, bigEndian, notes); + } + } + + public static Watch GenerateWatch(MemoryDomain domain, long address, WatchSize size, DisplayType type, bool bigendian, long prev, int changecount) + { + switch (size) + { + default: + case WatchSize.Separator: + return SeparatorWatch.Instance; + case WatchSize.Byte: + return new ByteWatch(domain, address, type, bigendian, (byte)prev, changecount); + case WatchSize.Word: + return new WordWatch(domain, address, type, bigendian, (ushort)prev, changecount); + case WatchSize.DWord: + return new DWordWatch(domain, address, type, bigendian, (uint)prev, changecount); + } + } + + public static List AvailableTypes(WatchSize size) + { + switch (size) + { + default: + case WatchSize.Separator: + return SeparatorWatch.ValidTypes; + case WatchSize.Byte: + return ByteWatch.ValidTypes; + case WatchSize.Word: + return WordWatch.ValidTypes; + case WatchSize.DWord: + return DWordWatch.ValidTypes; + } + } + + public int ChangeCount { get { return _changecount; } } + + public abstract string Diff { get; } + + public abstract void Update(); + + public override bool Equals(object obj) + { + if (obj is Watch) + { + var watch = obj as Watch; + + return this.Domain == watch.Domain && + this.Address == watch.Address && + this.Size == watch.Size && + this.Type == watch.Type && + this.Notes == watch.Notes; + } + + if (obj is Cheat) + { + var cheat = obj as Cheat; + return this.Domain == cheat.Domain && this.Address == cheat.Address; + } + + return base.Equals(obj); + } + + public override int GetHashCode() + { + return this.Domain.GetHashCode() + (int)(this.Address ?? 0); + } + + public static bool operator ==(Watch a, Watch b) + { + // If one is null, but not both, return false. + if (((object)a == null) || ((object)b == null)) + { + return false; + } + + return a.Equals(b); + } + + public static bool operator !=(Watch a, Watch b) + { + return !a.Equals(b); + } + + public static bool operator ==(Watch a, Cheat b) + { + // If one is null, but not both, return false. + if (((object)a == null) || ((object)b == null)) + { + return false; + } + + return a.Domain == b.Domain && a.Address == b.Address; + } + + public static bool operator !=(Watch a, Cheat b) + { + return !(a == b); + } + } +} diff --git a/BizHawk.Client.Common/tools/WatchList.cs b/BizHawk.Client.Common/tools/Watch/WatchList.cs similarity index 95% rename from BizHawk.Client.Common/tools/WatchList.cs rename to BizHawk.Client.Common/tools/Watch/WatchList.cs index 8641b729a4..0e690bfd4a 100644 --- a/BizHawk.Client.Common/tools/WatchList.cs +++ b/BizHawk.Client.Common/tools/Watch/WatchList.cs @@ -1,560 +1,560 @@ -using System.Collections; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Text; - -using BizHawk.Common.NumberExtensions; -using BizHawk.Common.StringExtensions; -using BizHawk.Emulation.Common; - -namespace BizHawk.Client.Common -{ - public class WatchList : IList - { - private IMemoryDomains _memoryDomains; - private List _watchList = new List(); - private MemoryDomain _domain; - private string _currentFilename = string.Empty; - private string _systemid; - - public const string ADDRESS = "AddressColumn"; - public const string VALUE = "ValueColumn"; - public const string PREV = "PrevColumn"; - public const string CHANGES = "ChangesColumn"; - public const string DIFF = "DiffColumn"; - public const string DOMAIN = "DomainColumn"; - public const string NOTES = "NotesColumn"; - - public WatchList(IMemoryDomains core, MemoryDomain domain, string systemid) - { - _memoryDomains = core; - _domain = domain; - _systemid = systemid; - } - - public void RefreshDomans(IMemoryDomains core, MemoryDomain domain) - { - _memoryDomains = core; - _domain = domain; - - _watchList.ForEach(w => - { - if (w.Domain != null) - { - w.Domain = _memoryDomains[w.Domain.Name]; - } - }); - } - - public enum WatchPrevDef { LastSearch, Original, LastFrame, LastChange } - - public string AddressFormatStr // TODO: this is probably compensating for not using the ToHex string extension - { - get - { - if (_domain != null) - { - return "{0:X" + (_domain.Size - 1).NumHexDigits() + "}"; - } - - return string.Empty; - } - } - - public int Count - { - get { return _watchList.Count; } - } - - public int WatchCount - { - get { return _watchList.Count(w => !w.IsSeparator); } - } - - public int ItemCount - { - get { return _watchList.Count; } - } - - public MemoryDomain Domain - { - get { return _domain; } - set { _domain = value; } - } - - public bool IsReadOnly { get { return false; } } - - public string CurrentFileName - { - get { return _currentFilename; } - set { _currentFilename = value; } - } - - public bool Changes { get; set; } - - public Watch this[int index] - { - get { return _watchList[index]; } - set { _watchList[index] = value; } - } - - public IEnumerator GetEnumerator() - { - return _watchList.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public void OrderWatches(string column, bool reverse) - { - switch (column) - { - case ADDRESS: - if (reverse) - { - _watchList = _watchList - .OrderByDescending(x => x.Address ?? 0) - .ThenBy(x => x.Domain.Name) - .ThenBy(x => x.Size) - .ThenBy(x => x.Type) - .ThenBy(x => x.BigEndian) - .ToList(); - } - else - { - _watchList = _watchList - .OrderBy(x => x.Address ?? 0) - .ThenBy(x => x.Domain.Name) - .ThenBy(x => x.Size) - .ThenBy(x => x.Type) - .ThenBy(x => x.BigEndian) - .ToList(); - } - - break; - case VALUE: - if (reverse) - { - _watchList = _watchList - .OrderByDescending(x => x.Value ?? 0) - .ThenBy(x => x.Address ?? 0) - .ThenBy(x => x.Size) - .ThenBy(x => x.Type) - .ThenBy(x => x.BigEndian) - .ToList(); - } - else - { - _watchList = _watchList - .OrderBy(x => x.Value ?? 0) - .ThenBy(x => x.Address ?? 0) - .ThenBy(x => x.Size) - .ThenBy(x => x.Type) - .ThenBy(x => x.BigEndian) - .ToList(); - } - - break; - case PREV: // Note: these only work if all entries are detailed objects! - if (reverse) - { - _watchList = _watchList - .OrderByDescending(x => x.PreviousStr) - .ThenBy(x => x.Address ?? 0) - .ThenBy(x => x.Size) - .ThenBy(x => x.Type) - .ToList(); - } - else - { - _watchList = _watchList - .OrderBy(x => x.PreviousStr) - .ThenBy(x => x.Address ?? 0) - .ThenBy(x => x.Size) - .ThenBy(x => x.Type) - .ToList(); - } - - break; - case DIFF: - if (reverse) - { - _watchList = _watchList - .OrderByDescending(x => x.Diff) - .ThenBy(x => x.Address ?? 0) - .ThenBy(x => x.Size) - .ThenBy(x => x.Type) - .ToList(); - } - else - { - _watchList = _watchList - .OrderBy(x => x.Diff) - .ThenBy(x => x.Address ?? 0) - .ThenBy(x => x.Size) - .ThenBy(x => x.Type) - .ToList(); - } - - break; - case CHANGES: - if (reverse) - { - _watchList = _watchList - .OrderByDescending(x => x.ChangeCount) - .ThenBy(x => x.Address ?? 0) - .ThenBy(x => x.Size) - .ThenBy(x => x.Type) - .ToList(); - } - else - { - _watchList = _watchList - .OrderBy(x => x.ChangeCount) - .ThenBy(x => x.Address ?? 0) - .ThenBy(x => x.Size) - .ThenBy(x => x.Type) - .ToList(); - } - - break; - case DOMAIN: - if (reverse) - { - _watchList = _watchList - .OrderByDescending(x => x.Domain) - .ThenBy(x => x.Address ?? 0) - .ThenBy(x => x.Size) - .ThenBy(x => x.Type) - .ThenBy(x => x.BigEndian) - .ToList(); - } - else - { - _watchList = _watchList - .OrderBy(x => x.Domain) - .ThenBy(x => x.Address ?? 0) - .ThenBy(x => x.Size) - .ThenBy(x => x.Type) - .ThenBy(x => x.BigEndian) - .ToList(); - } - - break; - case NOTES: - if (reverse) - { - _watchList = _watchList - .OrderByDescending(x => x.Notes) - .ThenBy(x => x.Address ?? 0) - .ThenBy(x => x.Size) - .ThenBy(x => x.Type) - .ToList(); - } - else - { - _watchList = _watchList - .OrderBy(x => x.Notes) - .ThenBy(x => x.Address ?? 0) - .ThenBy(x => x.Size) - .ThenBy(x => x.Type) - .ToList(); - } - - break; - } - } - - public void Clear() - { - _watchList.Clear(); - Changes = false; - _currentFilename = string.Empty; - } - - public void UpdateValues() - { - foreach (var watch in _watchList) - { - watch.Update(); - } - } - - public void Add(Watch watch) - { - _watchList.Add(watch); - Changes = true; - } - - public void AddRange(IList watches) - { - _watchList.AddRange(watches); - Changes = true; - } - - public bool Remove(Watch watch) - { - var result = _watchList.Remove(watch); - if (result) - { - Changes = true; - } - - return result; - } - - public void Insert(int index, Watch watch) - { - _watchList.Insert(index, watch); - } - - public void ClearChangeCounts() - { - foreach (var watch in _watchList) - { - watch.ClearChangeCount(); - } - } - - public bool Contains(Watch watch) - { - return _watchList.Any(w => - w.Size == watch.Size && - w.Type == watch.Type && - w.Domain == watch.Domain && - w.Address == watch.Address && - w.BigEndian == watch.BigEndian); - } - - public void CopyTo(Watch[] array, int arrayIndex) - { - _watchList.CopyTo(array, arrayIndex); - } - - public int IndexOf(Watch watch) - { - return _watchList.IndexOf(watch); - } - - public void RemoveAt(int index) - { - _watchList.RemoveAt(index); - Changes = true; - } - - #region File handling logic - probably needs to be its own class - - public bool Load(string path, bool append) - { - var result = LoadFile(path, append); - - if (result) - { - if (append) - { - Changes = true; - } - else - { - CurrentFileName = path; - Changes = false; - } - } - - return result; - } - - public void Reload() - { - if (!string.IsNullOrWhiteSpace(CurrentFileName)) - { - LoadFile(CurrentFileName, append: false); - Changes = false; - } - } - - public bool Save() - { - if (string.IsNullOrWhiteSpace(CurrentFileName)) - { - return false; - } - - using (var sw = new StreamWriter(CurrentFileName)) - { - var sb = new StringBuilder(); - sb - .Append("Domain ").AppendLine(_domain.Name) - .Append("SystemID ").AppendLine(_systemid); - - foreach (var watch in _watchList) - { - sb.AppendLine(Watch.ToString(watch, _domain)); - } - - sw.WriteLine(sb.ToString()); - } - - Global.Config.RecentWatches.Add(CurrentFileName); - Changes = false; - return true; - } - - public bool SaveAs(FileInfo file) - { - if (file != null) - { - CurrentFileName = file.FullName; - return Save(); - } - - return false; - } - - private bool LoadFile(string path, bool append) - { - var domain = string.Empty; - var file = new FileInfo(path); - if (file.Exists == false) - { - return false; - } - - var isBizHawkWatch = true; // Hack to support .wch files from other emulators - var isOldBizHawkWatch = false; - using (var sr = file.OpenText()) - { - string line; - - if (!append) - { - Clear(); - } - - while ((line = sr.ReadLine()) != null) - { - // .wch files from other emulators start with a number representing the number of watch, that line can be discarded here - // Any properly formatted line couldn't possibly be this short anyway, this also takes care of any garbage lines that might be in a file - if (line.Length < 5) - { - isBizHawkWatch = false; - continue; - } - - if (line.Length >= 6 && line.Substring(0, 6) == "Domain") - { - domain = line.Substring(7, line.Length - 7); - isBizHawkWatch = true; - } - - if (line.Length >= 8 && line.Substring(0, 8) == "SystemID") - { - continue; - } - - var numColumns = line.HowMany('\t'); - int startIndex; - if (numColumns == 5) - { - // If 5, then this is a post 1.0.5 .wch file - if (isBizHawkWatch) - { - // Do nothing here - } - else - { - startIndex = line.IndexOf('\t') + 1; - line = line.Substring(startIndex, line.Length - startIndex); // 5 digit value representing the watch position number - } - } - else if (numColumns == 4) - { - isOldBizHawkWatch = true; // This supports the legacy .wch format from 1.0.5 and earlier - } - else - { - continue; // If not 4, something is wrong with this line, ignore it - } - - // Temporary, rename if kept - int addr; - var memDomain = _memoryDomains.MainMemory; - - var temp = line.Substring(0, line.IndexOf('\t')); - try - { - addr = int.Parse(temp, NumberStyles.HexNumber); - } - catch - { - continue; - } - - startIndex = line.IndexOf('\t') + 1; - line = line.Substring(startIndex, line.Length - startIndex); // Type - var size = Watch.SizeFromChar(line[0]); - - startIndex = line.IndexOf('\t') + 1; - line = line.Substring(startIndex, line.Length - startIndex); // Signed - var type = Watch.DisplayTypeFromChar(line[0]); - - startIndex = line.IndexOf('\t') + 1; - line = line.Substring(startIndex, line.Length - startIndex); // Endian - try - { - startIndex = short.Parse(line[0].ToString()); - } - catch - { - continue; - } - - var bigEndian = startIndex != 0; - - if (isBizHawkWatch && !isOldBizHawkWatch) - { - startIndex = line.IndexOf('\t') + 1; - line = line.Substring(startIndex, line.Length - startIndex); // Domain - temp = line.Substring(0, line.IndexOf('\t')); - memDomain = _memoryDomains[temp] ?? _memoryDomains.MainMemory; - } - - startIndex = line.IndexOf('\t') + 1; - var notes = line.Substring(startIndex, line.Length - startIndex); - - _watchList.Add( - Watch.GenerateWatch( - memDomain, - addr, - size, - type, - notes, - bigEndian)); - _domain = _memoryDomains[domain]; - } - - Domain = _memoryDomains[domain] ?? _memoryDomains.MainMemory; - _currentFilename = path; - } - - if (!append) - { - Global.Config.RecentWatches.Add(path); - Changes = false; - } - else - { - Changes = true; - } - - return true; - } - - #endregion - } -} +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; + +using BizHawk.Common.NumberExtensions; +using BizHawk.Common.StringExtensions; +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.Common +{ + public class WatchList : IList + { + private IMemoryDomains _memoryDomains; + private List _watchList = new List(); + private MemoryDomain _domain; + private string _currentFilename = string.Empty; + private string _systemid; + + public const string ADDRESS = "AddressColumn"; + public const string VALUE = "ValueColumn"; + public const string PREV = "PrevColumn"; + public const string CHANGES = "ChangesColumn"; + public const string DIFF = "DiffColumn"; + public const string DOMAIN = "DomainColumn"; + public const string NOTES = "NotesColumn"; + + public WatchList(IMemoryDomains core, MemoryDomain domain, string systemid) + { + _memoryDomains = core; + _domain = domain; + _systemid = systemid; + } + + public void RefreshDomans(IMemoryDomains core, MemoryDomain domain) + { + _memoryDomains = core; + _domain = domain; + + _watchList.ForEach(w => + { + if (w.Domain != null) + { + w.Domain = _memoryDomains[w.Domain.Name]; + } + }); + } + + public enum WatchPrevDef { LastSearch, Original, LastFrame, LastChange } + + public string AddressFormatStr // TODO: this is probably compensating for not using the ToHex string extension + { + get + { + if (_domain != null) + { + return "{0:X" + (_domain.Size - 1).NumHexDigits() + "}"; + } + + return string.Empty; + } + } + + public int Count + { + get { return _watchList.Count; } + } + + public int WatchCount + { + get { return _watchList.Count(w => !w.IsSeparator); } + } + + public int ItemCount + { + get { return _watchList.Count; } + } + + public MemoryDomain Domain + { + get { return _domain; } + set { _domain = value; } + } + + public bool IsReadOnly { get { return false; } } + + public string CurrentFileName + { + get { return _currentFilename; } + set { _currentFilename = value; } + } + + public bool Changes { get; set; } + + public Watch this[int index] + { + get { return _watchList[index]; } + set { _watchList[index] = value; } + } + + public IEnumerator GetEnumerator() + { + return _watchList.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void OrderWatches(string column, bool reverse) + { + switch (column) + { + case ADDRESS: + if (reverse) + { + _watchList = _watchList + .OrderByDescending(x => x.Address ?? 0) + .ThenBy(x => x.Domain.Name) + .ThenBy(x => x.Size) + .ThenBy(x => x.Type) + .ThenBy(x => x.BigEndian) + .ToList(); + } + else + { + _watchList = _watchList + .OrderBy(x => x.Address ?? 0) + .ThenBy(x => x.Domain.Name) + .ThenBy(x => x.Size) + .ThenBy(x => x.Type) + .ThenBy(x => x.BigEndian) + .ToList(); + } + + break; + case VALUE: + if (reverse) + { + _watchList = _watchList + .OrderByDescending(x => x.Value ?? 0) + .ThenBy(x => x.Address ?? 0) + .ThenBy(x => x.Size) + .ThenBy(x => x.Type) + .ThenBy(x => x.BigEndian) + .ToList(); + } + else + { + _watchList = _watchList + .OrderBy(x => x.Value ?? 0) + .ThenBy(x => x.Address ?? 0) + .ThenBy(x => x.Size) + .ThenBy(x => x.Type) + .ThenBy(x => x.BigEndian) + .ToList(); + } + + break; + case PREV: // Note: these only work if all entries are detailed objects! + if (reverse) + { + _watchList = _watchList + .OrderByDescending(x => x.PreviousStr) + .ThenBy(x => x.Address ?? 0) + .ThenBy(x => x.Size) + .ThenBy(x => x.Type) + .ToList(); + } + else + { + _watchList = _watchList + .OrderBy(x => x.PreviousStr) + .ThenBy(x => x.Address ?? 0) + .ThenBy(x => x.Size) + .ThenBy(x => x.Type) + .ToList(); + } + + break; + case DIFF: + if (reverse) + { + _watchList = _watchList + .OrderByDescending(x => x.Diff) + .ThenBy(x => x.Address ?? 0) + .ThenBy(x => x.Size) + .ThenBy(x => x.Type) + .ToList(); + } + else + { + _watchList = _watchList + .OrderBy(x => x.Diff) + .ThenBy(x => x.Address ?? 0) + .ThenBy(x => x.Size) + .ThenBy(x => x.Type) + .ToList(); + } + + break; + case CHANGES: + if (reverse) + { + _watchList = _watchList + .OrderByDescending(x => x.ChangeCount) + .ThenBy(x => x.Address ?? 0) + .ThenBy(x => x.Size) + .ThenBy(x => x.Type) + .ToList(); + } + else + { + _watchList = _watchList + .OrderBy(x => x.ChangeCount) + .ThenBy(x => x.Address ?? 0) + .ThenBy(x => x.Size) + .ThenBy(x => x.Type) + .ToList(); + } + + break; + case DOMAIN: + if (reverse) + { + _watchList = _watchList + .OrderByDescending(x => x.Domain) + .ThenBy(x => x.Address ?? 0) + .ThenBy(x => x.Size) + .ThenBy(x => x.Type) + .ThenBy(x => x.BigEndian) + .ToList(); + } + else + { + _watchList = _watchList + .OrderBy(x => x.Domain) + .ThenBy(x => x.Address ?? 0) + .ThenBy(x => x.Size) + .ThenBy(x => x.Type) + .ThenBy(x => x.BigEndian) + .ToList(); + } + + break; + case NOTES: + if (reverse) + { + _watchList = _watchList + .OrderByDescending(x => x.Notes) + .ThenBy(x => x.Address ?? 0) + .ThenBy(x => x.Size) + .ThenBy(x => x.Type) + .ToList(); + } + else + { + _watchList = _watchList + .OrderBy(x => x.Notes) + .ThenBy(x => x.Address ?? 0) + .ThenBy(x => x.Size) + .ThenBy(x => x.Type) + .ToList(); + } + + break; + } + } + + public void Clear() + { + _watchList.Clear(); + Changes = false; + _currentFilename = string.Empty; + } + + public void UpdateValues() + { + foreach (var watch in _watchList) + { + watch.Update(); + } + } + + public void Add(Watch watch) + { + _watchList.Add(watch); + Changes = true; + } + + public void AddRange(IList watches) + { + _watchList.AddRange(watches); + Changes = true; + } + + public bool Remove(Watch watch) + { + var result = _watchList.Remove(watch); + if (result) + { + Changes = true; + } + + return result; + } + + public void Insert(int index, Watch watch) + { + _watchList.Insert(index, watch); + } + + public void ClearChangeCounts() + { + foreach (var watch in _watchList) + { + watch.ClearChangeCount(); + } + } + + public bool Contains(Watch watch) + { + return _watchList.Any(w => + w.Size == watch.Size && + w.Type == watch.Type && + w.Domain == watch.Domain && + w.Address == watch.Address && + w.BigEndian == watch.BigEndian); + } + + public void CopyTo(Watch[] array, int arrayIndex) + { + _watchList.CopyTo(array, arrayIndex); + } + + public int IndexOf(Watch watch) + { + return _watchList.IndexOf(watch); + } + + public void RemoveAt(int index) + { + _watchList.RemoveAt(index); + Changes = true; + } + + #region File handling logic - probably needs to be its own class + + public bool Load(string path, bool append) + { + var result = LoadFile(path, append); + + if (result) + { + if (append) + { + Changes = true; + } + else + { + CurrentFileName = path; + Changes = false; + } + } + + return result; + } + + public void Reload() + { + if (!string.IsNullOrWhiteSpace(CurrentFileName)) + { + LoadFile(CurrentFileName, append: false); + Changes = false; + } + } + + public bool Save() + { + if (string.IsNullOrWhiteSpace(CurrentFileName)) + { + return false; + } + + using (var sw = new StreamWriter(CurrentFileName)) + { + var sb = new StringBuilder(); + sb + .Append("Domain ").AppendLine(_domain.Name) + .Append("SystemID ").AppendLine(_systemid); + + foreach (var watch in _watchList) + { + sb.AppendLine(watch.ToString()); + } + + sw.WriteLine(sb.ToString()); + } + + Global.Config.RecentWatches.Add(CurrentFileName); + Changes = false; + return true; + } + + public bool SaveAs(FileInfo file) + { + if (file != null) + { + CurrentFileName = file.FullName; + return Save(); + } + + return false; + } + + private bool LoadFile(string path, bool append) + { + var domain = string.Empty; + var file = new FileInfo(path); + if (file.Exists == false) + { + return false; + } + + var isBizHawkWatch = true; // Hack to support .wch files from other emulators + var isOldBizHawkWatch = false; + using (var sr = file.OpenText()) + { + string line; + + if (!append) + { + Clear(); + } + + while ((line = sr.ReadLine()) != null) + { + // .wch files from other emulators start with a number representing the number of watch, that line can be discarded here + // Any properly formatted line couldn't possibly be this short anyway, this also takes care of any garbage lines that might be in a file + if (line.Length < 5) + { + isBizHawkWatch = false; + continue; + } + + if (line.Length >= 6 && line.Substring(0, 6) == "Domain") + { + domain = line.Substring(7, line.Length - 7); + isBizHawkWatch = true; + } + + if (line.Length >= 8 && line.Substring(0, 8) == "SystemID") + { + continue; + } + + var numColumns = line.HowMany('\t'); + int startIndex; + if (numColumns == 5) + { + // If 5, then this is a post 1.0.5 .wch file + if (isBizHawkWatch) + { + // Do nothing here + } + else + { + startIndex = line.IndexOf('\t') + 1; + line = line.Substring(startIndex, line.Length - startIndex); // 5 digit value representing the watch position number + } + } + else if (numColumns == 4) + { + isOldBizHawkWatch = true; // This supports the legacy .wch format from 1.0.5 and earlier + } + else + { + continue; // If not 4, something is wrong with this line, ignore it + } + + // Temporary, rename if kept + int addr; + var memDomain = _memoryDomains.MainMemory; + + var temp = line.Substring(0, line.IndexOf('\t')); + try + { + addr = int.Parse(temp, NumberStyles.HexNumber); + } + catch + { + continue; + } + + startIndex = line.IndexOf('\t') + 1; + line = line.Substring(startIndex, line.Length - startIndex); // Type + var size = Watch.SizeFromChar(line[0]); + + startIndex = line.IndexOf('\t') + 1; + line = line.Substring(startIndex, line.Length - startIndex); // Signed + var type = Watch.DisplayTypeFromChar(line[0]); + + startIndex = line.IndexOf('\t') + 1; + line = line.Substring(startIndex, line.Length - startIndex); // Endian + try + { + startIndex = short.Parse(line[0].ToString()); + } + catch + { + continue; + } + + var bigEndian = startIndex != 0; + + if (isBizHawkWatch && !isOldBizHawkWatch) + { + startIndex = line.IndexOf('\t') + 1; + line = line.Substring(startIndex, line.Length - startIndex); // Domain + temp = line.Substring(0, line.IndexOf('\t')); + memDomain = _memoryDomains[temp] ?? _memoryDomains.MainMemory; + } + + startIndex = line.IndexOf('\t') + 1; + var notes = line.Substring(startIndex, line.Length - startIndex); + + _watchList.Add( + Watch.GenerateWatch( + memDomain, + addr, + size, + type, + notes, + bigEndian)); + _domain = _memoryDomains[domain]; + } + + Domain = _memoryDomains[domain] ?? _memoryDomains.MainMemory; + _currentFilename = path; + } + + if (!append) + { + Global.Config.RecentWatches.Add(path); + Changes = false; + } + else + { + Changes = true; + } + + return true; + } + + #endregion + } +} diff --git a/BizHawk.Client.Common/tools/Watch/WatchSize.cs b/BizHawk.Client.Common/tools/Watch/WatchSize.cs new file mode 100644 index 0000000000..f1274eb666 --- /dev/null +++ b/BizHawk.Client.Common/tools/Watch/WatchSize.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BizHawk.Client.Common +{ + public abstract partial class Watch + { + /// + /// This enum specify the size of a + /// + public enum WatchSize + { + /// + /// One byte (8 bits) + /// Use this for + /// + Byte = 1, + /// + /// 2 bytes (16 bits) + /// Use this for + /// + Word = 2, + /// + /// 4 bytes (32 bits) + /// Use this for + /// + DWord = 4, + /// + /// Special case used for a separator in ramwatch + /// Use this for + /// + Separator = 0 + } + } +} diff --git a/BizHawk.Client.Common/tools/Watch/WordWatch.cs b/BizHawk.Client.Common/tools/Watch/WordWatch.cs new file mode 100644 index 0000000000..53bf20765d --- /dev/null +++ b/BizHawk.Client.Common/tools/Watch/WordWatch.cs @@ -0,0 +1,234 @@ +using BizHawk.Common.NumberExtensions; +using BizHawk.Common.StringExtensions; +using BizHawk.Emulation.Common; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; + +namespace BizHawk.Client.Common +{ + public sealed class WordWatch : Watch + { + private ushort _previous; + private ushort _value; + + public WordWatch(MemoryDomain domain, long address, DisplayType type, bool bigEndian, string notes) + { + _domain = domain; + _address = address; + _value = _previous = GetWord(); + + if (AvailableTypes(WatchSize.Word).Contains(type)) + { + _type = type; + } + + _bigEndian = bigEndian; + + if (notes != null) + { + Notes = notes; + } + } + + public WordWatch(MemoryDomain domain, long address, DisplayType type, bool bigEndian, ushort prev, int changeCount, string notes = null) + : this(domain, address, type, bigEndian, notes) + { + _previous = prev; + _changecount = changeCount; + } + + public override uint MaxValue + { + get { return ushort.MaxValue; } + } + + public override int? Value + { + get { return GetWord(); } + } + + public override int? ValueNoFreeze + { + get { return GetWord(true); } + } + + public override int? Previous + { + get { return _previous; } + } + + public override string PreviousStr + { + get { return FormatValue(_previous); } + } + + public override void ResetPrevious() + { + _previous = GetWord(); + } + + public override WatchSize Size + { + get { return WatchSize.Word; } + } + + public static List ValidTypes + { + get + { + return new List + { + DisplayType.Unsigned, DisplayType.Signed, DisplayType.Hex, DisplayType.FixedPoint_12_4, DisplayType.Binary + }; + } + } + + public override string ValueString + { + get { return FormatValue(GetWord()); } + } + + public override string ToString() + { + return Notes + ": " + ValueString; + } + + public string FormatValue(ushort val) + { + switch (Type) + { + default: + case DisplayType.Unsigned: + return val.ToString(); + case DisplayType.Signed: + return ((short)val).ToString(); + case DisplayType.Hex: + return val.ToHexString(4); + case DisplayType.FixedPoint_12_4: + return string.Format("{0:F4}", val / 16.0); + case DisplayType.Binary: + return Convert.ToString(val, 2).PadLeft(16, '0').Insert(8, " ").Insert(4, " ").Insert(14, " "); + } + } + + public override bool Poke(string value) + { + try + { + ushort val = 0; + switch (Type) + { + case DisplayType.Unsigned: + if (value.IsUnsigned()) + { + val = (ushort)int.Parse(value); + } + else + { + return false; + } + + break; + case DisplayType.Signed: + if (value.IsSigned()) + { + val = (ushort)(short)int.Parse(value); + } + else + { + return false; + } + + break; + case DisplayType.Hex: + if (value.IsHex()) + { + val = (ushort)int.Parse(value, NumberStyles.HexNumber); + } + else + { + return false; + } + + break; + case DisplayType.Binary: + if (value.IsBinary()) + { + val = (ushort)Convert.ToInt32(value, 2); + } + else + { + return false; + } + + break; + case DisplayType.FixedPoint_12_4: + if (value.IsFixedPoint()) + { + val = (ushort)(double.Parse(value) * 16.0); + } + else + { + return false; + } + + break; + } + + if (Global.CheatList.Contains(Domain, _address)) + { + var cheat = Global.CheatList.FirstOrDefault(c => c.Address == _address && c.Domain == Domain); + if (cheat != (Cheat)null) + { + cheat.PokeValue(val); + PokeWord(val); + return true; + } + } + + PokeWord(val); + return true; + } + catch + { + return false; + } + } + + public override string Diff + { + get { return FormatValue((ushort)(_previous - _value)); } + } + + public override void Update() + { + switch (Global.Config.RamWatchDefinePrevious) + { + case PreviousType.Original: + return; + case PreviousType.LastChange: + var temp = _value; + _value = GetWord(); + + if (_value != temp) + { + _previous = temp; + _changecount++; + } + + break; + case PreviousType.LastFrame: + _previous = _value; + _value = GetWord(); + if (_value != Previous) + { + _changecount++; + } + + break; + } + } + } +} diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index e1ba614d41..852c8809ab 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -531,9 +531,7 @@ Component - - Component - + @@ -807,8 +805,6 @@ HexFind.cs - - @@ -1566,6 +1562,10 @@ + + {8e2f11f2-3955-4382-8c3a-ceba1276caea} + BizHawk.Client.ApiHawk + {24A0AA3C-B25F-4197-B23D-476D6462DBA0} BizHawk.Client.Common diff --git a/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/BizHawk.Client.EmuHawk/tools/ToolManager.cs index bf2e5f3381..c724746669 100644 --- a/BizHawk.Client.EmuHawk/tools/ToolManager.cs +++ b/BizHawk.Client.EmuHawk/tools/ToolManager.cs @@ -562,7 +562,8 @@ namespace BizHawk.Client.EmuHawk IToolForm tool; //Specific case for custom tools - //TODO: Use AppDomain in order to be able to unload the assembly + //TODO: Use AppDomain in order to be able to unload the assembly + //Hard stuff as we need a proxy object that inherit from MarshalByRefObject. if (toolType == typeof(IExternalToolForm)) { if (MessageBox.Show(@"Are you sure want to load this external tool?\r\nAccept ONLY if you trust the source and if you know what you're doing. In any other case, choose no." @@ -571,7 +572,7 @@ namespace BizHawk.Client.EmuHawk try { tool = Activator.CreateInstanceFrom(dllPath, "BizHawk.Client.EmuHawk.CustomMainForm").Unwrap() as IExternalToolForm; - if (tool == null) + if (tool == null) { MessageBox.Show("It seems that the object CustomMainForm does not implement IExternalToolForm. Please review the code.", "No, no, no. Wrong Way !", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return null; @@ -683,7 +684,7 @@ namespace BizHawk.Client.EmuHawk } var tool = Assembly - .GetAssembly(typeof(IToolForm)) + .GetExecutingAssembly() .GetTypes() .FirstOrDefault(type => type == t); diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs index d1bfdfe875..f8a70b9b91 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs @@ -1511,7 +1511,7 @@ namespace BizHawk.Client.EmuHawk var sb = new StringBuilder(); foreach (var watch in SelectedItems) { - sb.AppendLine(Watch.ToString(watch, _searches.Domain)); + sb.AppendLine(watch.ToString()); } if (sb.Length > 0) diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs index d0137d2490..0eadd6252d 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs @@ -352,7 +352,7 @@ namespace BizHawk.Client.EmuHawk var sb = new StringBuilder(); foreach (var watch in SelectedItems) { - sb.AppendLine(Watch.ToString(watch, _watches.Domain)); + sb.AppendLine(watch.ToString()); } if (sb.Length > 0) diff --git a/BizHawk.sln b/BizHawk.sln index 20621e4314..b7d95323c1 100644 --- a/BizHawk.sln +++ b/BizHawk.sln @@ -58,179 +58,228 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizHawk.Bizware.BizwareGL.S EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizHawk.Client.MultiHawk", "BizHawk.Client.MultiHawk\BizHawk.Client.MultiHawk.csproj", "{B95649F5-A0AE-41EB-B62B-578A2AFF5E18}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizHawk.Client.ApiHawk", "BizHawk.Client.ApiHawk\BizHawk.Client.ApiHawk.csproj", "{8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU Debug|Mixed Platforms = Debug|Mixed Platforms Debug|Win32 = Debug|Win32 Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU Release|Mixed Platforms = Release|Mixed Platforms Release|Win32 = Release|Win32 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Debug|Any CPU.ActiveCfg = Debug|x86 {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Debug|Mixed Platforms.Build.0 = Debug|x86 {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Debug|Win32.ActiveCfg = Debug|x86 {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Debug|x86.ActiveCfg = Debug|x86 {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Debug|x86.Build.0 = Debug|x86 + {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Release|Any CPU.ActiveCfg = Release|x86 {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Release|Mixed Platforms.ActiveCfg = Release|x86 {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Release|Mixed Platforms.Build.0 = Release|x86 {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Release|Win32.ActiveCfg = Release|x86 {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Release|x86.ActiveCfg = Release|x86 {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Release|x86.Build.0 = Release|x86 + {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Debug|Any CPU.ActiveCfg = Debug|x86 {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Debug|Mixed Platforms.Build.0 = Debug|x86 {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Debug|Win32.ActiveCfg = Debug|x86 {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Debug|x86.ActiveCfg = Debug|x86 {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Debug|x86.Build.0 = Debug|x86 + {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Release|Any CPU.ActiveCfg = Release|x86 {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Release|Mixed Platforms.ActiveCfg = Release|x86 {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Release|Mixed Platforms.Build.0 = Release|x86 {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Release|Win32.ActiveCfg = Release|x86 {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Release|x86.ActiveCfg = Release|x86 {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Release|x86.Build.0 = Release|x86 + {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Debug|Any CPU.ActiveCfg = Debug|x86 {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Debug|Mixed Platforms.Build.0 = Debug|x86 {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Debug|Win32.ActiveCfg = Debug|x86 {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Debug|x86.ActiveCfg = Debug|x86 {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Debug|x86.Build.0 = Debug|x86 + {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Release|Any CPU.ActiveCfg = Release|x86 {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Release|Mixed Platforms.ActiveCfg = Release|x86 {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Release|Mixed Platforms.Build.0 = Release|x86 {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Release|Win32.ActiveCfg = Release|x86 {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Release|x86.ActiveCfg = Release|x86 {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Release|x86.Build.0 = Release|x86 + {DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Any CPU.ActiveCfg = Debug|x86 {DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Mixed Platforms.Build.0 = Debug|x86 {DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Win32.ActiveCfg = Debug|x86 {DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Win32.Build.0 = Debug|x86 {DD448B37-BA3F-4544-9754-5406E8094723}.Debug|x86.ActiveCfg = Debug|x86 {DD448B37-BA3F-4544-9754-5406E8094723}.Debug|x86.Build.0 = Debug|x86 + {DD448B37-BA3F-4544-9754-5406E8094723}.Release|Any CPU.ActiveCfg = Release|x86 {DD448B37-BA3F-4544-9754-5406E8094723}.Release|Mixed Platforms.ActiveCfg = Release|x86 {DD448B37-BA3F-4544-9754-5406E8094723}.Release|Mixed Platforms.Build.0 = Release|x86 {DD448B37-BA3F-4544-9754-5406E8094723}.Release|Win32.ActiveCfg = Release|x86 {DD448B37-BA3F-4544-9754-5406E8094723}.Release|Win32.Build.0 = Release|x86 {DD448B37-BA3F-4544-9754-5406E8094723}.Release|x86.ActiveCfg = Release|x86 {DD448B37-BA3F-4544-9754-5406E8094723}.Release|x86.Build.0 = Release|x86 + {C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Any CPU.ActiveCfg = Debug|x86 {C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Mixed Platforms.Build.0 = Debug|x86 {C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Win32.ActiveCfg = Debug|x86 {C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Win32.Build.0 = Debug|x86 {C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|x86.ActiveCfg = Debug|x86 {C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|x86.Build.0 = Debug|x86 + {C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Any CPU.ActiveCfg = Release|x86 {C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Mixed Platforms.ActiveCfg = Release|x86 {C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Mixed Platforms.Build.0 = Release|x86 {C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Win32.ActiveCfg = Release|x86 {C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Win32.Build.0 = Release|x86 {C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|x86.ActiveCfg = Release|x86 {C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|x86.Build.0 = Release|x86 + {F51946EA-827F-4D82-B841-1F2F6D060312}.Debug|Any CPU.ActiveCfg = Debug|x86 {F51946EA-827F-4D82-B841-1F2F6D060312}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {F51946EA-827F-4D82-B841-1F2F6D060312}.Debug|Mixed Platforms.Build.0 = Debug|x86 {F51946EA-827F-4D82-B841-1F2F6D060312}.Debug|Win32.ActiveCfg = Debug|x86 {F51946EA-827F-4D82-B841-1F2F6D060312}.Debug|x86.ActiveCfg = Debug|x86 {F51946EA-827F-4D82-B841-1F2F6D060312}.Debug|x86.Build.0 = Debug|x86 + {F51946EA-827F-4D82-B841-1F2F6D060312}.Release|Any CPU.ActiveCfg = Release|x86 {F51946EA-827F-4D82-B841-1F2F6D060312}.Release|Mixed Platforms.ActiveCfg = Release|x86 {F51946EA-827F-4D82-B841-1F2F6D060312}.Release|Mixed Platforms.Build.0 = Release|x86 {F51946EA-827F-4D82-B841-1F2F6D060312}.Release|Win32.ActiveCfg = Release|x86 {F51946EA-827F-4D82-B841-1F2F6D060312}.Release|x86.ActiveCfg = Release|x86 {F51946EA-827F-4D82-B841-1F2F6D060312}.Release|x86.Build.0 = Release|x86 + {E1A23168-B571-411C-B360-2229E7225E0E}.Debug|Any CPU.ActiveCfg = Debug|x86 {E1A23168-B571-411C-B360-2229E7225E0E}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {E1A23168-B571-411C-B360-2229E7225E0E}.Debug|Mixed Platforms.Build.0 = Debug|x86 {E1A23168-B571-411C-B360-2229E7225E0E}.Debug|Win32.ActiveCfg = Debug|x86 {E1A23168-B571-411C-B360-2229E7225E0E}.Debug|x86.ActiveCfg = Debug|x86 {E1A23168-B571-411C-B360-2229E7225E0E}.Debug|x86.Build.0 = Debug|x86 + {E1A23168-B571-411C-B360-2229E7225E0E}.Release|Any CPU.ActiveCfg = Release|x86 {E1A23168-B571-411C-B360-2229E7225E0E}.Release|Mixed Platforms.ActiveCfg = Release|x86 {E1A23168-B571-411C-B360-2229E7225E0E}.Release|Mixed Platforms.Build.0 = Release|x86 {E1A23168-B571-411C-B360-2229E7225E0E}.Release|Win32.ActiveCfg = Release|x86 {E1A23168-B571-411C-B360-2229E7225E0E}.Release|x86.ActiveCfg = Release|x86 {E1A23168-B571-411C-B360-2229E7225E0E}.Release|x86.Build.0 = Release|x86 + {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Debug|Any CPU.ActiveCfg = Debug|x86 {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Debug|Mixed Platforms.Build.0 = Debug|x86 {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Debug|Win32.ActiveCfg = Debug|x86 {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Debug|x86.ActiveCfg = Debug|x86 {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Debug|x86.Build.0 = Debug|x86 + {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Release|Any CPU.ActiveCfg = Release|x86 {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Release|Mixed Platforms.ActiveCfg = Release|x86 {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Release|Mixed Platforms.Build.0 = Release|x86 {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Release|Win32.ActiveCfg = Release|x86 {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Release|x86.ActiveCfg = Release|x86 {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Release|x86.Build.0 = Release|x86 + {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Debug|Any CPU.ActiveCfg = Debug|x86 {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Debug|Mixed Platforms.Build.0 = Debug|x86 {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Debug|Win32.ActiveCfg = Debug|x86 {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Debug|x86.ActiveCfg = Debug|x86 {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Debug|x86.Build.0 = Debug|x86 + {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Release|Any CPU.ActiveCfg = Release|x86 {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Release|Mixed Platforms.ActiveCfg = Release|x86 {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Release|Mixed Platforms.Build.0 = Release|x86 {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Release|Win32.ActiveCfg = Release|x86 {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Release|x86.ActiveCfg = Release|x86 {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Release|x86.Build.0 = Release|x86 + {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Debug|Any CPU.ActiveCfg = Debug|x86 {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Debug|Mixed Platforms.Build.0 = Debug|x86 {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Debug|Win32.ActiveCfg = Debug|x86 {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Debug|x86.ActiveCfg = Debug|x86 {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Debug|x86.Build.0 = Debug|x86 + {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Release|Any CPU.ActiveCfg = Release|x86 {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Release|Mixed Platforms.ActiveCfg = Release|x86 {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Release|Mixed Platforms.Build.0 = Release|x86 {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Release|Win32.ActiveCfg = Release|x86 {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Release|x86.ActiveCfg = Release|x86 {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Release|x86.Build.0 = Release|x86 + {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|Any CPU.ActiveCfg = Debug|x86 {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|Mixed Platforms.Build.0 = Debug|x86 {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|Win32.ActiveCfg = Debug|x86 {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|Win32.Build.0 = Debug|x86 {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|x86.ActiveCfg = Debug|x86 {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|x86.Build.0 = Debug|x86 + {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|Any CPU.ActiveCfg = Release|x86 {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|Mixed Platforms.ActiveCfg = Release|x86 {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|Mixed Platforms.Build.0 = Release|x86 {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|Win32.ActiveCfg = Release|x86 {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|Win32.Build.0 = Release|x86 {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|x86.ActiveCfg = Release|x86 {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|x86.Build.0 = Release|x86 + {337CA23E-65E7-44E1-9411-97EE08BB8116}.Debug|Any CPU.ActiveCfg = Debug|x86 {337CA23E-65E7-44E1-9411-97EE08BB8116}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {337CA23E-65E7-44E1-9411-97EE08BB8116}.Debug|Mixed Platforms.Build.0 = Debug|x86 {337CA23E-65E7-44E1-9411-97EE08BB8116}.Debug|Win32.ActiveCfg = Debug|x86 {337CA23E-65E7-44E1-9411-97EE08BB8116}.Debug|x86.ActiveCfg = Debug|x86 {337CA23E-65E7-44E1-9411-97EE08BB8116}.Debug|x86.Build.0 = Debug|x86 + {337CA23E-65E7-44E1-9411-97EE08BB8116}.Release|Any CPU.ActiveCfg = Release|x86 {337CA23E-65E7-44E1-9411-97EE08BB8116}.Release|Mixed Platforms.ActiveCfg = Release|x86 {337CA23E-65E7-44E1-9411-97EE08BB8116}.Release|Mixed Platforms.Build.0 = Release|x86 {337CA23E-65E7-44E1-9411-97EE08BB8116}.Release|Win32.ActiveCfg = Release|x86 {337CA23E-65E7-44E1-9411-97EE08BB8116}.Release|x86.ActiveCfg = Release|x86 {337CA23E-65E7-44E1-9411-97EE08BB8116}.Release|x86.Build.0 = Release|x86 + {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Debug|Any CPU.ActiveCfg = Debug|x86 {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Debug|Mixed Platforms.Build.0 = Debug|x86 {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Debug|Win32.ActiveCfg = Debug|x86 {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Debug|x86.ActiveCfg = Debug|x86 {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Debug|x86.Build.0 = Debug|x86 + {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Release|Any CPU.ActiveCfg = Release|x86 {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Release|Mixed Platforms.ActiveCfg = Release|x86 {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Release|Mixed Platforms.Build.0 = Release|x86 {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Release|Win32.ActiveCfg = Release|x86 {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Release|x86.ActiveCfg = Release|x86 {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Release|x86.Build.0 = Release|x86 + {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Debug|Any CPU.ActiveCfg = Debug|x86 {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Debug|Mixed Platforms.Build.0 = Debug|x86 {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Debug|Win32.ActiveCfg = Debug|x86 {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Debug|x86.ActiveCfg = Debug|x86 {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Debug|x86.Build.0 = Debug|x86 + {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Release|Any CPU.ActiveCfg = Release|x86 {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Release|Mixed Platforms.ActiveCfg = Release|x86 {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Release|Mixed Platforms.Build.0 = Release|x86 {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Release|Win32.ActiveCfg = Release|x86 {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Release|x86.ActiveCfg = Release|x86 {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Release|x86.Build.0 = Release|x86 + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Debug|Win32.ActiveCfg = Debug|Any CPU + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Debug|Win32.Build.0 = Debug|Any CPU + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Debug|x86.ActiveCfg = Debug|Any CPU + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Debug|x86.Build.0 = Debug|Any CPU + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|Any CPU.Build.0 = Release|Any CPU + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|Win32.ActiveCfg = Release|Any CPU + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|Win32.Build.0 = Release|Any CPU + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|x86.ActiveCfg = Release|Any CPU + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution + {24A0AA3C-B25F-4197-B23D-476D6462DBA0} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA} {DD448B37-BA3F-4544-9754-5406E8094723} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA} {C4366030-6D03-424B-AE53-F4F43BB217C3} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA} - {24A0AA3C-B25F-4197-B23D-476D6462DBA0} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA} - {2D2890A8-C338-4439-AD8B-CB9EE85A94F9} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA} - {B95649F5-A0AE-41EB-B62B-578A2AFF5E18} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA} - {E1A23168-B571-411C-B360-2229E7225E0E} = {3627C08B-3E43-4224-9DA4-40BD69495FBC} {F51946EA-827F-4D82-B841-1F2F6D060312} = {3627C08B-3E43-4224-9DA4-40BD69495FBC} + {E1A23168-B571-411C-B360-2229E7225E0E} = {3627C08B-3E43-4224-9DA4-40BD69495FBC} {197D4314-8A9F-49BA-977D-54ACEFAEB6BA} = {3627C08B-3E43-4224-9DA4-40BD69495FBC} {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465} = {0540A9A6-977E-466D-8BD3-1D8590BD5282} {5160CFB1-5389-47C1-B7F6-8A0DC97641EE} = {0540A9A6-977E-466D-8BD3-1D8590BD5282} + {2D2890A8-C338-4439-AD8B-CB9EE85A94F9} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA} {337CA23E-65E7-44E1-9411-97EE08BB8116} = {0540A9A6-977E-466D-8BD3-1D8590BD5282} {E6B436B1-A3CD-4C9A-8F76-5D7154726884} = {0540A9A6-977E-466D-8BD3-1D8590BD5282} + {B95649F5-A0AE-41EB-B62B-578A2AFF5E18} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA} + {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA} EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = BizHawk.Client.EmuHawk\BizHawk.Client.EmuHawk.csproj