diff --git a/src/HexManiac.Core/Core/Autos/StubDataModel.cs b/src/HexManiac.Core/Core/Autos/StubDataModel.cs index b4484c07..2b9a058d 100644 --- a/src/HexManiac.Core/Core/Autos/StubDataModel.cs +++ b/src/HexManiac.Core/Core/Autos/StubDataModel.cs @@ -8,6 +8,8 @@ namespace HavenSoft.HexManiac.Core.Models { public class StubDataModel : IDataModel { + public event EventHandler LogMessage; + public Func HasChanged { get; set; } bool IDataModel.HasChanged(int index) diff --git a/src/HexManiac.Core/Models/IDataModel.cs b/src/HexManiac.Core/Models/IDataModel.cs index 513e6e7e..0f36574d 100644 --- a/src/HexManiac.Core/Models/IDataModel.cs +++ b/src/HexManiac.Core/Models/IDataModel.cs @@ -18,6 +18,8 @@ namespace HavenSoft.HexManiac.Core.Models { /// Task InitializationWorkload { get; } + event EventHandler? LogMessage; + byte[] RawData { get; } ModelCacheScope CurrentCacheScope { get; } int ReferenceCount { get; set; } @@ -134,6 +136,9 @@ namespace HavenSoft.HexManiac.Core.Models { public Task InitializationWorkload { get; protected set; } + public event EventHandler? LogMessage; + protected void RaiseLogMessage(string message) => LogMessage?.Invoke(this, message); + public byte[] RawData { get; private set; } private ModelCacheScope currentCacheScope; diff --git a/src/HexManiac.Core/Models/PokemonModel.cs b/src/HexManiac.Core/Models/PokemonModel.cs index bf33a918..ac5e8836 100644 --- a/src/HexManiac.Core/Models/PokemonModel.cs +++ b/src/HexManiac.Core/Models/PokemonModel.cs @@ -2703,6 +2703,9 @@ namespace HavenSoft.HexManiac.Core.Models { } private T MoveRun(ModelDelta changeToken, T run, int length, int newStart) where T : IFormattedRun { + var logName = run.Start.ToAddress(); + if (anchorForAddress.TryGetValue(run.Start, out var existingAnchorName)) logName = existingAnchorName; + RaiseLogMessage($"Moving {run.GetType().Name} {logName} to {newStart.ToAddress()}"); // repoint foreach (var source in run.PointerSources?.ToList() ?? new()) { // special update for pointers to this run that live within this run diff --git a/src/HexManiac.Core/ViewModels/Map/MapEditorViewModel.cs b/src/HexManiac.Core/ViewModels/Map/MapEditorViewModel.cs index a605dd6a..1e885179 100644 --- a/src/HexManiac.Core/ViewModels/Map/MapEditorViewModel.cs +++ b/src/HexManiac.Core/ViewModels/Map/MapEditorViewModel.cs @@ -361,6 +361,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map { } public void NavigateTo(int bank, int map, int x, int y) { + viewPort.Tools.LogTool.LogMessages.Add($"Navigate to ({x}, {y}) in map {bank}.{map}"); if (primaryMap != null) { backStack.Add(primaryMap.MapID); if (backStack.Count == 1) backCommand.RaiseCanExecuteChanged(); diff --git a/src/HexManiac.Core/ViewModels/ViewPort.cs b/src/HexManiac.Core/ViewModels/ViewPort.cs index 84a69a63..5e1c4653 100644 --- a/src/HexManiac.Core/ViewModels/ViewPort.cs +++ b/src/HexManiac.Core/ViewModels/ViewPort.cs @@ -221,7 +221,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels { dispatcher.BlockOnUIWork(() => { TabChangeRequestedEventArgs args; if (arg is string str) { - tools.LogTool.LogMessages.Add("Attempting to Goto Token: " + str); + tools?.LogTool.LogMessages.Add("Attempting to Goto Token: " + str); var possibleMatches = Model.GetExtendedAutocompleteOptions(str); if (possibleMatches.Count == 1) str = possibleMatches[0]; else if (possibleMatches.Count > 1 && possibleMatches.All(match => Model.GetMatchedWords(match).Any())) str = possibleMatches[0]; @@ -310,7 +310,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels { } if (arg is int address) { - tools.LogTool.LogMessages.Add("Attempting to Goto Address: " + address.ToString()); + tools?.LogTool.LogMessages.Add("Attempting to Goto Address: " + address.ToString()); } selection.Goto.Execute(arg); @@ -1102,6 +1102,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels { if (this is not ChildViewPort) { // child viewports don't need tools tools = new ToolTray(Singletons, Model, selection, history, this); + tools.LogTool.LogMessages.Add($"Start of session {Name} - {DateTime.Now}"); Tools.OnError += (sender, e) => OnError?.Invoke(this, e); Tools.OnMessage += (sender, e) => RaiseMessage(e); tools.RequestMenuClose += (sender, e) => RequestMenuClose?.Invoke(this, e); @@ -1111,6 +1112,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels { Tools.TableTool.ModelDataMoved += ModelDataMovedByTool; Tools.CodeTool.ModelDataChanged += ModelChangedByCodeTool; Tools.CodeTool.ModelDataMoved += ModelDataMovedByTool; + model.LogMessage += (sender, e) => tools.LogTool.LogMessages.Add(e); scroll.Scheduler = tools; } diff --git a/src/HexManiac.WPF/Windows/MainWindow.xaml.cs b/src/HexManiac.WPF/Windows/MainWindow.xaml.cs index a9ac27ba..ef0de7fb 100644 --- a/src/HexManiac.WPF/Windows/MainWindow.xaml.cs +++ b/src/HexManiac.WPF/Windows/MainWindow.xaml.cs @@ -6,6 +6,7 @@ using HavenSoft.HexManiac.Core.Models.Runs.Sprites; using HavenSoft.HexManiac.Core.ViewModels; using HavenSoft.HexManiac.Core.ViewModels.Map; using HavenSoft.HexManiac.Core.ViewModels.QuickEditItems; +using HavenSoft.HexManiac.Core.ViewModels.Tools; using HavenSoft.HexManiac.WPF.Controls; using HavenSoft.HexManiac.WPF.Implementations; using System; @@ -97,6 +98,15 @@ namespace HavenSoft.HexManiac.WPF.Windows { text.AppendLine(DateTime.Now.ToString()); text.AppendLine("General Information:"); AppendGeneralAppInfo(text); + var logLines = new List(); + if (ViewModel.SelectedTab is IViewPort vp && vp.Tools is ToolTray tray && tray.LogTool is LogTool logs) { + text.AppendLine("Recent Log Information:"); + logLines.AddRange(logs.LogMessages); + } else if (ViewModel.SelectedTab is MapEditorViewModel mapEditor && mapEditor.ViewPort.Tools is ToolTray mapTray && mapTray.LogTool is LogTool mapLogs) { + logLines.AddRange(mapLogs.LogMessages); + } + while (logLines.Count > 15) logLines.RemoveAt(1); + if (logLines.Count > 0) text.AppendLine(Environment.NewLine.Join(logLines)); text.AppendLine("Exception Information:"); AppendException(text, e.Exception); text.AppendLine("-------------------------------------------"); @@ -104,7 +114,7 @@ namespace HavenSoft.HexManiac.WPF.Windows { File.AppendAllText("crash.log", text.ToString()); var editor = DataContext as EditorViewModel; var tabCount = editor?.Count ?? 0; - var shortError = Environment.NewLine.Join(text.ToString().SplitLines().Take(15 + tabCount * 5)); + var shortError = Environment.NewLine.Join(text.ToString().SplitLines().Take(15 + tabCount * 5 + logLines.Count)); shortError = Environment.NewLine.Join(new[] { $"~I got a crash! ({ViewModel.Singletons.MetadataInfo.VersionNumber})", "```", @@ -766,14 +776,23 @@ namespace HavenSoft.HexManiac.WPF.Windows { Debugger.Break(); break; } else { + string logs = string.Empty; + if (Application.Current.MainWindow is MainWindow window && window.ViewModel is EditorViewModel editor) { + if (editor.SelectedTab is IViewPort viewPort && viewPort.Tools is ToolTray tray && tray.LogTool is LogTool logTool) { + logs = Environment.NewLine.Join(logTool.LogMessages); + } else if (editor.SelectedTab is MapEditorViewModel mapEditor && mapEditor.ViewPort.Tools is ToolTray mapTray && mapTray.LogTool is LogTool mapLogTool) { + logs = Environment.NewLine.Join(mapLogTool.LogMessages); + } + } Application.Current.Dispatcher.Invoke(() => { result = fileSystem.ShowOptions( "Attach a Debugger", "Attach a debugger and click 'Debug' to get more information about the following assertion:" + Environment.NewLine + message + Environment.NewLine + detailMessage + Environment.NewLine + - "To report the assert, copy & paste the stack trace to the Discord's #hma-bug-reports channel." + + "To report the assert, copy & paste the stack trace to the Discord's #hma-bug-reports channel." + Environment.NewLine + Environment.NewLine + + logs + Environment.NewLine + "Stack Trace:" + Environment.NewLine + Environment.StackTrace, null,