diff --git a/Source/SM64 Diagnostic/Controls/ObjectSlot.cs b/Source/SM64 Diagnostic/Controls/ObjectSlot.cs index e4088bb24..e9c2b6ec5 100644 --- a/Source/SM64 Diagnostic/Controls/ObjectSlot.cs +++ b/Source/SM64 Diagnostic/Controls/ObjectSlot.cs @@ -37,7 +37,7 @@ public class ObjectSlot : Panel public enum MouseStateType {None, Over, Down}; public MouseStateType MouseState; - public bool Selected + public bool SelectedOnMap { get { @@ -105,6 +105,7 @@ public Color TextColor { _textBrush.Color = value; } + Invalidate(); } } diff --git a/Source/SM64 Diagnostic/Managers/ObjectSlotsManager.cs b/Source/SM64 Diagnostic/Managers/ObjectSlotsManager.cs index 2889100b2..f17f24ae5 100644 --- a/Source/SM64 Diagnostic/Managers/ObjectSlotsManager.cs +++ b/Source/SM64 Diagnostic/Managers/ObjectSlotsManager.cs @@ -14,7 +14,19 @@ namespace SM64_Diagnostic.Managers { public class ObjectSlotsManager { + public class ObjectSlotData + { + public uint Address; + public byte ObjectProcessGroup; + public int ProcessIndex; + public int? VacantSlotIndex; + public float DistanceToMario; + public bool IsActive; + public uint Behavior; + } + const int DefaultSlotSize = 36; + public ObjectSlot[] ObjectSlots; public ObjectAssociations ObjectAssoc; @@ -28,7 +40,8 @@ public class ObjectSlotsManager Dictionary _mapObjects = new Dictionary(); Dictionary _memoryAddressSlotIndex; - Dictionary _lastSlotLabel = new Dictionary(); + Dictionary> _lastSlotLabel = new Dictionary>(); + bool _labelsLocked = false; public List SelectedSlotsAddresses = new List(); List _toggleMapGroups = new List(); @@ -146,7 +159,7 @@ private void OnSlotClick(object sender, EventArgs e) else _toggleMapSlots.Add(selectedSlot.Address); - UpdateSelectedObjectSlots(); + UpdateSelectedMapObjectSlots(); break; case MapToggleModeType.ObjectType: @@ -156,7 +169,7 @@ private void OnSlotClick(object sender, EventArgs e) else _toggleMapBehaviors.Add(behavior); - UpdateSelectedObjectSlots(); + UpdateSelectedMapObjectSlots(); break; case MapToggleModeType.ProcessGroup: @@ -166,22 +179,22 @@ private void OnSlotClick(object sender, EventArgs e) else _toggleMapGroups.Add(group); - UpdateSelectedObjectSlots(); + UpdateSelectedMapObjectSlots(); break; } break; } } - public void SetAllSelectedObjectSlots() + public void SetAllSelectedMapObjectSlots() { foreach (var objSlot in ObjectSlots) { - objSlot.Selected = true; + objSlot.SelectedOnMap = true; } } - public void UpdateSelectedObjectSlots() + public void UpdateSelectedMapObjectSlots() { foreach (var objSlot in ObjectSlots) { @@ -189,7 +202,7 @@ public void UpdateSelectedObjectSlots() && !_toggleMapBehaviors.Contains(objSlot.Behavior) && !_toggleMapSlots.Contains(objSlot.Address); - objSlot.Selected = selected; + objSlot.SelectedOnMap = selected; } } @@ -238,7 +251,6 @@ private List GetProcessedObjects(ObjectGroupsConfig groupConfig, // Loop through every object within the group while ((currentGroupObject != processGroupStructAddress && currentSlot < slotConfig.MaxSlots)) { - // Validate current object if (_stream.GetUInt16(currentGroupObject + Config.ObjectSlots.HeaderOffset) != 0x18) return null; @@ -290,7 +302,6 @@ public void Update() var slotConfig = Config.ObjectSlots; var newObjectSlotData = GetProcessedObjects(groupConfig, slotConfig); - if (newObjectSlotData == null) return; @@ -361,10 +372,18 @@ public void Update() : s.DistanceToMario).First().Address; // Update slots + UpdateSlots(newObjectSlotData); + } + + private void UpdateSlots(List newObjectSlotData) + { + // Lock label update + _labelsLocked = ManagerGui.LockLabelsCheckbox.Checked; + BehaviorCriteria? multiBehavior = null; List selectedBehaviorCriterias = new List(); bool firstObject = true; - for (int i = 0; i < slotConfig.MaxSlots; i++) + for (int i = 0; i < Config.ObjectSlots.MaxSlots; i++) { var behaviorCritera = UpdateSlot(newObjectSlotData[i], ObjectSlots[i]); if (!SelectedSlotsAddresses.Contains(newObjectSlotData[i].Address)) @@ -477,6 +496,9 @@ private BehaviorCriteria UpdateSlot(ObjectSlotData objData, ObjectSlot objSlot) Config.ObjectGroups.ProcessingGroupsColor[objData.ObjectProcessGroup]; objSlot.BackColor = newColor; + if (!_labelsLocked) + _lastSlotLabel[objAddress] = new Tuple(objData.ProcessIndex, objData.VacantSlotIndex); + string labelText = ""; switch ((SlotLabelType)ManagerGui.LabelMethodComboBox.SelectedItem) { @@ -492,28 +514,22 @@ private BehaviorCriteria UpdateSlot(ObjectSlotData objData, ObjectSlot objSlot) break; case SlotLabelType.SlotPos: - labelText = String.Format("{0}", objData.ProcessIndex + labelText = String.Format("{0}", _lastSlotLabel[objAddress].Item1 + (Config.SlotIndexsFromOne ? 1 : 0)); break; case SlotLabelType.SlotPosVs: - if (!objData.VacantSlotIndex.HasValue) + var vacantSlotIndex = _lastSlotLabel[objAddress].Item2; + if (!vacantSlotIndex.HasValue) goto case SlotLabelType.SlotPos; - labelText = String.Format("VS{0}", objData.VacantSlotIndex.Value + labelText = String.Format("VS{0}", vacantSlotIndex.Value + (Config.SlotIndexsFromOne ? 1 : 0)); break; } - if (ManagerGui.LockLabelsCheckbox.Checked) - { - if (!_lastSlotLabel.ContainsKey(objAddress)) - _lastSlotLabel.Add(objAddress, labelText); - else - _lastSlotLabel[objAddress] = labelText; - } - objSlot.TextColor = ManagerGui.LockLabelsCheckbox.Checked ? Color.Red : Color.Blue; - objSlot.Text = ManagerGui.LockLabelsCheckbox.Checked ? _lastSlotLabel[objAddress] : labelText; + objSlot.TextColor = _labelsLocked ? Color.Red : Color.Blue; + objSlot.Text = labelText; // Update object manager image if (SelectedSlotsAddresses.Count <= 1 && SelectedSlotsAddresses.Contains(objAddress)) diff --git a/Source/SM64 Diagnostic/SM64 Diagnostic.csproj b/Source/SM64 Diagnostic/SM64 Diagnostic.csproj index d40ca5f29..faf70d739 100644 --- a/Source/SM64 Diagnostic/SM64 Diagnostic.csproj +++ b/Source/SM64 Diagnostic/SM64 Diagnostic.csproj @@ -159,7 +159,6 @@ - diff --git a/Source/SM64 Diagnostic/StroopMainForm.Designer.cs b/Source/SM64 Diagnostic/StroopMainForm.Designer.cs index ad48761b9..a05656bdc 100644 --- a/Source/SM64 Diagnostic/StroopMainForm.Designer.cs +++ b/Source/SM64 Diagnostic/StroopMainForm.Designer.cs @@ -2251,7 +2251,6 @@ private void InitializeComponent() this.Margin = new System.Windows.Forms.Padding(2); this.Name = "StroopMainForm"; this.Text = "STROOP"; - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.StroopMainForm_FormClosing); this.Load += new System.EventHandler(this.StroopMainForm_Load); this.groupBoxObjects.ResumeLayout(false); this.groupBoxObjects.PerformLayout(); diff --git a/Source/SM64 Diagnostic/StroopMainForm.cs b/Source/SM64 Diagnostic/StroopMainForm.cs index 27bc77937..acfc87159 100644 --- a/Source/SM64 Diagnostic/StroopMainForm.cs +++ b/Source/SM64 Diagnostic/StroopMainForm.cs @@ -82,6 +82,7 @@ private void StroopMainForm_Load(object sender, EventArgs e) _sm64Stream.FpsUpdated += _sm64Stream_FpsUpdated; _sm64Stream.OnDisconnect += _sm64Stream_OnDisconnect; _sm64Stream.WarnReadonlyOff += _sm64Stream_WarnReadonlyOff; + _sm64Stream.OnClose += _sm64Stream_OnClose; currentContext.DisassemblyManager = _disManager = new DisassemblyManager(_sm64Stream, tabPageDisassembly); currentContext.ScriptManager = _scriptManager = new ScriptManager(_sm64Stream, _scriptParser, checkBoxUseRomHack); @@ -160,7 +161,7 @@ private void StroopMainForm_Load(object sender, EventArgs e) private void _sm64Stream_WarnReadonlyOff(object sender, EventArgs e) { - this.Invoke(new Action(() => + Invoke(new Action(() => { var dr = MessageBox.Show("Warning! Editing variables and enabling hacks may cause the emulator to freeze. Turn off read-only mode?", "Turn Off Read-only Mode?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning); @@ -184,7 +185,7 @@ private void _sm64Stream_WarnReadonlyOff(object sender, EventArgs e) private void _sm64Stream_OnDisconnect(object sender, EventArgs e) { - this.Invoke(new Action(() => { + this.BeginInvoke(new Action(() => { buttonRefresh_Click(this, new EventArgs()); panelConnect.Visible = true; })); @@ -258,7 +259,7 @@ private void OnUpdate(object sender, EventArgs e) private void _sm64Stream_FpsUpdated(object sender, EventArgs e) { - Invoke(new Action(() => + BeginInvoke(new Action(() => { labelFpsCounter.Text = "FPS: " + (int)_sm64Stream.Fps; })); @@ -429,9 +430,22 @@ await Task.Run(() => { _mapManager.Load(); } - private void StroopMainForm_FormClosing(object sender, FormClosingEventArgs e) + protected override void OnFormClosing(FormClosingEventArgs e) + { + if (_sm64Stream.IsRunning) + { + _sm64Stream.Stop(); + e.Cancel = true; + Hide(); + return; + } + + base.OnFormClosing(e); + } + + private void _sm64Stream_OnClose(object sender, EventArgs e) { - _sm64Stream.Stop(); + Invoke(new Action(() => Close())); } private void buttonCollapseBottom_Click(object sender, EventArgs e) @@ -526,13 +540,13 @@ private void tabControlMain_SelectedIndexChanged(object sender, EventArgs e) { if (tabControlMain.SelectedTab == tabPageMap) { - _objectSlotManager.UpdateSelectedObjectSlots(); + _objectSlotManager.UpdateSelectedMapObjectSlots(); comboBoxMapToggleMode.Visible = true; labelToggleMode.Visible = true; } else { - _objectSlotManager.SetAllSelectedObjectSlots(); + _objectSlotManager.SetAllSelectedMapObjectSlots(); comboBoxMapToggleMode.Visible = false; labelToggleMode.Visible = false; } diff --git a/Source/SM64 Diagnostic/Structs/ObjectSlotData.cs b/Source/SM64 Diagnostic/Structs/ObjectSlotData.cs deleted file mode 100644 index d5ba74d74..000000000 --- a/Source/SM64 Diagnostic/Structs/ObjectSlotData.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Drawing; - -namespace SM64_Diagnostic.Structs -{ - public class ObjectSlotData - { - public uint Address; - public byte ObjectProcessGroup; - public int ProcessIndex; - public int? VacantSlotIndex; - public float DistanceToMario; - public bool IsActive; - public uint Behavior; - } -} diff --git a/Source/SM64 Diagnostic/Utilities/ProcessStream.cs b/Source/SM64 Diagnostic/Utilities/ProcessStream.cs index 94e32ee67..c7d52c483 100644 --- a/Source/SM64 Diagnostic/Utilities/ProcessStream.cs +++ b/Source/SM64 Diagnostic/Utilities/ProcessStream.cs @@ -9,6 +9,7 @@ using SM64_Diagnostic.Structs; using System.Threading; using System.IO; +using System.ComponentModel; namespace SM64_Diagnostic.Utilities { @@ -18,20 +19,19 @@ public class ProcessStream IntPtr _processHandle; Process _process; Queue _fpsTimes = new Queue(); - Task _streamUpdater; + BackgroundWorker _streamUpdater; byte[] _ram; bool _lastUpdateBeforePausing = false; int _interval; object _enableLocker = new object(); object _fpsQueueLocker = new object(); - CancellationTokenSource _cancelToken = new CancellationTokenSource(); - public event EventHandler OnUpdate; public event EventHandler OnStatusChanged; public event EventHandler OnDisconnect; public event EventHandler FpsUpdated; public event EventHandler WarnReadonlyOff; + public event EventHandler OnClose; public bool Readonly = true; public bool ShowWarning = true; @@ -86,7 +86,7 @@ public Boolean IsRunning bool running; lock(_enableLocker) { - running = !(IsSuspended || IsClosed || !IsEnabled); + running = !(IsSuspended || IsClosed || !IsEnabled || !_streamUpdater.IsBusy); } return running; } @@ -99,17 +99,22 @@ public ProcessStream(Process process = null, Emulator emulator = null) _interval = (int) (1000.0f / Config.RefreshRateFreq); _ram = new byte[Config.RamSize]; - _streamUpdater = new Task(() => ProcessUpdateTask(_cancelToken.Token), _cancelToken.Token); - _streamUpdater.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted); - _streamUpdater.Start(); + _streamUpdater = new BackgroundWorker(); + _streamUpdater.DoWork += ProcessUpdateTask; + _streamUpdater.WorkerSupportsCancellation = true; + _streamUpdater.RunWorkerAsync(); SwitchProcess(_process, _emulator); } private void LogException(Exception e) { - File.AppendAllText("error.txt", String.Format("{0}\n{1}\n{2}\n{3}\n", e.Message, - e.InnerException.ToString(), e.TargetSite.ToString(), e.StackTrace)); + try + { + var log = String.Format("{0}\n{1}\n{2}\n", e.Message, e.TargetSite.ToString(), e.StackTrace); + File.AppendAllText("error.txt", log); + } + catch (Exception) { } } private void ExceptionHandler(Task obj) @@ -123,16 +128,7 @@ private void ExceptionHandler(Task obj) if (_process != null) _process.Exited -= ProcessClosed; - _cancelToken?.Cancel(); - try - { - _streamUpdater?.Wait(); - } - catch (AggregateException) { } - finally - { - _cancelToken?.Dispose(); - } + _streamUpdater.CancelAsync(); } public bool SwitchProcess(Process newProcess, Emulator emulator) @@ -449,19 +445,21 @@ public bool WriteRam(byte[] buffer, uint address, int bufferStart = 0, int? leng public void Stop() { - _cancelToken?.Cancel(); - try - { - //_streamUpdater?.Wait(); - } - catch (AggregateException) { } + _streamUpdater.CancelAsync(); } - private void ProcessUpdateTask(CancellationToken ct) + private void ProcessUpdateTask(object sender, DoWorkEventArgs e) { + var worker = sender as BackgroundWorker; var prevTime = Stopwatch.StartNew(); - while (!ct.IsCancellationRequested) + while (!e.Cancel) { + if (worker.CancellationPending) + { + e.Cancel = true; + break; + } + prevTime.Restart(); if (!IsRunning & !_lastUpdateBeforePausing) goto FrameLimitStreamUpdate; @@ -480,9 +478,12 @@ private void ProcessUpdateTask(CancellationToken ct) foreach (var lockVar in LockedVariables) lockVar.Value.Update(); } - catch (Exception e) + catch (Exception ee) { - LogException(e); + LogException(ee); + MessageBox.Show("A Fatal Error has occured. See output.txt for details. The program will now exit.", + "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification); + break; } FrameLimitStreamUpdate: @@ -504,7 +505,7 @@ private void ProcessUpdateTask(CancellationToken ct) Task.Delay(timeToWait).Wait(); } - ct.ThrowIfCancellationRequested(); + OnClose?.BeginInvoke(this, new EventArgs(), null, null); } public int ConvertAddressEndianess(int address, int dataSize) diff --git a/Windows Build/Stroop.exe b/Windows Build/Stroop.exe index a840803fd..ec75cf75d 100644 Binary files a/Windows Build/Stroop.exe and b/Windows Build/Stroop.exe differ