A round of code cleanup on Rewind and some other misc things in Client.Common

This commit is contained in:
adelikat 2013-12-30 01:17:11 +00:00
parent 134783ff36
commit 16f7c7fcdc
9 changed files with 383 additions and 315 deletions

View File

@ -1,4 +1,5 @@
using System.Collections; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -7,8 +8,8 @@ namespace BizHawk.Client.Common
[Newtonsoft.Json.JsonObject] [Newtonsoft.Json.JsonObject]
public class RecentFiles : IEnumerable public class RecentFiles : IEnumerable
{ {
public int MAX_RECENT_FILES { get; private set; } //Maximum number of files public int MAX_RECENT_FILES { get; private set; } // Maximum number of files
public List<string> recentlist { get; private set; } //List of recent files public List<string> recentlist { get; private set; } // List of recent files
public bool AutoLoad = false; public bool AutoLoad = false;
@ -46,13 +47,14 @@ namespace BizHawk.Client.Common
public void Add(string newFile) public void Add(string newFile)
{ {
for (int x = 0; x < recentlist.Count; x++) for (int i = 0; i < recentlist.Count; i++)
{ {
if (string.Compare(newFile, recentlist[x]) == 0) if (String.Compare(newFile, recentlist[i], StringComparison.CurrentCultureIgnoreCase) == 0)
{ {
recentlist.Remove(newFile); //intentionally keeps iterating after this to remove duplicate instances, though those should never exist in the first place recentlist.Remove(newFile); // intentionally keeps iterating after this to remove duplicate instances, though those should never exist in the first place
} }
} }
recentlist.Insert(0, newFile); recentlist.Insert(0, newFile);
if (recentlist.Count > MAX_RECENT_FILES) if (recentlist.Count > MAX_RECENT_FILES)
{ {
@ -62,15 +64,16 @@ namespace BizHawk.Client.Common
public bool Remove(string newFile) public bool Remove(string newFile)
{ {
bool removed = false; var removed = false;
for (int x = 0; x < recentlist.Count; x++) for (int i = 0; i < recentlist.Count; i++)
{ {
if (string.Compare(newFile, recentlist[x]) == 0) if (String.Compare(newFile, recentlist[i], StringComparison.CurrentCultureIgnoreCase) == 0)
{ {
recentlist.Remove(newFile); //intentionally keeps iterating after this to remove duplicate instances, though those should never exist in the first place recentlist.Remove(newFile); // intentionally keeps iterating after this to remove duplicate instances, though those should never exist in the first place
removed = true; removed = true;
} }
} }
return removed; return removed;
} }
@ -89,7 +92,7 @@ namespace BizHawk.Client.Common
} }
else else
{ {
return ""; return String.Empty;
} }
} }
} }

View File

@ -65,7 +65,7 @@ namespace BizHawk.Client.Common
public bool Deterministic { get; private set; } public bool Deterministic { get; private set; }
public class RomErrorArgs public class RomErrorArgs : EventArgs
{ {
// TODO: think about naming here, what to pass, a lot of potential good information about what went wrong could go here! // TODO: think about naming here, what to pass, a lot of potential good information about what went wrong could go here!
public RomErrorArgs(string message, string systemId) public RomErrorArgs(string message, string systemId)
@ -78,7 +78,7 @@ namespace BizHawk.Client.Common
public string AttemptedCoreLoad { get; private set; } public string AttemptedCoreLoad { get; private set; }
} }
public class SettingsLoadArgs public class SettingsLoadArgs : EventArgs
{ {
public object Settings { get; set; } public object Settings { get; set; }
public Type Core { get; private set; } public Type Core { get; private set; }

View File

@ -1,6 +1,6 @@
using System; using System;
using System.Threading;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Threading;
namespace BizHawk.Client.Common namespace BizHawk.Client.Common
{ {
@ -13,10 +13,11 @@ namespace BizHawk.Client.Common
// which will kill N64 for sure... // which will kill N64 for sure...
public static bool IsThreaded = false; public static bool IsThreaded = false;
private readonly ConcurrentQueue<Job> Jobs = new ConcurrentQueue<Job>(); private readonly ConcurrentQueue<Job> _jobs = new ConcurrentQueue<Job>();
private EventWaitHandle _ewh, _ewh2; private readonly EventWaitHandle _ewh;
private Thread _thread; private readonly EventWaitHandle _ewh2;
private Rewinder _rewinder; private readonly Thread _thread;
private readonly Rewinder _rewinder;
public RewindThreader(Rewinder rewinder, bool isThreaded) public RewindThreader(Rewinder rewinder, bool isThreaded)
{ {
@ -27,8 +28,7 @@ namespace BizHawk.Client.Common
{ {
_ewh = new EventWaitHandle(false, EventResetMode.AutoReset); _ewh = new EventWaitHandle(false, EventResetMode.AutoReset);
_ewh2 = new EventWaitHandle(false, EventResetMode.AutoReset); _ewh2 = new EventWaitHandle(false, EventResetMode.AutoReset);
_thread = new Thread(ThreadProc); _thread = new Thread(ThreadProc) { IsBackground = true };
_thread.IsBackground = true;
_thread.Start(); _thread.Start();
} }
} }
@ -40,9 +40,8 @@ namespace BizHawk.Client.Common
return; return;
} }
var job = new Job(); var job = new Job { Type = JobType.Abort };
job.Type = JobType.Abort; _jobs.Enqueue(job);
Jobs.Enqueue(job);
_ewh.Set(); _ewh.Set();
_thread.Join(); _thread.Join();
@ -50,15 +49,49 @@ namespace BizHawk.Client.Common
_ewh2.Dispose(); _ewh2.Dispose();
} }
void ThreadProc() public void Rewind(int frames)
{ {
for (; ; ) if (!IsThreaded)
{
_rewinder._RunRewind(frames);
return;
}
var job = new Job
{
Type = JobType.Rewind,
Frames = frames
};
_jobs.Enqueue(job);
_ewh.Set();
_ewh2.WaitOne();
}
public void Capture(byte[] coreSavestate)
{
if (!IsThreaded)
{
_rewinder.RunCapture(coreSavestate);
return;
}
var job = new Job
{
Type = JobType.Capture,
CoreState = coreSavestate
};
DoSafeEnqueue(job);
}
private void ThreadProc()
{
for (;; )
{ {
_ewh.WaitOne(); _ewh.WaitOne();
while (Jobs.Count != 0) while (_jobs.Count != 0)
{ {
Job job = null; Job job;
if (Jobs.TryDequeue(out job)) if (_jobs.TryDequeue(out job))
{ {
if (job.Type == JobType.Abort) if (job.Type == JobType.Abort)
{ {
@ -80,59 +113,29 @@ namespace BizHawk.Client.Common
} }
} }
public void Rewind(int frames) private void DoSafeEnqueue(Job job)
{ {
if (!IsThreaded) _jobs.Enqueue(job);
{
_rewinder._RunRewind(frames);
return;
}
var job = new Job();
job.Type = JobType.Rewind;
job.Frames = frames;
Jobs.Enqueue(job);
_ewh.Set();
_ewh2.WaitOne();
}
void DoSafeEnqueue(Job job)
{
Jobs.Enqueue(job);
_ewh.Set(); _ewh.Set();
//just in case... we're getting really behind.. slow it down here // just in case... we're getting really behind.. slow it down here
//if this gets backed up too much, then the rewind will seem to malfunction since it requires all the captures in the queue to complete first // if this gets backed up too much, then the rewind will seem to malfunction since it requires all the captures in the queue to complete first
while (Jobs.Count > 15) while (_jobs.Count > 15)
{ {
Thread.Sleep(0); Thread.Sleep(0);
} }
} }
public void Capture(byte[] coreSavestate)
{
if (!IsThreaded)
{
_rewinder.RunCapture(coreSavestate);
return;
}
var job = new Job();
job.Type = JobType.Capture;
job.CoreState = coreSavestate;
DoSafeEnqueue(job);
}
private enum JobType private enum JobType
{ {
Capture, Rewind, Abort Capture, Rewind, Abort
} }
private class Job private sealed class Job
{ {
public JobType Type; public JobType Type { get; set; }
public byte[] CoreState; public byte[] CoreState { get; set; }
public int Frames; public int Frames { get; set; }
} }
} }
} }

View File

@ -5,79 +5,81 @@ namespace BizHawk.Client.Common
{ {
public class Rewinder public class Rewinder
{ {
public bool RewindActive = true; public Rewinder()
{
RewindActive = true;
}
private StreamBlobDatabase RewindBuffer; private StreamBlobDatabase _rewindBuffer;
private RewindThreader RewindThread; private RewindThreader _rewindThread;
private byte[] LastState; private byte[] _lastState;
private bool RewindImpossible; private bool _rewindImpossible;
private int RewindFrequency = 1; private int _rewindFrequency = 1;
private bool RewindDeltaEnable = false; private bool _rewindDeltaEnable;
private byte[] RewindFellationBuf; private byte[] _rewindFellationBuf;
private byte[] TempBuf = new byte[0]; private byte[] _tempBuf = new byte[0];
public Action<string> MessageCallback; public Action<string> MessageCallback { get; set; }
public bool RewindActive { get; set; }
// TODO: make RewindBuf never be null // TODO: make RewindBuf never be null
public float FullnessRatio public float FullnessRatio
{ {
get { return RewindBuffer.FullnessRatio; } get { return _rewindBuffer.FullnessRatio; }
} }
public int Count public int Count
{ {
get { return RewindBuffer != null ? RewindBuffer.Count : 0; } get { return _rewindBuffer != null ? _rewindBuffer.Count : 0; }
} }
public long Size public long Size
{ {
get { return RewindBuffer != null ? RewindBuffer.Size : 0; } get { return _rewindBuffer != null ? _rewindBuffer.Size : 0; }
} }
public int BufferCount public int BufferCount
{ {
get { return RewindBuffer != null ? RewindBuffer.Count : 0; } get { return _rewindBuffer != null ? _rewindBuffer.Count : 0; }
} }
public bool HasBuffer public bool HasBuffer
{ {
get { return RewindBuffer != null; } get { return _rewindBuffer != null; }
} }
// TOOD: this should not be parameterless?! It is only possible due to passing a static context in // TOOD: this should not be parameterless?! It is only possible due to passing a static context in
public void CaptureRewindState() public void CaptureRewindState()
{ {
if (RewindImpossible) if (_rewindImpossible)
{ {
return; return;
} }
if (LastState == null) if (_lastState == null)
{ {
DoRewindSettings(); DoRewindSettings();
} }
// log a frame
//log a frame if (_lastState != null && Global.Emulator.Frame % _rewindFrequency == 0)
if (LastState != null && Global.Emulator.Frame % RewindFrequency == 0)
{ {
byte[] CurrentState = Global.Emulator.SaveStateBinary(); _rewindThread.Capture(Global.Emulator.SaveStateBinary());
RewindThread.Capture(CurrentState);
} }
} }
public void DoRewindSettings() public void DoRewindSettings()
{ {
// This is the first frame. Capture the state, and put it in LastState for future deltas to be compared against. // This is the first frame. Capture the state, and put it in LastState for future deltas to be compared against.
LastState = (byte[])Global.Emulator.SaveStateBinary().Clone(); _lastState = (byte[])Global.Emulator.SaveStateBinary().Clone();
int state_size = 0; int state_size;
if (LastState.Length >= Global.Config.Rewind_LargeStateSize) if (_lastState.Length >= Global.Config.Rewind_LargeStateSize)
{ {
SetRewindParams(Global.Config.RewindEnabledLarge, Global.Config.RewindFrequencyLarge); SetRewindParams(Global.Config.RewindEnabledLarge, Global.Config.RewindFrequencyLarge);
state_size = 3; state_size = 3;
} }
else if (LastState.Length >= Global.Config.Rewind_MediumStateSize) else if (_lastState.Length >= Global.Config.Rewind_MediumStateSize)
{ {
SetRewindParams(Global.Config.RewindEnabledMedium, Global.Config.RewindFrequencyMedium); SetRewindParams(Global.Config.RewindEnabledMedium, Global.Config.RewindFrequencyMedium);
state_size = 2; state_size = 2;
@ -88,7 +90,7 @@ namespace BizHawk.Client.Common
state_size = 1; state_size = 1;
} }
bool rewind_enabled = false; var rewind_enabled = false;
if (state_size == 1) if (state_size == 1)
{ {
rewind_enabled = Global.Config.RewindEnabledSmall; rewind_enabled = Global.Config.RewindEnabledSmall;
@ -102,31 +104,31 @@ namespace BizHawk.Client.Common
rewind_enabled = Global.Config.RewindEnabledLarge; rewind_enabled = Global.Config.RewindEnabledLarge;
} }
RewindDeltaEnable = Global.Config.Rewind_UseDelta; _rewindDeltaEnable = Global.Config.Rewind_UseDelta;
if (rewind_enabled) if (rewind_enabled)
{ {
long cap = Global.Config.Rewind_BufferSize * (long)1024 * (long)1024; var cap = Global.Config.Rewind_BufferSize * (long)1024 * 1024;
if (RewindBuffer != null) if (_rewindBuffer != null)
{ {
RewindBuffer.Dispose(); _rewindBuffer.Dispose();
} }
RewindBuffer = new StreamBlobDatabase(Global.Config.Rewind_OnDisk, cap, BufferManage); _rewindBuffer = new StreamBlobDatabase(Global.Config.Rewind_OnDisk, cap, BufferManage);
if (RewindThread != null) if (_rewindThread != null)
{ {
RewindThread.Dispose(); _rewindThread.Dispose();
} }
RewindThread = new RewindThreader(this, Global.Config.Rewind_IsThreaded); _rewindThread = new RewindThreader(this, Global.Config.Rewind_IsThreaded);
} }
} }
public void Rewind(int frames) public void Rewind(int frames)
{ {
RewindThread.Rewind(frames); _rewindThread.Rewind(frames);
} }
// TODO remove me // TODO remove me
@ -134,12 +136,12 @@ namespace BizHawk.Client.Common
{ {
for (int i = 0; i < frames; i++) for (int i = 0; i < frames; i++)
{ {
if (RewindBuffer.Count == 0 || (Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie.InputLogLength == 0)) if (_rewindBuffer.Count == 0 || (Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie.InputLogLength == 0))
{ {
return; return;
} }
if (LastState.Length < 0x10000) if (_lastState.Length < 0x10000)
{ {
Rewind64K(); Rewind64K();
} }
@ -153,16 +155,9 @@ namespace BizHawk.Client.Common
// TODO: only run by RewindThreader, refactor // TODO: only run by RewindThreader, refactor
public void RunCapture(byte[] coreSavestate) public void RunCapture(byte[] coreSavestate)
{ {
if (RewindDeltaEnable) if (_rewindDeltaEnable)
{ {
if (LastState.Length <= 0x10000) CaptureRewindStateDelta(coreSavestate, _lastState.Length <= 0x10000);
{
CaptureRewindStateDelta(coreSavestate, true);
}
else
{
CaptureRewindStateDelta(coreSavestate, false);
}
} }
else else
{ {
@ -172,13 +167,13 @@ namespace BizHawk.Client.Common
public void ResetRewindBuffer() public void ResetRewindBuffer()
{ {
if (RewindBuffer != null) if (_rewindBuffer != null)
{ {
RewindBuffer.Clear(); _rewindBuffer.Clear();
} }
RewindImpossible = false; _rewindImpossible = false;
LastState = null; _lastState = null;
} }
private void DoMessage(string message) private void DoMessage(string message)
@ -196,17 +191,17 @@ namespace BizHawk.Client.Common
DoMessage("Rewind " + (enabled ? "Enabled" : "Disabled")); DoMessage("Rewind " + (enabled ? "Enabled" : "Disabled"));
} }
if (RewindFrequency != frequency && enabled) if (_rewindFrequency != frequency && enabled)
{ {
DoMessage("Rewind frequency set to " + frequency); DoMessage("Rewind frequency set to " + frequency);
} }
RewindActive = enabled; RewindActive = enabled;
RewindFrequency = frequency; _rewindFrequency = frequency;
if (!RewindActive) if (!RewindActive)
{ {
LastState = null; _lastState = null;
} }
} }
@ -214,69 +209,69 @@ namespace BizHawk.Client.Common
{ {
if (allocate) if (allocate)
{ {
//if we have an appropriate buffer free, return it // if we have an appropriate buffer free, return it
if (RewindFellationBuf != null && RewindFellationBuf.LongLength == size) if (_rewindFellationBuf != null && _rewindFellationBuf.LongLength == size)
{ {
byte[] ret = RewindFellationBuf; var ret = _rewindFellationBuf;
RewindFellationBuf = null; _rewindFellationBuf = null;
return ret; return ret;
} }
//otherwise, allocate it
// otherwise, allocate it
return new byte[size]; return new byte[size];
} }
else else
{ {
RewindFellationBuf = inbuf; _rewindFellationBuf = inbuf;
return null; return null;
} }
} }
private void CaptureRewindStateNonDelta(byte[] CurrentState) private void CaptureRewindStateNonDelta(byte[] currentState)
{ {
long offset = RewindBuffer.Enqueue(0, CurrentState.Length + 1); long offset = _rewindBuffer.Enqueue(0, currentState.Length + 1);
Stream stream = RewindBuffer.Stream; var stream = _rewindBuffer.Stream;
stream.Position = offset; stream.Position = offset;
//write the header for a non-delta frame // write the header for a non-delta frame
stream.WriteByte(1); //i.e. true stream.WriteByte(1); // i.e. true
stream.Write(CurrentState, 0, CurrentState.Length); stream.Write(currentState, 0, currentState.Length);
} }
private void CaptureRewindStateDelta(byte[] CurrentState, bool isSmall) private void CaptureRewindStateDelta(byte[] currentState, bool isSmall)
{ {
//in case the state sizes mismatch, capture a full state rather than trying to do anything clever // in case the state sizes mismatch, capture a full state rather than trying to do anything clever
if (CurrentState.Length != LastState.Length) if (currentState.Length != _lastState.Length)
{ {
CaptureRewindStateNonDelta(CurrentState); CaptureRewindStateNonDelta(currentState);
return; return;
} }
int beginChangeSequence = -1; var beginChangeSequence = -1;
bool inChangeSequence = false; var inChangeSequence = false;
MemoryStream ms;
// try to set up the buffer in advance so we dont ever have exceptions in here // try to set up the buffer in advance so we dont ever have exceptions in here
if (TempBuf.Length < CurrentState.Length) if (_tempBuf.Length < currentState.Length)
{ {
TempBuf = new byte[CurrentState.Length * 2]; _tempBuf = new byte[currentState.Length * 2];
} }
ms = new MemoryStream(TempBuf, 0, TempBuf.Length, true, true); var ms = new MemoryStream(_tempBuf, 0, _tempBuf.Length, true, true);
RETRY: RETRY:
try try
{ {
var writer = new BinaryWriter(ms); var writer = new BinaryWriter(ms);
writer.Write(false); // delta state writer.Write(false); // delta state
for (int i = 0; i < CurrentState.Length; i++) for (int i = 0; i < currentState.Length; i++)
{ {
if (inChangeSequence == false) if (inChangeSequence == false)
{ {
if (i >= LastState.Length) if (i >= _lastState.Length)
{ {
continue; continue;
} }
if (CurrentState[i] == LastState[i]) if (currentState[i] == _lastState[i])
{ {
continue; continue;
} }
@ -286,7 +281,7 @@ namespace BizHawk.Client.Common
continue; continue;
} }
if (i - beginChangeSequence == 254 || i == CurrentState.Length - 1) if (i - beginChangeSequence == 254 || i == currentState.Length - 1)
{ {
writer.Write((byte)(i - beginChangeSequence + 1)); writer.Write((byte)(i - beginChangeSequence + 1));
if (isSmall) if (isSmall)
@ -298,12 +293,12 @@ namespace BizHawk.Client.Common
writer.Write(beginChangeSequence); writer.Write(beginChangeSequence);
} }
writer.Write(LastState, beginChangeSequence, i - beginChangeSequence + 1); writer.Write(_lastState, beginChangeSequence, i - beginChangeSequence + 1);
inChangeSequence = false; inChangeSequence = false;
continue; continue;
} }
if (CurrentState[i] == LastState[i]) if (currentState[i] == _lastState[i])
{ {
writer.Write((byte)(i - beginChangeSequence)); writer.Write((byte)(i - beginChangeSequence));
if (isSmall) if (isSmall)
@ -315,30 +310,30 @@ namespace BizHawk.Client.Common
writer.Write(beginChangeSequence); writer.Write(beginChangeSequence);
} }
writer.Write(LastState, beginChangeSequence, i - beginChangeSequence); writer.Write(_lastState, beginChangeSequence, i - beginChangeSequence);
inChangeSequence = false; inChangeSequence = false;
} }
} }
} }
catch (NotSupportedException) catch (NotSupportedException)
{ {
//ok... we had an exception after all // ok... we had an exception after all
//if we did actually run out of room in the memorystream, then try it again with a bigger buffer // if we did actually run out of room in the memorystream, then try it again with a bigger buffer
TempBuf = new byte[TempBuf.Length * 2]; _tempBuf = new byte[_tempBuf.Length * 2];
goto RETRY; goto RETRY;
} }
if (LastState != null && LastState.Length == CurrentState.Length) if (_lastState != null && _lastState.Length == currentState.Length)
{ {
Buffer.BlockCopy(CurrentState, 0, LastState, 0, LastState.Length); Buffer.BlockCopy(currentState, 0, _lastState, 0, _lastState.Length);
} }
else else
{ {
LastState = (byte[])CurrentState.Clone(); _lastState = (byte[])currentState.Clone();
} }
var seg = new ArraySegment<byte>(TempBuf, 0, (int)ms.Position); var seg = new ArraySegment<byte>(_tempBuf, 0, (int)ms.Position);
RewindBuffer.Push(seg); _rewindBuffer.Push(seg);
} }
private void RewindLarge() private void RewindLarge()
@ -353,23 +348,21 @@ namespace BizHawk.Client.Common
private void RewindDelta(bool isSmall) private void RewindDelta(bool isSmall)
{ {
var ms = RewindBuffer.PopMemoryStream(); var ms = _rewindBuffer.PopMemoryStream();
var reader = new BinaryReader(ms); var reader = new BinaryReader(ms);
bool fullstate = reader.ReadBoolean(); var fullstate = reader.ReadBoolean();
if (fullstate) if (fullstate)
{ {
Global.Emulator.LoadStateBinary(reader); Global.Emulator.LoadStateBinary(reader);
} }
else else
{ {
var output = new MemoryStream(LastState); var output = new MemoryStream(_lastState);
while (ms.Position < ms.Length - 1) while (ms.Position < ms.Length - 1)
{ {
byte len = reader.ReadByte(); var len = reader.ReadByte();
int offset; int offset = isSmall ? reader.ReadUInt16() : reader.ReadInt32();
if(isSmall)
offset = reader.ReadUInt16();
else offset = reader.ReadInt32();
output.Position = offset; output.Position = offset;
output.Write(ms.GetBuffer(), (int)ms.Position, len); output.Write(ms.GetBuffer(), (int)ms.Position, len);
ms.Position += len; ms.Position += len;

View File

@ -1,8 +1,6 @@
using System; using System;
using System.IO;
using System.Threading;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Concurrent; using System.IO;
namespace BizHawk.Client.Common namespace BizHawk.Client.Common
{ {
@ -25,7 +23,7 @@ namespace BizHawk.Client.Common
_mCapacity = capacity; _mCapacity = capacity;
if (onDisk) if (onDisk)
{ {
var path = Path.Combine(System.IO.Path.GetTempPath(), "bizhawk.rewindbuf-pid" + System.Diagnostics.Process.GetCurrentProcess().Id + "-" + Guid.NewGuid().ToString()); var path = Path.Combine(Path.GetTempPath(), "bizhawk.rewindbuf-pid" + System.Diagnostics.Process.GetCurrentProcess().Id + "-" + Guid.NewGuid());
// I checked the DeleteOnClose operation to make sure it cleans up when the process is aborted, and it seems to. // I checked the DeleteOnClose operation to make sure it cleans up when the process is aborted, and it seems to.
// Otherwise we would have a more complex tempfile management problem here. // Otherwise we would have a more complex tempfile management problem here.
@ -40,7 +38,7 @@ namespace BizHawk.Client.Common
} }
/// <summary> /// <summary>
/// Returns the amount of the buffer that's used /// Gets the amount of the buffer that's used
/// </summary> /// </summary>
public long Size { get { return _mSize; } } public long Size { get { return _mSize; } }
@ -50,12 +48,12 @@ namespace BizHawk.Client.Common
public float FullnessRatio { get { return (float)((double)Size / (double)_mCapacity); } } public float FullnessRatio { get { return (float)((double)Size / (double)_mCapacity); } }
/// <summary> /// <summary>
/// the number of frames stored here /// Gets the number of frames stored here
/// </summary> /// </summary>
public int Count { get { return _mBookmarks.Count; } } public int Count { get { return _mBookmarks.Count; } }
/// <summary> /// <summary>
/// The underlying stream to /// Gets the underlying stream to
/// </summary> /// </summary>
public Stream Stream { get { return _mStream; } } public Stream Stream { get { return _mStream; } }
@ -141,7 +139,7 @@ namespace BizHawk.Client.Common
CLEANUP: CLEANUP:
// while the head impinges on tail items, discard them // while the head impinges on tail items, discard them
for (; ; ) for (;;)
{ {
if (_mTail == null) if (_mTail == null)
{ {
@ -150,12 +148,15 @@ namespace BizHawk.Client.Common
if (_mHead.Value.EndExclusive > _mTail.Value.Index && _mHead.Value.Index <= _mTail.Value.Index) if (_mHead.Value.EndExclusive > _mTail.Value.Index && _mHead.Value.Index <= _mTail.Value.Index)
{ {
LinkedListNode<ListItem> nextTail = _mTail.Next; var nextTail = _mTail.Next;
_mSize -= _mTail.Value.Length; _mSize -= _mTail.Value.Length;
_mBookmarks.Remove(_mTail); _mBookmarks.Remove(_mTail);
_mTail = nextTail; _mTail = nextTail;
} }
else break; else
{
break;
}
} }
return _mHead.Value.Index; return _mHead.Value.Index;
@ -177,12 +178,7 @@ namespace BizHawk.Client.Common
_mTail = null; _mTail = null;
} }
_mHead = nextHead; _mHead = nextHead ?? _mBookmarks.Last;
if (_mHead == null)
{
_mHead = _mBookmarks.Last;
}
return ret; return ret;
} }
@ -196,18 +192,14 @@ namespace BizHawk.Client.Common
var ret = _mTail.Value; var ret = _mTail.Value;
_mSize -= ret.Length; _mSize -= ret.Length;
LinkedListNode<ListItem> nextTail = _mTail.Next; var nextTail = _mTail.Next;
_mBookmarks.Remove(_mTail); _mBookmarks.Remove(_mTail);
if (_mTail == _mHead) if (_mTail == _mHead)
{ {
_mHead = null; _mHead = null;
} }
_mTail = nextTail; _mTail = nextTail ?? _mBookmarks.First;
if (_mTail == null)
{
_mTail = _mBookmarks.First;
}
return ret; return ret;
} }
@ -222,7 +214,7 @@ namespace BizHawk.Client.Common
int ts = _mTail.Value.Timestamp; int ts = _mTail.Value.Timestamp;
LinkedListNode<ListItem> curr = _mTail; LinkedListNode<ListItem> curr = _mTail;
for (; ; ) for (;;)
{ {
if (curr == null) if (curr == null)
{ {

View File

@ -18,12 +18,13 @@ namespace BizHawk.Client.Common
{ {
return _changes; return _changes;
} }
set set
{ {
_changes = value; _changes = value;
if (value) if (value)
{ {
CheatChanged(Cheat.Separator); //Pass a dummy, no cheat invoked this change CheatChanged(Cheat.Separator); // Pass a dummy, no cheat invoked this change
} }
} }
} }
@ -49,10 +50,7 @@ namespace BizHawk.Client.Common
public void Pulse() public void Pulse()
{ {
foreach(var cheat in _cheatList) _cheatList.ForEach(cheat => cheat.Pulse());
{
cheat.Pulse();
}
} }
/// <summary> /// <summary>
@ -106,7 +104,6 @@ namespace BizHawk.Client.Common
if (cheat.IsSeparator) if (cheat.IsSeparator)
{ {
_cheatList.Add(cheat); _cheatList.Add(cheat);
} }
else else
{ {
@ -115,6 +112,7 @@ namespace BizHawk.Client.Common
{ {
_cheatList.Remove(Global.CheatList.FirstOrDefault(x => x.Domain == cheat.Domain && x.Address == cheat.Address)); _cheatList.Remove(Global.CheatList.FirstOrDefault(x => x.Domain == cheat.Domain && x.Address == cheat.Address));
} }
_cheatList.Add(cheat); _cheatList.Add(cheat);
} }
@ -138,7 +136,7 @@ namespace BizHawk.Client.Common
public bool Remove(Cheat c) public bool Remove(Cheat c)
{ {
bool result = _cheatList.Remove(c); var result = _cheatList.Remove(c);
if (result) if (result)
{ {
Changes = true; Changes = true;
@ -152,7 +150,6 @@ namespace BizHawk.Client.Common
public bool Remove(Watch w) public bool Remove(Watch w)
{ {
var cheat = _cheatList.FirstOrDefault(x => x.Domain == w.Domain && x.Address == w.Address); var cheat = _cheatList.FirstOrDefault(x => x.Domain == w.Domain && x.Address == w.Address);
if (cheat != null) if (cheat != null)
{ {
@ -184,6 +181,7 @@ namespace BizHawk.Client.Common
{ {
_cheatList.Remove(cheat); _cheatList.Remove(cheat);
} }
Changes = true; Changes = true;
} }
@ -254,15 +252,15 @@ namespace BizHawk.Client.Common
{ {
try try
{ {
FileInfo file = new FileInfo(path); var file = new FileInfo(path);
if (file.Directory != null && !file.Directory.Exists) if (file.Directory != null && !file.Directory.Exists)
{ {
file.Directory.Create(); file.Directory.Create();
} }
using (StreamWriter sw = new StreamWriter(path)) using (var sw = new StreamWriter(path))
{ {
StringBuilder sb = new StringBuilder(); var sb = new StringBuilder();
foreach (var cheat in _cheatList) foreach (var cheat in _cheatList)
{ {
@ -272,7 +270,7 @@ namespace BizHawk.Client.Common
} }
else else
{ {
//Set to hex for saving // Set to hex for saving
cheat.SetType(Watch.DisplayType.Hex); cheat.SetType(Watch.DisplayType.Hex);
sb sb
@ -316,7 +314,7 @@ namespace BizHawk.Client.Common
_currentFileName = path; _currentFileName = path;
} }
using (StreamReader sr = file.OpenText()) using (var sr = file.OpenText())
{ {
if (!append) if (!append)
{ {
@ -335,15 +333,18 @@ namespace BizHawk.Client.Common
else else
{ {
int? compare; int? compare;
Watch.WatchSize size = Watch.WatchSize.Byte; var size = Watch.WatchSize.Byte;
Watch.DisplayType type = Watch.DisplayType.Hex; var type = Watch.DisplayType.Hex;
bool BIGENDIAN = false; var bigendian = false;
if (s.Length < 6)
{
continue;
}
if (s.Length < 6) continue; var vals = s.Split('\t');
string[] vals = s.Split('\t'); var address = Int32.Parse(vals[0], NumberStyles.HexNumber);
int ADDR = Int32.Parse(vals[0], NumberStyles.HexNumber); var value = Int32.Parse(vals[1], NumberStyles.HexNumber);
int value = Int32.Parse(vals[1], NumberStyles.HexNumber);
if (vals[2] == "N") if (vals[2] == "N")
{ {
@ -353,28 +354,29 @@ namespace BizHawk.Client.Common
{ {
compare = Int32.Parse(vals[2], NumberStyles.HexNumber); compare = Int32.Parse(vals[2], NumberStyles.HexNumber);
} }
MemoryDomain domain = Global.Emulator.MemoryDomains[vals[3]];
bool ENABLED = vals[4] == "1";
string name = vals[5];
//For backwards compatibility, don't assume these values exist var domain = Global.Emulator.MemoryDomains[vals[3]];
var enabled = vals[4] == "1";
var name = vals[5];
// For backwards compatibility, don't assume these values exist
if (vals.Length > 6) if (vals.Length > 6)
{ {
size = Watch.SizeFromChar(vals[6][0]); size = Watch.SizeFromChar(vals[6][0]);
type = Watch.DisplayTypeFromChar(vals[7][0]); type = Watch.DisplayTypeFromChar(vals[7][0]);
BIGENDIAN = vals[8] == "1"; bigendian = vals[8] == "1";
} }
Watch w = Watch.GenerateWatch( var watch = Watch.GenerateWatch(
domain, domain,
ADDR, address,
size, size,
type, type,
name, name,
BIGENDIAN bigendian
); );
Add(new Cheat(w, value, compare, !Global.Config.DisableCheatsOnLoad && ENABLED)); Add(new Cheat(watch, value, compare, !Global.Config.DisableCheatsOnLoad && enabled));
} }
} }
catch catch
@ -412,6 +414,7 @@ namespace BizHawk.Client.Common
.ThenBy(x => x.Address ?? 0) .ThenBy(x => x.Address ?? 0)
.ToList(); .ToList();
} }
break; break;
case ADDRESS: case ADDRESS:
if (reverse) if (reverse)
@ -428,6 +431,7 @@ namespace BizHawk.Client.Common
.ThenBy(x => x.Name) .ThenBy(x => x.Name)
.ToList(); .ToList();
} }
break; break;
case VALUE: case VALUE:
if (reverse) if (reverse)
@ -446,6 +450,7 @@ namespace BizHawk.Client.Common
.ThenBy(x => x.Address ?? 0) .ThenBy(x => x.Address ?? 0)
.ToList(); .ToList();
} }
break; break;
case COMPARE: case COMPARE:
if (reverse) if (reverse)
@ -464,6 +469,7 @@ namespace BizHawk.Client.Common
.ThenBy(x => x.Address ?? 0) .ThenBy(x => x.Address ?? 0)
.ToList(); .ToList();
} }
break; break;
case ON: case ON:
if (reverse) if (reverse)
@ -482,6 +488,7 @@ namespace BizHawk.Client.Common
.ThenBy(x => x.Address ?? 0) .ThenBy(x => x.Address ?? 0)
.ToList(); .ToList();
} }
break; break;
case DOMAIN: case DOMAIN:
if (reverse) if (reverse)
@ -500,6 +507,7 @@ namespace BizHawk.Client.Common
.ThenBy(x => x.Address ?? 0) .ThenBy(x => x.Address ?? 0)
.ToList(); .ToList();
} }
break; break;
case SIZE: case SIZE:
if (reverse) if (reverse)
@ -518,6 +526,7 @@ namespace BizHawk.Client.Common
.ThenBy(x => x.Address ?? 0) .ThenBy(x => x.Address ?? 0)
.ToList(); .ToList();
} }
break; break;
case ENDIAN: case ENDIAN:
if (reverse) if (reverse)
@ -536,6 +545,7 @@ namespace BizHawk.Client.Common
.ThenBy(x => x.Address ?? 0) .ThenBy(x => x.Address ?? 0)
.ToList(); .ToList();
} }
break; break;
case TYPE: case TYPE:
if (reverse) if (reverse)
@ -554,11 +564,12 @@ namespace BizHawk.Client.Common
.ThenBy(x => x.Address ?? 0) .ThenBy(x => x.Address ?? 0)
.ToList(); .ToList();
} }
break; break;
} }
} }
public class CheatListEventArgs public class CheatListEventArgs : EventArgs
{ {
public CheatListEventArgs(Cheat c) public CheatListEventArgs(Cheat c)
{ {
@ -579,6 +590,7 @@ namespace BizHawk.Client.Common
{ {
Changed(this, new CheatListEventArgs(sender as Cheat)); Changed(this, new CheatListEventArgs(sender as Cheat));
} }
_changes = true; _changes = true;
} }

View File

@ -9,7 +9,7 @@ namespace BizHawk.Client.Common
{ {
public class RamSearchEngine public class RamSearchEngine
{ {
public enum ComparisonOperator { Equal, GreaterThan, GreaterThanEqual, LessThan, LessThanEqual, NotEqual, DifferentBy }; public enum ComparisonOperator { Equal, GreaterThan, GreaterThanEqual, LessThan, LessThanEqual, NotEqual, DifferentBy }
public enum Compare { Previous, SpecificValue, SpecificAddress, Changes, Difference } public enum Compare { Previous, SpecificValue, SpecificAddress, Changes, Difference }
private int? _differentBy; private int? _differentBy;
@ -72,14 +72,14 @@ namespace BizHawk.Client.Common
case Watch.WatchSize.Word: case Watch.WatchSize.Word:
if (_settings.Mode == Settings.SearchMode.Detailed) if (_settings.Mode == Settings.SearchMode.Detailed)
{ {
for (int i = 0; i < domain.Size; i += (_settings.CheckMisAligned ? 1 : 2)) for (int i = 0; i < domain.Size; i += _settings.CheckMisAligned ? 1 : 2)
{ {
_watchList.Add(new MiniWordWatchDetailed(domain, i, _settings.BigEndian)); _watchList.Add(new MiniWordWatchDetailed(domain, i, _settings.BigEndian));
} }
} }
else else
{ {
for (int i = 0; i < domain.Size; i += (_settings.CheckMisAligned ? 1 : 2)) for (int i = 0; i < domain.Size; i += _settings.CheckMisAligned ? 1 : 2)
{ {
_watchList.Add(new MiniWordWatch(domain, i, _settings.BigEndian)); _watchList.Add(new MiniWordWatch(domain, i, _settings.BigEndian));
} }
@ -89,14 +89,14 @@ namespace BizHawk.Client.Common
case Watch.WatchSize.DWord: case Watch.WatchSize.DWord:
if (_settings.Mode == Settings.SearchMode.Detailed) if (_settings.Mode == Settings.SearchMode.Detailed)
{ {
for (int i = 0; i < domain.Size; i += (_settings.CheckMisAligned ? 1 : 4)) for (int i = 0; i < domain.Size; i += _settings.CheckMisAligned ? 1 : 4)
{ {
_watchList.Add(new MiniDWordWatchDetailed(domain, i, _settings.BigEndian)); _watchList.Add(new MiniDWordWatchDetailed(domain, i, _settings.BigEndian));
} }
} }
else else
{ {
for (int i = 0; i < domain.Size; i += (_settings.CheckMisAligned ? 1 : 4)) for (int i = 0; i < domain.Size; i += _settings.CheckMisAligned ? 1 : 4)
{ {
_watchList.Add(new MiniDWordWatch(domain, i, _settings.BigEndian)); _watchList.Add(new MiniDWordWatch(domain, i, _settings.BigEndian));
} }
@ -219,7 +219,11 @@ namespace BizHawk.Client.Common
public Compare CompareTo public Compare CompareTo
{ {
get { return _compareTo; } get
{
return _compareTo;
}
set set
{ {
if (CanDoCompareType(value)) if (CanDoCompareType(value))
@ -310,7 +314,7 @@ namespace BizHawk.Client.Common
{ {
if (_settings.Mode == Settings.SearchMode.Detailed) if (_settings.Mode == Settings.SearchMode.Detailed)
{ {
foreach (IMiniWatchDetails watch in _watchList.Cast<IMiniWatchDetails>()) foreach (var watch in _watchList.Cast<IMiniWatchDetails>())
{ {
watch.ClearChangeCount(); watch.ClearChangeCount();
} }
@ -334,45 +338,66 @@ namespace BizHawk.Client.Common
_watchList.Clear(); _watchList.Clear();
} }
switch(_settings.Size) switch (_settings.Size)
{ {
default: default:
case Watch.WatchSize.Byte: case Watch.WatchSize.Byte:
if (_settings.Mode == Settings.SearchMode.Detailed) if (_settings.Mode == Settings.SearchMode.Detailed)
{ {
foreach(var addr in addresses) { _watchList.Add(new MiniByteWatchDetailed(_settings.Domain, addr)); } foreach (var addr in addresses)
{
_watchList.Add(new MiniByteWatchDetailed(_settings.Domain, addr));
}
} }
else else
{ {
foreach(var addr in addresses) { _watchList.Add(new MiniByteWatch(_settings.Domain, addr)); } foreach (var addr in addresses)
{
_watchList.Add(new MiniByteWatch(_settings.Domain, addr));
}
} }
break; break;
case Watch.WatchSize.Word: case Watch.WatchSize.Word:
if (_settings.Mode == Settings.SearchMode.Detailed) if (_settings.Mode == Settings.SearchMode.Detailed)
{ {
foreach (var addr in addresses) { _watchList.Add(new MiniWordWatchDetailed(_settings.Domain, addr, _settings.BigEndian)); } foreach (var addr in addresses)
{
_watchList.Add(new MiniWordWatchDetailed(_settings.Domain, addr, _settings.BigEndian));
}
} }
else else
{ {
foreach (var addr in addresses) { _watchList.Add(new MiniWordWatch(_settings.Domain, addr, _settings.BigEndian)); } foreach (var addr in addresses)
{
_watchList.Add(new MiniWordWatch(_settings.Domain, addr, _settings.BigEndian));
}
} }
break; break;
case Watch.WatchSize.DWord: case Watch.WatchSize.DWord:
if (_settings.Mode == Settings.SearchMode.Detailed) if (_settings.Mode == Settings.SearchMode.Detailed)
{ {
foreach (var addr in addresses) { _watchList.Add(new MiniDWordWatchDetailed(_settings.Domain, addr, _settings.BigEndian)); } foreach (var addr in addresses)
{
_watchList.Add(new MiniDWordWatchDetailed(_settings.Domain, addr, _settings.BigEndian));
}
} }
else else
{ {
foreach (var addr in addresses) { _watchList.Add(new MiniDWordWatch(_settings.Domain, addr, _settings.BigEndian)); } foreach (var addr in addresses)
{
_watchList.Add(new MiniDWordWatch(_settings.Domain, addr, _settings.BigEndian));
}
} }
break; break;
} }
} }
public void Sort(string column, bool reverse) public void Sort(string column, bool reverse)
{ {
switch(column) switch (column)
{ {
case WatchList.ADDRESS: case WatchList.ADDRESS:
if (reverse) if (reverse)
@ -383,6 +408,7 @@ namespace BizHawk.Client.Common
{ {
_watchList = _watchList.OrderBy(x => x.Address).ToList(); _watchList = _watchList.OrderBy(x => x.Address).ToList();
} }
break; break;
case WatchList.VALUE: case WatchList.VALUE:
if (reverse) if (reverse)
@ -393,6 +419,7 @@ namespace BizHawk.Client.Common
{ {
_watchList = _watchList.OrderBy(x => GetValue(x.Address)).ToList(); _watchList = _watchList.OrderBy(x => GetValue(x.Address)).ToList();
} }
break; break;
case WatchList.PREV: case WatchList.PREV:
if (reverse) if (reverse)
@ -403,6 +430,7 @@ namespace BizHawk.Client.Common
{ {
_watchList = _watchList.OrderBy(x => x.Previous).ToList(); _watchList = _watchList.OrderBy(x => x.Previous).ToList();
} }
break; break;
case WatchList.CHANGES: case WatchList.CHANGES:
if (_settings.Mode == Settings.SearchMode.Detailed) if (_settings.Mode == Settings.SearchMode.Detailed)
@ -422,6 +450,7 @@ namespace BizHawk.Client.Common
.Cast<IMiniWatch>().ToList(); .Cast<IMiniWatch>().ToList();
} }
} }
break; break;
case WatchList.DIFF: case WatchList.DIFF:
if (reverse) if (reverse)
@ -432,6 +461,7 @@ namespace BizHawk.Client.Common
{ {
_watchList = _watchList.OrderBy(x => (GetValue(x.Address) - x.Previous)).ToList(); _watchList = _watchList.OrderBy(x => (GetValue(x.Address) - x.Previous)).ToList();
} }
break; break;
} }
} }
@ -507,7 +537,6 @@ namespace BizHawk.Client.Common
{ {
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
} }
} }
@ -523,7 +552,7 @@ namespace BizHawk.Client.Common
case ComparisonOperator.NotEqual: case ComparisonOperator.NotEqual:
return watchList.Where(x => GetValue(x.Address) != _compareValue.Value); return watchList.Where(x => GetValue(x.Address) != _compareValue.Value);
case ComparisonOperator.GreaterThan: case ComparisonOperator.GreaterThan:
return watchList.Where(x => GetValue(x.Address) > _compareValue.Value); return watchList.Where(x => GetValue(x.Address) > _compareValue.Value);
case ComparisonOperator.GreaterThanEqual: case ComparisonOperator.GreaterThanEqual:
return watchList.Where(x => GetValue(x.Address) >= _compareValue.Value); return watchList.Where(x => GetValue(x.Address) >= _compareValue.Value);
case ComparisonOperator.LessThan: case ComparisonOperator.LessThan:
@ -695,6 +724,7 @@ namespace BizHawk.Client.Common
{ {
return theByte; return theByte;
} }
case Watch.WatchSize.Word: case Watch.WatchSize.Word:
var theWord = _settings.Domain.PeekWord(addr, _settings.BigEndian); var theWord = _settings.Domain.PeekWord(addr, _settings.BigEndian);
if (_settings.Type == Watch.DisplayType.Signed) if (_settings.Type == Watch.DisplayType.Signed)
@ -705,6 +735,7 @@ namespace BizHawk.Client.Common
{ {
return theWord; return theWord;
} }
case Watch.WatchSize.DWord: case Watch.WatchSize.DWord:
var theDWord = _settings.Domain.PeekDWord(addr, _settings.BigEndian); var theDWord = _settings.Domain.PeekDWord(addr, _settings.BigEndian);
if (_settings.Type == Watch.DisplayType.Signed) if (_settings.Type == Watch.DisplayType.Signed)
@ -749,7 +780,7 @@ namespace BizHawk.Client.Common
void Update(Watch.PreviousType type, MemoryDomain domain, bool bigendian); void Update(Watch.PreviousType type, MemoryDomain domain, bool bigendian);
} }
private class MiniByteWatch : IMiniWatch private sealed class MiniByteWatch : IMiniWatch
{ {
public int Address { get; private set; } public int Address { get; private set; }
private byte _previous; private byte _previous;
@ -771,7 +802,7 @@ namespace BizHawk.Client.Common
} }
} }
private class MiniWordWatch : IMiniWatch private sealed class MiniWordWatch : IMiniWatch
{ {
public int Address { get; private set; } public int Address { get; private set; }
private ushort _previous; private ushort _previous;
@ -793,7 +824,7 @@ namespace BizHawk.Client.Common
} }
} }
public class MiniDWordWatch : IMiniWatch public sealed class MiniDWordWatch : IMiniWatch
{ {
public int Address { get; private set; } public int Address { get; private set; }
private uint _previous; private uint _previous;
@ -818,8 +849,9 @@ namespace BizHawk.Client.Common
private sealed class MiniByteWatchDetailed : IMiniWatch, IMiniWatchDetails private sealed class MiniByteWatchDetailed : IMiniWatch, IMiniWatchDetails
{ {
public int Address { get; private set; } public int Address { get; private set; }
private byte _previous; private byte _previous;
int _changecount; private int _changecount;
public MiniByteWatchDetailed(MemoryDomain domain, int addr) public MiniByteWatchDetailed(MemoryDomain domain, int addr)
{ {
@ -844,7 +876,7 @@ namespace BizHawk.Client.Common
public void Update(Watch.PreviousType type, MemoryDomain domain, bool bigendian) public void Update(Watch.PreviousType type, MemoryDomain domain, bool bigendian)
{ {
byte value = domain.PeekByte(Address); var value = domain.PeekByte(Address);
if (value != Previous) if (value != Previous)
{ {
_changecount++; _changecount++;
@ -870,8 +902,9 @@ namespace BizHawk.Client.Common
private sealed class MiniWordWatchDetailed : IMiniWatch, IMiniWatchDetails private sealed class MiniWordWatchDetailed : IMiniWatch, IMiniWatchDetails
{ {
public int Address { get; private set; } public int Address { get; private set; }
private ushort _previous; private ushort _previous;
int _changecount; private int _changecount;
public MiniWordWatchDetailed(MemoryDomain domain, int addr, bool bigEndian) public MiniWordWatchDetailed(MemoryDomain domain, int addr, bool bigEndian)
{ {
@ -896,11 +929,12 @@ namespace BizHawk.Client.Common
public void Update(Watch.PreviousType type, MemoryDomain domain, bool bigendian) public void Update(Watch.PreviousType type, MemoryDomain domain, bool bigendian)
{ {
ushort value = domain.PeekWord(Address, bigendian); var value = domain.PeekWord(Address, bigendian);
if (value != Previous) if (value != Previous)
{ {
_changecount++; _changecount++;
} }
switch (type) switch (type)
{ {
case Watch.PreviousType.Original: case Watch.PreviousType.Original:
@ -921,8 +955,9 @@ namespace BizHawk.Client.Common
public sealed class MiniDWordWatchDetailed : IMiniWatch, IMiniWatchDetails public sealed class MiniDWordWatchDetailed : IMiniWatch, IMiniWatchDetails
{ {
public int Address { get; private set; } public int Address { get; private set; }
private uint _previous; private uint _previous;
int _changecount; private int _changecount;
public MiniDWordWatchDetailed(MemoryDomain domain, int addr, bool bigEndian) public MiniDWordWatchDetailed(MemoryDomain domain, int addr, bool bigEndian)
{ {
@ -947,11 +982,12 @@ namespace BizHawk.Client.Common
public void Update(Watch.PreviousType type, MemoryDomain domain, bool bigendian) public void Update(Watch.PreviousType type, MemoryDomain domain, bool bigendian)
{ {
uint value = domain.PeekDWord(Address, bigendian); var value = domain.PeekDWord(Address, bigendian);
if (value != Previous) if (value != Previous)
{ {
_changecount++; _changecount++;
} }
switch (type) switch (type)
{ {
case Watch.PreviousType.Original: case Watch.PreviousType.Original:
@ -974,15 +1010,15 @@ namespace BizHawk.Client.Common
/*Require restart*/ /*Require restart*/
public enum SearchMode { Fast, Detailed } public enum SearchMode { Fast, Detailed }
public SearchMode Mode; public SearchMode Mode { get; set; }
public MemoryDomain Domain; public MemoryDomain Domain { get; set; }
public Watch.WatchSize Size; public Watch.WatchSize Size { get; set; }
public bool CheckMisAligned; public bool CheckMisAligned { get; set; }
/*Can be changed mid-search*/ /*Can be changed mid-search*/
public Watch.DisplayType Type; public Watch.DisplayType Type { get; set; }
public bool BigEndian; public bool BigEndian { get; set; }
public Watch.PreviousType PreviousType; public Watch.PreviousType PreviousType { get; set; }
public Settings() public Settings()
{ {

View File

@ -1,6 +1,6 @@
using System; using System;
using System.Globalization;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using BizHawk.Common; using BizHawk.Common;
using BizHawk.Emulation.Common; using BizHawk.Emulation.Common;
@ -9,9 +9,9 @@ namespace BizHawk.Client.Common
{ {
public abstract class Watch public abstract class Watch
{ {
public enum WatchSize { Byte = 1, Word = 2, DWord = 4, Separator = 0 }; 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, Float }; public enum DisplayType { Separator, Signed, Unsigned, Hex, Binary, FixedPoint_12_4, FixedPoint_20_12, Float }
public enum PreviousType { Original = 0, LastSearch = 1, LastFrame = 2, LastChange = 3 }; public enum PreviousType { Original = 0, LastSearch = 1, LastFrame = 2, LastChange = 3 }
public static string DisplayTypeToString(DisplayType type) public static string DisplayTypeToString(DisplayType type)
{ {
@ -161,11 +161,11 @@ namespace BizHawk.Client.Common
{ {
if (_domain != null) if (_domain != null)
{ {
return "X" + IntHelpers.GetNumDigits(_domain.Size - 1).ToString(); return "X" + IntHelpers.GetNumDigits(this._domain.Size - 1);
} }
else else
{ {
return ""; return String.Empty;
} }
} }
} }
@ -350,6 +350,7 @@ namespace BizHawk.Client.Common
{ {
_type = type; _type = type;
} }
_bigEndian = bigEndian; _bigEndian = bigEndian;
if (notes != null) if (notes != null)
{ {
@ -452,6 +453,7 @@ namespace BizHawk.Client.Common
{ {
return false; return false;
} }
break; break;
case DisplayType.Signed: case DisplayType.Signed:
if (InputValidate.IsValidSignedNumber(value)) if (InputValidate.IsValidSignedNumber(value))
@ -462,6 +464,7 @@ namespace BizHawk.Client.Common
{ {
return false; return false;
} }
break; break;
case DisplayType.Hex: case DisplayType.Hex:
if (InputValidate.IsValidHexNumber(value)) if (InputValidate.IsValidHexNumber(value))
@ -472,6 +475,7 @@ namespace BizHawk.Client.Common
{ {
return false; return false;
} }
break; break;
case DisplayType.Binary: case DisplayType.Binary:
if (InputValidate.IsValidBinaryNumber(value)) if (InputValidate.IsValidBinaryNumber(value))
@ -482,6 +486,7 @@ namespace BizHawk.Client.Common
{ {
return false; return false;
} }
break; break;
} }
@ -498,8 +503,8 @@ namespace BizHawk.Client.Common
{ {
get get
{ {
string diff = String.Empty; var diff = String.Empty;
int diffVal = _value - _previous; var diffVal = _value - _previous;
if (diffVal > 0) if (diffVal > 0)
{ {
diff = "+"; diff = "+";
@ -508,6 +513,7 @@ namespace BizHawk.Client.Common
{ {
diff = "-"; diff = "-";
} }
return diff + FormatValue((byte)(_previous - _value)); return diff + FormatValue((byte)(_previous - _value));
} }
} }
@ -526,6 +532,7 @@ namespace BizHawk.Client.Common
_previous = _value; _previous = _value;
_changecount++; _changecount++;
} }
break; break;
case PreviousType.LastFrame: case PreviousType.LastFrame:
_previous = _value; _previous = _value;
@ -534,6 +541,7 @@ namespace BizHawk.Client.Common
{ {
_changecount++; _changecount++;
} }
break; break;
} }
} }
@ -554,6 +562,7 @@ namespace BizHawk.Client.Common
{ {
_type = type; _type = type;
} }
_bigEndian = bigEndian; _bigEndian = bigEndian;
if (notes != null) if (notes != null)
@ -627,7 +636,7 @@ namespace BizHawk.Client.Common
case DisplayType.Hex: case DisplayType.Hex:
return val.ToHexString(4); return val.ToHexString(4);
case DisplayType.FixedPoint_12_4: case DisplayType.FixedPoint_12_4:
return String.Format("{0:F4}", (val / 16.0)); return String.Format("{0:F4}", val / 16.0);
case DisplayType.Binary: case DisplayType.Binary:
return Convert.ToString(val, 2).PadLeft(16, '0').Insert(8, " ").Insert(4, " ").Insert(14, " "); return Convert.ToString(val, 2).PadLeft(16, '0').Insert(8, " ").Insert(4, " ").Insert(14, " ");
} }
@ -649,6 +658,7 @@ namespace BizHawk.Client.Common
{ {
return false; return false;
} }
break; break;
case DisplayType.Signed: case DisplayType.Signed:
if (InputValidate.IsValidSignedNumber(value)) if (InputValidate.IsValidSignedNumber(value))
@ -659,6 +669,7 @@ namespace BizHawk.Client.Common
{ {
return false; return false;
} }
break; break;
case DisplayType.Hex: case DisplayType.Hex:
if (InputValidate.IsValidHexNumber(value)) if (InputValidate.IsValidHexNumber(value))
@ -669,6 +680,7 @@ namespace BizHawk.Client.Common
{ {
return false; return false;
} }
break; break;
case DisplayType.Binary: case DisplayType.Binary:
if (InputValidate.IsValidBinaryNumber(value)) if (InputValidate.IsValidBinaryNumber(value))
@ -679,6 +691,7 @@ namespace BizHawk.Client.Common
{ {
return false; return false;
} }
break; break;
case DisplayType.FixedPoint_12_4: case DisplayType.FixedPoint_12_4:
if (InputValidate.IsValidFixedPointNumber(value)) if (InputValidate.IsValidFixedPointNumber(value))
@ -689,8 +702,10 @@ namespace BizHawk.Client.Common
{ {
return false; return false;
} }
break; break;
} }
PokeWord(val); PokeWord(val);
return true; return true;
} }
@ -720,6 +735,7 @@ namespace BizHawk.Client.Common
_previous = temp; _previous = temp;
_changecount++; _changecount++;
} }
break; break;
case PreviousType.LastFrame: case PreviousType.LastFrame:
_previous = _value; _previous = _value;
@ -728,6 +744,7 @@ namespace BizHawk.Client.Common
{ {
_changecount++; _changecount++;
} }
break; break;
} }
} }
@ -748,6 +765,7 @@ namespace BizHawk.Client.Common
{ {
_type = type; _type = type;
} }
_bigEndian = bigEndian; _bigEndian = bigEndian;
if (notes != null) if (notes != null)
@ -823,10 +841,10 @@ namespace BizHawk.Client.Common
case DisplayType.Hex: case DisplayType.Hex:
return val.ToHexString(8); return val.ToHexString(8);
case DisplayType.FixedPoint_20_12: case DisplayType.FixedPoint_20_12:
return String.Format("{0:0.######}", (val / 4096.0)); return String.Format("{0:0.######}", val / 4096.0);
case DisplayType.Float: case DisplayType.Float:
byte[] bytes = BitConverter.GetBytes(val); var bytes = BitConverter.GetBytes(val);
float _float = BitConverter.ToSingle(bytes, 0); var _float = BitConverter.ToSingle(bytes, 0);
return String.Format("{0:0.######}", _float); return String.Format("{0:0.######}", _float);
} }
} }
@ -847,6 +865,7 @@ namespace BizHawk.Client.Common
{ {
return false; return false;
} }
break; break;
case DisplayType.Signed: case DisplayType.Signed:
if (InputValidate.IsValidSignedNumber(value)) if (InputValidate.IsValidSignedNumber(value))
@ -857,6 +876,7 @@ namespace BizHawk.Client.Common
{ {
return false; return false;
} }
break; break;
case DisplayType.Hex: case DisplayType.Hex:
if (InputValidate.IsValidHexNumber(value)) if (InputValidate.IsValidHexNumber(value))
@ -867,6 +887,7 @@ namespace BizHawk.Client.Common
{ {
return false; return false;
} }
break; break;
case DisplayType.FixedPoint_20_12: case DisplayType.FixedPoint_20_12:
if (InputValidate.IsValidFixedPointNumber(value)) if (InputValidate.IsValidFixedPointNumber(value))
@ -877,19 +898,22 @@ namespace BizHawk.Client.Common
{ {
return false; return false;
} }
break; break;
case DisplayType.Float: case DisplayType.Float:
if (InputValidate.IsValidDecimalNumber(value)) if (InputValidate.IsValidDecimalNumber(value))
{ {
byte[] bytes = BitConverter.GetBytes(float.Parse(value)); var bytes = BitConverter.GetBytes(float.Parse(value));
val = BitConverter.ToUInt32(bytes, 0); val = BitConverter.ToUInt32(bytes, 0);
} }
else else
{ {
return false; return false;
} }
break; break;
} }
PokeDWord(val); PokeDWord(val);
return true; return true;
} }
@ -918,6 +942,7 @@ namespace BizHawk.Client.Common
_previous = _value; _previous = _value;
_changecount++; _changecount++;
} }
break; break;
case PreviousType.LastFrame: case PreviousType.LastFrame:
_previous = _value; _previous = _value;
@ -926,6 +951,7 @@ namespace BizHawk.Client.Common
{ {
_changecount++; _changecount++;
} }
break; break;
} }
} }

View File

@ -19,7 +19,7 @@ namespace BizHawk.Client.Common
public const string DOMAIN = "DomainColumn"; public const string DOMAIN = "DomainColumn";
public const string NOTES = "NotesColumn"; public const string NOTES = "NotesColumn";
public enum WatchPrevDef { LastSearch, Original, LastFrame, LastChange }; public enum WatchPrevDef { LastSearch, Original, LastFrame, LastChange }
private List<Watch> _watchList = new List<Watch>(); private List<Watch> _watchList = new List<Watch>();
private MemoryDomain _domain; private MemoryDomain _domain;
@ -86,6 +86,7 @@ namespace BizHawk.Client.Common
.ThenBy(x => x.BigEndian) .ThenBy(x => x.BigEndian)
.ToList(); .ToList();
} }
break; break;
case VALUE: case VALUE:
if (reverse) if (reverse)
@ -108,8 +109,9 @@ namespace BizHawk.Client.Common
.ThenBy(x => x.BigEndian) .ThenBy(x => x.BigEndian)
.ToList(); .ToList();
} }
break; break;
case PREV: //Note: these only work if all entries are detailed objects! case PREV: // Note: these only work if all entries are detailed objects!
if (reverse) if (reverse)
{ {
_watchList = _watchList _watchList = _watchList
@ -128,6 +130,7 @@ namespace BizHawk.Client.Common
.ThenBy(x => x.Type) .ThenBy(x => x.Type)
.ToList(); .ToList();
} }
break; break;
case DIFF: case DIFF:
if (reverse) if (reverse)
@ -148,6 +151,7 @@ namespace BizHawk.Client.Common
.ThenBy(x => x.Type) .ThenBy(x => x.Type)
.ToList(); .ToList();
} }
break; break;
case CHANGES: case CHANGES:
if (reverse) if (reverse)
@ -168,6 +172,7 @@ namespace BizHawk.Client.Common
.ThenBy(x => x.Type) .ThenBy(x => x.Type)
.ToList(); .ToList();
} }
break; break;
case DOMAIN: case DOMAIN:
if (reverse) if (reverse)
@ -190,6 +195,7 @@ namespace BizHawk.Client.Common
.ThenBy(x => x.BigEndian) .ThenBy(x => x.BigEndian)
.ToList(); .ToList();
} }
break; break;
case NOTES: case NOTES:
if (reverse) if (reverse)
@ -210,6 +216,7 @@ namespace BizHawk.Client.Common
.ThenBy(x => x.Type) .ThenBy(x => x.Type)
.ToList(); .ToList();
} }
break; break;
} }
} }
@ -220,7 +227,7 @@ namespace BizHawk.Client.Common
{ {
if (_domain != null) if (_domain != null)
{ {
return "{0:X" + IntHelpers.GetNumDigits(_domain.Size - 1).ToString() + "}"; return "{0:X" + IntHelpers.GetNumDigits(this._domain.Size - 1) + "}";
} }
else else
{ {
@ -260,11 +267,12 @@ namespace BizHawk.Client.Common
public bool Remove(Watch watch) public bool Remove(Watch watch)
{ {
bool result = _watchList.Remove(watch); var result = _watchList.Remove(watch);
if (result) if (result)
{ {
Changes = true; Changes = true;
} }
return result; return result;
} }
@ -317,7 +325,7 @@ namespace BizHawk.Client.Common
public bool Load(string path, bool append) public bool Load(string path, bool append)
{ {
bool result = LoadFile(path, append); var result = LoadFile(path, append);
if (result) if (result)
{ {
@ -339,7 +347,7 @@ namespace BizHawk.Client.Common
{ {
if (!String.IsNullOrWhiteSpace(CurrentFileName)) if (!String.IsNullOrWhiteSpace(CurrentFileName))
{ {
LoadFile(CurrentFileName, append:false); LoadFile(CurrentFileName, append: false);
Changes = false; Changes = false;
} }
} }
@ -351,22 +359,22 @@ namespace BizHawk.Client.Common
return false; return false;
} }
using (StreamWriter sw = new StreamWriter(CurrentFileName)) using (var sw = new StreamWriter(CurrentFileName))
{ {
StringBuilder sb = new StringBuilder(); var sb = new StringBuilder();
sb sb
.Append("Domain ").AppendLine(_domain.Name) .Append("Domain ").AppendLine(_domain.Name)
.Append("SystemID ").AppendLine(Global.Emulator.SystemId); .Append("SystemID ").AppendLine(Global.Emulator.SystemId);
foreach (Watch w in _watchList) foreach (var watch in _watchList)
{ {
sb sb
.Append(String.Format(AddressFormatStr, w.Address ?? 0)).Append('\t') .Append(String.Format(AddressFormatStr, watch.Address ?? 0)).Append('\t')
.Append(w.SizeAsChar).Append('\t') .Append(watch.SizeAsChar).Append('\t')
.Append(w.TypeAsChar).Append('\t') .Append(watch.TypeAsChar).Append('\t')
.Append(w.BigEndian ? '1' : '0').Append('\t') .Append(watch.BigEndian ? '1' : '0').Append('\t')
.Append(w.DomainName).Append('\t') .Append(watch.DomainName).Append('\t')
.Append(w.Notes) .Append(watch.Notes)
.AppendLine(); .AppendLine();
} }
@ -393,12 +401,16 @@ namespace BizHawk.Client.Common
private bool LoadFile(string path, bool append) private bool LoadFile(string path, bool append)
{ {
string domain = String.Empty; var domain = String.Empty;
var file = new FileInfo(path); var file = new FileInfo(path);
if (file.Exists == false) return false; if (file.Exists == false)
bool isBizHawkWatch = true; //Hack to support .wch files from other emulators {
bool isOldBizHawkWatch = false; return false;
using (StreamReader sr = file.OpenText()) }
var isBizHawkWatch = true; // Hack to support .wch files from other emulators
var isOldBizHawkWatch = false;
using (var sr = file.OpenText())
{ {
string line; string line;
@ -409,8 +421,8 @@ namespace BizHawk.Client.Common
while ((line = sr.ReadLine()) != null) 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 // .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 // 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) if (line.Length < 5)
{ {
isBizHawkWatch = false; isBizHawkWatch = false;
@ -428,38 +440,35 @@ namespace BizHawk.Client.Common
continue; continue;
} }
int numColumns = StringHelpers.HowMany(line, '\t'); var numColumns = StringHelpers.HowMany(line, '\t');
int startIndex; int startIndex;
if (numColumns == 5) if (numColumns == 5)
{ {
//If 5, then this is a post 1.0.5 .wch file // If 5, then this is a post 1.0.5 .wch file
if (isBizHawkWatch) if (isBizHawkWatch)
{ {
//Do nothing here // Do nothing here
} }
else else
{ {
startIndex = line.IndexOf('\t') + 1; startIndex = line.IndexOf('\t') + 1;
line = line.Substring(startIndex, line.Length - startIndex); //5 digit value representing the watch position number line = line.Substring(startIndex, line.Length - startIndex); // 5 digit value representing the watch position number
} }
} }
else if (numColumns == 4) else if (numColumns == 4)
{ {
isOldBizHawkWatch = true; isOldBizHawkWatch = true;
} }
else //4 is 1.0.5 and earlier else // 4 is 1.0.5 and earlier
{ {
continue; //If not 4, something is wrong with this line, ignore it continue; // If not 4, something is wrong with this line, ignore it
} }
// Temporary, rename if kept
//Temporary, rename if kept
int addr; int addr;
bool bigEndian; var memDomain = Global.Emulator.MemoryDomains.MainMemory;
MemoryDomain memDomain = Global.Emulator.MemoryDomains.MainMemory;
string temp = line.Substring(0, line.IndexOf('\t')); var temp = line.Substring(0, line.IndexOf('\t'));
try try
{ {
addr = Int32.Parse(temp, NumberStyles.HexNumber); addr = Int32.Parse(temp, NumberStyles.HexNumber);
@ -470,16 +479,15 @@ namespace BizHawk.Client.Common
} }
startIndex = line.IndexOf('\t') + 1; startIndex = line.IndexOf('\t') + 1;
line = line.Substring(startIndex, line.Length - startIndex); //Type line = line.Substring(startIndex, line.Length - startIndex); // Type
Watch.WatchSize size = Watch.SizeFromChar(line[0]); var size = Watch.SizeFromChar(line[0]);
startIndex = line.IndexOf('\t') + 1; startIndex = line.IndexOf('\t') + 1;
line = line.Substring(startIndex, line.Length - startIndex); //Signed line = line.Substring(startIndex, line.Length - startIndex); // Signed
Watch.DisplayType type = Watch.DisplayTypeFromChar(line[0]); var type = Watch.DisplayTypeFromChar(line[0]);
startIndex = line.IndexOf('\t') + 1; startIndex = line.IndexOf('\t') + 1;
line = line.Substring(startIndex, line.Length - startIndex); //Endian line = line.Substring(startIndex, line.Length - startIndex); // Endian
try try
{ {
startIndex = Int16.Parse(line[0].ToString()); startIndex = Int16.Parse(line[0].ToString());
@ -488,25 +496,19 @@ namespace BizHawk.Client.Common
{ {
continue; continue;
} }
if (startIndex == 0)
{ var bigEndian = startIndex != 0;
bigEndian = false;
}
else
{
bigEndian = true;
}
if (isBizHawkWatch && !isOldBizHawkWatch) if (isBizHawkWatch && !isOldBizHawkWatch)
{ {
startIndex = line.IndexOf('\t') + 1; startIndex = line.IndexOf('\t') + 1;
line = line.Substring(startIndex, line.Length - startIndex); //Domain line = line.Substring(startIndex, line.Length - startIndex); // Domain
temp = line.Substring(0, line.IndexOf('\t')); temp = line.Substring(0, line.IndexOf('\t'));
memDomain = Global.Emulator.MemoryDomains[temp] ?? Global.Emulator.MemoryDomains.MainMemory; memDomain = Global.Emulator.MemoryDomains[temp] ?? Global.Emulator.MemoryDomains.MainMemory;
} }
startIndex = line.IndexOf('\t') + 1; startIndex = line.IndexOf('\t') + 1;
string notes = line.Substring(startIndex, line.Length - startIndex); var notes = line.Substring(startIndex, line.Length - startIndex);
_watchList.Add( _watchList.Add(
Watch.GenerateWatch( Watch.GenerateWatch(
@ -531,6 +533,7 @@ namespace BizHawk.Client.Common
{ {
Changes = true; Changes = true;
} }
return true; return true;
} }