mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 10:17:22 +01:00
replace nonfunctional managed asserts with proper imgui-handled assert mechanism
This commit is contained in:
parent
8773d3b873
commit
12bf2f4478
12 changed files with 238 additions and 207 deletions
|
|
@ -243,7 +243,7 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether or not ImGui asserts should be enabled at startup.
|
/// Gets or sets a value indicating whether or not ImGui asserts should be enabled at startup.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AssertsEnabledAtStartup { get; set; }
|
public bool? ImGuiAssertsEnabledAtStartup { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether or not docking should be globally enabled in ImGui.
|
/// Gets or sets a value indicating whether or not docking should be globally enabled in ImGui.
|
||||||
|
|
@ -605,6 +605,12 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
|
||||||
this.AutoUpdateBehavior ??= this.AutoUpdatePlugins
|
this.AutoUpdateBehavior ??= this.AutoUpdatePlugins
|
||||||
? Plugin.Internal.AutoUpdate.AutoUpdateBehavior.UpdateAll
|
? Plugin.Internal.AutoUpdate.AutoUpdateBehavior.UpdateAll
|
||||||
: Plugin.Internal.AutoUpdate.AutoUpdateBehavior.OnlyNotify;
|
: Plugin.Internal.AutoUpdate.AutoUpdateBehavior.OnlyNotify;
|
||||||
|
|
||||||
|
// Turn ImGui asserts on by default if we have any active dev plugins
|
||||||
|
if (!this.ImGuiAssertsEnabledAtStartup.HasValue && this.DevPluginLoadLocations.Any(x => x.IsEnabled))
|
||||||
|
{
|
||||||
|
this.ImGuiAssertsEnabledAtStartup = true;
|
||||||
|
}
|
||||||
#pragma warning restore CS0618
|
#pragma warning restore CS0618
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
177
Dalamud/Interface/Internal/AssertHandler.cs
Normal file
177
Dalamud/Interface/Internal/AssertHandler.cs
Normal file
|
|
@ -0,0 +1,177 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
using Dalamud.Utility;
|
||||||
|
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.Internal;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class responsible for registering and handling ImGui asserts.
|
||||||
|
/// </summary>
|
||||||
|
internal class AssertHandler : IDisposable
|
||||||
|
{
|
||||||
|
private readonly HashSet<string> ignoredAsserts = [];
|
||||||
|
|
||||||
|
// Store callback to avoid it from being GC'd
|
||||||
|
private readonly AssertCallbackDelegate callback;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AssertHandler"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public AssertHandler()
|
||||||
|
{
|
||||||
|
this.callback = (expr, file, line) => this.OnImGuiAssert(expr, file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
private delegate void AssertCallbackDelegate(
|
||||||
|
[MarshalAs(UnmanagedType.LPStr)] string expr,
|
||||||
|
[MarshalAs(UnmanagedType.LPStr)] string file,
|
||||||
|
int line);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether ImGui asserts should be shown to the user.
|
||||||
|
/// </summary>
|
||||||
|
public bool ShowAsserts { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register the cimgui assert handler with the native library.
|
||||||
|
/// </summary>
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
CustomNativeFunctions.igCustom_SetAssertCallback(this.callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unregister the cimgui assert handler with the native library.
|
||||||
|
/// </summary>
|
||||||
|
public void Shutdown()
|
||||||
|
{
|
||||||
|
CustomNativeFunctions.igCustom_SetAssertCallback(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
this.Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnImGuiAssert(string expr, string file, int line)
|
||||||
|
{
|
||||||
|
Log.Warning("ImGui assertion failed: {Expr} at {File}:{Line}", expr, file, line);
|
||||||
|
|
||||||
|
if (!this.ShowAsserts)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var key = $"{file}:{line}";
|
||||||
|
if (this.ignoredAsserts.Contains(key))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO: It would be nice to get unmanaged stack frames here, seems hard though without pulling that
|
||||||
|
// entire code in from the crash handler
|
||||||
|
var originalStackTrace = new StackTrace(2).ToString();
|
||||||
|
|
||||||
|
string? GetRepoUrl()
|
||||||
|
{
|
||||||
|
// TODO: implot, imguizmo?
|
||||||
|
const string userName = "goatcorp";
|
||||||
|
const string repoName = "gc-imgui";
|
||||||
|
const string branch = "1.88-enhanced-abifix";
|
||||||
|
|
||||||
|
if (!file.Contains("imgui", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var lastSlash = file.LastIndexOf('\\');
|
||||||
|
var fileName = file[(lastSlash + 1)..];
|
||||||
|
return $"https://github.com/{userName}/{repoName}/blob/{branch}/{fileName}#L{line}";
|
||||||
|
}
|
||||||
|
|
||||||
|
var gitHubUrl = GetRepoUrl();
|
||||||
|
var showOnGitHubButton = new TaskDialogButton
|
||||||
|
{
|
||||||
|
Text = "Show on GitHub",
|
||||||
|
AllowCloseDialog = false,
|
||||||
|
Enabled = !gitHubUrl.IsNullOrEmpty(),
|
||||||
|
};
|
||||||
|
showOnGitHubButton.Click += (_, _) =>
|
||||||
|
{
|
||||||
|
if (!gitHubUrl.IsNullOrEmpty())
|
||||||
|
Util.OpenLink(gitHubUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
var breakButton = new TaskDialogButton
|
||||||
|
{
|
||||||
|
Text = "Break",
|
||||||
|
AllowCloseDialog = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
var ignoreButton = TaskDialogButton.Ignore;
|
||||||
|
var abortButton = TaskDialogButton.Abort;
|
||||||
|
|
||||||
|
TaskDialogButton? result = null;
|
||||||
|
void DialogThreadStart()
|
||||||
|
{
|
||||||
|
// TODO(goat): This is probably not gonna work if we showed the loading dialog
|
||||||
|
// this session since it already loaded visual styles...
|
||||||
|
Application.EnableVisualStyles();
|
||||||
|
|
||||||
|
var page = new TaskDialogPage()
|
||||||
|
{
|
||||||
|
Heading = "ImGui assertion failed",
|
||||||
|
Caption = "Dalamud",
|
||||||
|
Expander = new TaskDialogExpander
|
||||||
|
{
|
||||||
|
CollapsedButtonText = "Show stack trace",
|
||||||
|
ExpandedButtonText = "Hide stack trace",
|
||||||
|
Text = originalStackTrace,
|
||||||
|
},
|
||||||
|
Text = $"Some code in a plugin or Dalamud itself has caused an internal assertion in ImGui to fail. The game will most likely crash now.\n\n{expr}\nAt: {file}:{line}",
|
||||||
|
Icon = TaskDialogIcon.Warning,
|
||||||
|
Buttons =
|
||||||
|
[
|
||||||
|
showOnGitHubButton,
|
||||||
|
breakButton,
|
||||||
|
ignoreButton,
|
||||||
|
abortButton,
|
||||||
|
],
|
||||||
|
DefaultButton = showOnGitHubButton,
|
||||||
|
};
|
||||||
|
|
||||||
|
result = TaskDialog.ShowDialog(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run in a separate thread because of STA and to not mess up other stuff
|
||||||
|
var thread = new Thread(DialogThreadStart)
|
||||||
|
{
|
||||||
|
Name = "Dalamud ImGui Assert Dialog",
|
||||||
|
};
|
||||||
|
thread.SetApartmentState(ApartmentState.STA);
|
||||||
|
thread.Start();
|
||||||
|
thread.Join();
|
||||||
|
|
||||||
|
if (result == breakButton)
|
||||||
|
{
|
||||||
|
Debugger.Break();
|
||||||
|
}
|
||||||
|
else if (result == abortButton)
|
||||||
|
{
|
||||||
|
Environment.Exit(-1);
|
||||||
|
}
|
||||||
|
else if (result == ignoreButton)
|
||||||
|
{
|
||||||
|
this.ignoredAsserts.Add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CustomNativeFunctions
|
||||||
|
{
|
||||||
|
[DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
#pragma warning disable SA1300
|
||||||
|
public static extern void igCustom_SetAssertCallback(AssertCallbackDelegate callback);
|
||||||
|
#pragma warning restore SA1300
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,7 +16,6 @@ using Dalamud.Game.Text;
|
||||||
using Dalamud.Hooking.WndProcHook;
|
using Dalamud.Hooking.WndProcHook;
|
||||||
using Dalamud.Interface.Colors;
|
using Dalamud.Interface.Colors;
|
||||||
using Dalamud.Interface.GameFonts;
|
using Dalamud.Interface.GameFonts;
|
||||||
using Dalamud.Interface.Internal.ManagedAsserts;
|
|
||||||
using Dalamud.Interface.ManagedFontAtlas.Internals;
|
using Dalamud.Interface.ManagedFontAtlas.Internals;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
|
|
||||||
|
|
@ -185,7 +184,7 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
||||||
return true;
|
return true;
|
||||||
if (!ImGui.GetIO().ConfigInputTextCursorBlink)
|
if (!ImGui.GetIO().ConfigInputTextCursorBlink)
|
||||||
return true;
|
return true;
|
||||||
var textState = TextState;
|
var textState = CustomNativeFunctions.igCustom_GetInputTextState();
|
||||||
if (textState->Id == 0 || (textState->Flags & ImGuiInputTextFlags.ReadOnly) != 0)
|
if (textState->Id == 0 || (textState->Flags & ImGuiInputTextFlags.ReadOnly) != 0)
|
||||||
return true;
|
return true;
|
||||||
if (textState->CursorAnim <= 0)
|
if (textState->CursorAnim <= 0)
|
||||||
|
|
@ -194,9 +193,6 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ImGuiInputTextState* TextState =>
|
|
||||||
(ImGuiInputTextState*)(ImGui.GetCurrentContext() + ImGuiContextOffsets.TextStateOffset);
|
|
||||||
|
|
||||||
/// <summary>Gets a value indicating whether to display partial conversion status.</summary>
|
/// <summary>Gets a value indicating whether to display partial conversion status.</summary>
|
||||||
private bool ShowPartialConversion => this.partialConversionFrom != 0 ||
|
private bool ShowPartialConversion => this.partialConversionFrom != 0 ||
|
||||||
this.partialConversionTo != this.compositionString.Length;
|
this.partialConversionTo != this.compositionString.Length;
|
||||||
|
|
@ -341,7 +337,8 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var invalidTarget = TextState->Id == 0 || (TextState->Flags & ImGuiInputTextFlags.ReadOnly) != 0;
|
var textState = CustomNativeFunctions.igCustom_GetInputTextState();
|
||||||
|
var invalidTarget = textState->Id == 0 || (textState->Flags & ImGuiInputTextFlags.ReadOnly) != 0;
|
||||||
|
|
||||||
#if IMEDEBUG
|
#if IMEDEBUG
|
||||||
switch (args.Message)
|
switch (args.Message)
|
||||||
|
|
@ -570,19 +567,20 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
||||||
|
|
||||||
this.ReflectCharacterEncounters(newString);
|
this.ReflectCharacterEncounters(newString);
|
||||||
|
|
||||||
|
var textState = CustomNativeFunctions.igCustom_GetInputTextState();
|
||||||
if (this.temporaryUndoSelection is not null)
|
if (this.temporaryUndoSelection is not null)
|
||||||
{
|
{
|
||||||
TextState->Undo();
|
textState->Undo();
|
||||||
TextState->SelectionTuple = this.temporaryUndoSelection.Value;
|
textState->SelectionTuple = this.temporaryUndoSelection.Value;
|
||||||
this.temporaryUndoSelection = null;
|
this.temporaryUndoSelection = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextState->SanitizeSelectionRange();
|
textState->SanitizeSelectionRange();
|
||||||
if (TextState->ReplaceSelectionAndPushUndo(newString))
|
if (textState->ReplaceSelectionAndPushUndo(newString))
|
||||||
this.temporaryUndoSelection = TextState->SelectionTuple;
|
this.temporaryUndoSelection = textState->SelectionTuple;
|
||||||
|
|
||||||
// Put the cursor at the beginning, so that the candidate window appears aligned with the text.
|
// Put the cursor at the beginning, so that the candidate window appears aligned with the text.
|
||||||
TextState->SetSelectionRange(TextState->SelectionTuple.Start, newString.Length, 0);
|
textState->SetSelectionRange(textState->SelectionTuple.Start, newString.Length, 0);
|
||||||
|
|
||||||
if (finalCommit)
|
if (finalCommit)
|
||||||
{
|
{
|
||||||
|
|
@ -627,7 +625,10 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
||||||
this.partialConversionFrom = this.partialConversionTo = 0;
|
this.partialConversionFrom = this.partialConversionTo = 0;
|
||||||
this.compositionCursorOffset = 0;
|
this.compositionCursorOffset = 0;
|
||||||
this.temporaryUndoSelection = null;
|
this.temporaryUndoSelection = null;
|
||||||
TextState->Stb.SelectStart = TextState->Stb.Cursor = TextState->Stb.SelectEnd;
|
|
||||||
|
var textState = CustomNativeFunctions.igCustom_GetInputTextState();
|
||||||
|
textState->Stb.SelectStart = textState->Stb.Cursor = textState->Stb.SelectEnd;
|
||||||
|
|
||||||
this.candidateStrings.Clear();
|
this.candidateStrings.Clear();
|
||||||
this.immCandNative = default;
|
this.immCandNative = default;
|
||||||
if (invokeCancel)
|
if (invokeCancel)
|
||||||
|
|
@ -1113,6 +1114,14 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class CustomNativeFunctions
|
||||||
|
{
|
||||||
|
[DllImport("cimgui")]
|
||||||
|
#pragma warning disable SA1300
|
||||||
|
public static extern ImGuiInputTextState* igCustom_GetInputTextState();
|
||||||
|
#pragma warning restore SA1300
|
||||||
|
}
|
||||||
|
|
||||||
#if IMEDEBUG
|
#if IMEDEBUG
|
||||||
private static class ImeDebug
|
private static class ImeDebug
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ using Dalamud.Game.Internal;
|
||||||
using Dalamud.Hooking;
|
using Dalamud.Hooking;
|
||||||
using Dalamud.Interface.Animation.EasingFunctions;
|
using Dalamud.Interface.Animation.EasingFunctions;
|
||||||
using Dalamud.Interface.Colors;
|
using Dalamud.Interface.Colors;
|
||||||
using Dalamud.Interface.Internal.ManagedAsserts;
|
|
||||||
using Dalamud.Interface.Internal.Windows;
|
using Dalamud.Interface.Internal.Windows;
|
||||||
using Dalamud.Interface.Internal.Windows.Data;
|
using Dalamud.Interface.Internal.Windows.Data;
|
||||||
using Dalamud.Interface.Internal.Windows.PluginInstaller;
|
using Dalamud.Interface.Internal.Windows.PluginInstaller;
|
||||||
|
|
@ -163,7 +162,7 @@ internal class DalamudInterface : IInternalDisposableService
|
||||||
this.WindowSystem.AddWindow(this.branchSwitcherWindow);
|
this.WindowSystem.AddWindow(this.branchSwitcherWindow);
|
||||||
this.WindowSystem.AddWindow(this.hitchSettingsWindow);
|
this.WindowSystem.AddWindow(this.hitchSettingsWindow);
|
||||||
|
|
||||||
ImGuiManagedAsserts.AssertsEnabled = configuration.AssertsEnabledAtStartup;
|
this.interfaceManager.ShowAsserts = configuration.ImGuiAssertsEnabledAtStartup ?? false;
|
||||||
this.isImGuiDrawDevMenu = this.isImGuiDrawDevMenu || configuration.DevBarOpenAtStartup;
|
this.isImGuiDrawDevMenu = this.isImGuiDrawDevMenu || configuration.DevBarOpenAtStartup;
|
||||||
|
|
||||||
this.interfaceManager.Draw += this.OnDraw;
|
this.interfaceManager.Draw += this.OnDraw;
|
||||||
|
|
@ -832,6 +831,12 @@ internal class DalamudInterface : IInternalDisposableService
|
||||||
hook.Enable();
|
hook.Enable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ImGui.MenuItem("Cause ImGui assert"))
|
||||||
|
{
|
||||||
|
ImGui.PopStyleVar();
|
||||||
|
ImGui.PopStyleVar();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui.EndMenu();
|
ImGui.EndMenu();
|
||||||
}
|
}
|
||||||
|
|
@ -865,15 +870,16 @@ internal class DalamudInterface : IInternalDisposableService
|
||||||
|
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
|
|
||||||
var val = ImGuiManagedAsserts.AssertsEnabled;
|
var val = this.interfaceManager.ShowAsserts;
|
||||||
if (ImGui.MenuItem("Enable Asserts", string.Empty, ref val))
|
if (ImGui.MenuItem("Enable Asserts", string.Empty, ref val))
|
||||||
{
|
{
|
||||||
ImGuiManagedAsserts.AssertsEnabled = val;
|
this.interfaceManager.ShowAsserts = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui.MenuItem("Enable asserts at startup", null, this.configuration.AssertsEnabledAtStartup))
|
var assertsEnabled = this.configuration.ImGuiAssertsEnabledAtStartup ?? false;
|
||||||
|
if (ImGui.MenuItem("Enable asserts at startup", null, assertsEnabled))
|
||||||
{
|
{
|
||||||
this.configuration.AssertsEnabledAtStartup = !this.configuration.AssertsEnabledAtStartup;
|
this.configuration.ImGuiAssertsEnabledAtStartup = !assertsEnabled;
|
||||||
this.configuration.QueueSave();
|
this.configuration.QueueSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ using Dalamud.Hooking.WndProcHook;
|
||||||
using Dalamud.Interface.ImGuiNotification;
|
using Dalamud.Interface.ImGuiNotification;
|
||||||
using Dalamud.Interface.ImGuiNotification.Internal;
|
using Dalamud.Interface.ImGuiNotification.Internal;
|
||||||
using Dalamud.Interface.Internal.DesignSystem;
|
using Dalamud.Interface.Internal.DesignSystem;
|
||||||
using Dalamud.Interface.Internal.ManagedAsserts;
|
|
||||||
using Dalamud.Interface.Internal.ReShadeHandling;
|
using Dalamud.Interface.Internal.ReShadeHandling;
|
||||||
using Dalamud.Interface.ManagedFontAtlas;
|
using Dalamud.Interface.ManagedFontAtlas;
|
||||||
using Dalamud.Interface.ManagedFontAtlas.Internals;
|
using Dalamud.Interface.ManagedFontAtlas.Internals;
|
||||||
|
|
@ -93,6 +92,8 @@ internal partial class InterfaceManager : IInternalDisposableService
|
||||||
|
|
||||||
private readonly ConcurrentQueue<Action> runBeforeImGuiRender = new();
|
private readonly ConcurrentQueue<Action> runBeforeImGuiRender = new();
|
||||||
private readonly ConcurrentQueue<Action> runAfterImGuiRender = new();
|
private readonly ConcurrentQueue<Action> runAfterImGuiRender = new();
|
||||||
|
|
||||||
|
private readonly AssertHandler assertHandler = new();
|
||||||
|
|
||||||
private RawDX11Scene? scene;
|
private RawDX11Scene? scene;
|
||||||
|
|
||||||
|
|
@ -267,11 +268,20 @@ internal partial class InterfaceManager : IInternalDisposableService
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public long CumulativePresentCalls { get; private set; }
|
public long CumulativePresentCalls { get; private set; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="AssertHandler.ShowAsserts"/>
|
||||||
|
public bool ShowAsserts
|
||||||
|
{
|
||||||
|
get => this.assertHandler.ShowAsserts;
|
||||||
|
set => this.assertHandler.ShowAsserts = value;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dispose of managed and unmanaged resources.
|
/// Dispose of managed and unmanaged resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void IInternalDisposableService.DisposeService()
|
void IInternalDisposableService.DisposeService()
|
||||||
{
|
{
|
||||||
|
this.assertHandler.Dispose();
|
||||||
|
|
||||||
// Unload hooks from the framework thread if possible.
|
// Unload hooks from the framework thread if possible.
|
||||||
// We're currently off the framework thread, as this function can only be called from
|
// We're currently off the framework thread, as this function can only be called from
|
||||||
// ServiceManager.UnloadAllServices, which is called from EntryPoint.RunThread.
|
// ServiceManager.UnloadAllServices, which is called from EntryPoint.RunThread.
|
||||||
|
|
@ -565,6 +575,7 @@ internal partial class InterfaceManager : IInternalDisposableService
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
this.assertHandler.Setup();
|
||||||
newScene = new RawDX11Scene((nint)swapChain);
|
newScene = new RawDX11Scene((nint)swapChain);
|
||||||
}
|
}
|
||||||
catch (DllNotFoundException ex)
|
catch (DllNotFoundException ex)
|
||||||
|
|
@ -1128,15 +1139,11 @@ internal partial class InterfaceManager : IInternalDisposableService
|
||||||
WindowSystem.HasAnyWindowSystemFocus = false;
|
WindowSystem.HasAnyWindowSystemFocus = false;
|
||||||
WindowSystem.FocusedWindowSystemNamespace = string.Empty;
|
WindowSystem.FocusedWindowSystemNamespace = string.Empty;
|
||||||
|
|
||||||
var snap = ImGuiManagedAsserts.GetSnapshot();
|
|
||||||
|
|
||||||
if (this.IsDispatchingEvents)
|
if (this.IsDispatchingEvents)
|
||||||
{
|
{
|
||||||
this.Draw?.Invoke();
|
this.Draw?.Invoke();
|
||||||
Service<NotificationManager>.GetNullable()?.Draw();
|
Service<NotificationManager>.GetNullable()?.Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGuiManagedAsserts.ReportProblems("Dalamud Core", snap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
namespace Dalamud.Interface.Internal.ManagedAsserts;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Offsets to various data in ImGui context.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Last updated for ImGui 1.83.
|
|
||||||
/// </remarks>
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Document the unsage instead.")]
|
|
||||||
internal static class ImGuiContextOffsets
|
|
||||||
{
|
|
||||||
public const int CurrentWindowStackOffset = 0x73A;
|
|
||||||
|
|
||||||
public const int ColorStackOffset = 0x79C;
|
|
||||||
|
|
||||||
public const int StyleVarStackOffset = 0x7A0;
|
|
||||||
|
|
||||||
public const int FontStackOffset = 0x7A4;
|
|
||||||
|
|
||||||
public const int BeginPopupStackOffset = 0x7B8;
|
|
||||||
|
|
||||||
public const int TextStateOffset = 0x4588;
|
|
||||||
}
|
|
||||||
|
|
@ -1,140 +0,0 @@
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
using ImGuiNET;
|
|
||||||
|
|
||||||
using static Dalamud.NativeFunctions;
|
|
||||||
|
|
||||||
namespace Dalamud.Interface.Internal.ManagedAsserts;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Report ImGui problems with a MessageBox dialog.
|
|
||||||
/// </summary>
|
|
||||||
internal static class ImGuiManagedAsserts
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether asserts are enabled for ImGui.
|
|
||||||
/// </summary>
|
|
||||||
public static bool AssertsEnabled { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a snapshot of the current ImGui context.
|
|
||||||
/// Should be called before rendering an ImGui frame.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A snapshot of the current context.</returns>
|
|
||||||
public static unsafe ImGuiContextSnapshot GetSnapshot()
|
|
||||||
{
|
|
||||||
var contextPtr = ImGui.GetCurrentContext();
|
|
||||||
|
|
||||||
var styleVarStack = *((int*)contextPtr + ImGuiContextOffsets.StyleVarStackOffset); // ImVector.Size
|
|
||||||
var colorStack = *((int*)contextPtr + ImGuiContextOffsets.ColorStackOffset); // ImVector.Size
|
|
||||||
var fontStack = *((int*)contextPtr + ImGuiContextOffsets.FontStackOffset); // ImVector.Size
|
|
||||||
var popupStack = *((int*)contextPtr + ImGuiContextOffsets.BeginPopupStackOffset); // ImVector.Size
|
|
||||||
var windowStack = *((int*)contextPtr + ImGuiContextOffsets.CurrentWindowStackOffset); // ImVector.Size
|
|
||||||
|
|
||||||
return new ImGuiContextSnapshot
|
|
||||||
{
|
|
||||||
StyleVarStackSize = styleVarStack,
|
|
||||||
ColorStackSize = colorStack,
|
|
||||||
FontStackSize = fontStack,
|
|
||||||
BeginPopupStackSize = popupStack,
|
|
||||||
WindowStackSize = windowStack,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compare a snapshot to the current post-draw state and report any errors in a MessageBox dialog.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="source">The source of any problems, something to blame.</param>
|
|
||||||
/// <param name="before">ImGui context snapshot.</param>
|
|
||||||
public static void ReportProblems(string source, ImGuiContextSnapshot before)
|
|
||||||
{
|
|
||||||
// TODO: Needs to be updated for ImGui 1.88
|
|
||||||
return;
|
|
||||||
|
|
||||||
#pragma warning disable CS0162
|
|
||||||
if (!AssertsEnabled)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var cSnap = GetSnapshot();
|
|
||||||
|
|
||||||
if (before.StyleVarStackSize != cSnap.StyleVarStackSize)
|
|
||||||
{
|
|
||||||
ShowAssert(source, $"You forgot to pop a style var!\n\nBefore: {before.StyleVarStackSize}, after: {cSnap.StyleVarStackSize}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (before.ColorStackSize != cSnap.ColorStackSize)
|
|
||||||
{
|
|
||||||
ShowAssert(source, $"You forgot to pop a color!\n\nBefore: {before.ColorStackSize}, after: {cSnap.ColorStackSize}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (before.FontStackSize != cSnap.FontStackSize)
|
|
||||||
{
|
|
||||||
ShowAssert(source, $"You forgot to pop a font!\n\nBefore: {before.FontStackSize}, after: {cSnap.FontStackSize}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (before.BeginPopupStackSize != cSnap.BeginPopupStackSize)
|
|
||||||
{
|
|
||||||
ShowAssert(source, $"You forgot to end a popup!\n\nBefore: {before.BeginPopupStackSize}, after: {cSnap.BeginPopupStackSize}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cSnap.WindowStackSize != 1)
|
|
||||||
{
|
|
||||||
if (cSnap.WindowStackSize > 1)
|
|
||||||
{
|
|
||||||
ShowAssert(source, $"Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?\n\ncSnap.WindowStackSize = {cSnap.WindowStackSize}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ShowAssert(source, $"Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?\n\ncSnap.WindowStackSize = {cSnap.WindowStackSize}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#pragma warning restore CS0162
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ShowAssert(string source, string message)
|
|
||||||
{
|
|
||||||
var caption = $"You fucked up";
|
|
||||||
message = $"{message}\n\nSource: {source}\n\nAsserts are now disabled. You may re-enable them.";
|
|
||||||
var flags = MessageBoxType.Ok | MessageBoxType.IconError;
|
|
||||||
|
|
||||||
_ = MessageBoxW(Process.GetCurrentProcess().MainWindowHandle, message, caption, flags);
|
|
||||||
AssertsEnabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A snapshot of various ImGui context properties.
|
|
||||||
/// </summary>
|
|
||||||
public class ImGuiContextSnapshot
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the ImGui style var stack size.
|
|
||||||
/// </summary>
|
|
||||||
public int StyleVarStackSize { get; init; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the ImGui color stack size.
|
|
||||||
/// </summary>
|
|
||||||
public int ColorStackSize { get; init; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the ImGui font stack size.
|
|
||||||
/// </summary>
|
|
||||||
public int FontStackSize { get; init; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the ImGui begin popup stack size.
|
|
||||||
/// </summary>
|
|
||||||
public int BeginPopupStackSize { get; init; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the ImGui window stack size.
|
|
||||||
/// </summary>
|
|
||||||
public int WindowStackSize { get; init; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -222,6 +222,10 @@ public class DevPluginsSettingsEntry : SettingsEntry
|
||||||
this.devPluginLocationsChanged = true;
|
this.devPluginLocationsChanged = true;
|
||||||
this.devPluginTempLocation = string.Empty;
|
this.devPluginTempLocation = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var config = Service<DalamudConfiguration>.Get();
|
||||||
|
if (!config.ImGuiAssertsEnabledAtStartup.HasValue)
|
||||||
|
config.ImGuiAssertsEnabledAtStartup = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostDraw()
|
public override void PostDraw()
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ using Dalamud.Game.ClientState.Conditions;
|
||||||
using Dalamud.Game.Gui;
|
using Dalamud.Game.Gui;
|
||||||
using Dalamud.Interface.FontIdentifier;
|
using Dalamud.Interface.FontIdentifier;
|
||||||
using Dalamud.Interface.Internal;
|
using Dalamud.Interface.Internal;
|
||||||
using Dalamud.Interface.Internal.ManagedAsserts;
|
|
||||||
using Dalamud.Interface.ManagedFontAtlas;
|
using Dalamud.Interface.ManagedFontAtlas;
|
||||||
using Dalamud.Interface.ManagedFontAtlas.Internals;
|
using Dalamud.Interface.ManagedFontAtlas.Internals;
|
||||||
using Dalamud.Plugin.Internal.Types;
|
using Dalamud.Plugin.Internal.Types;
|
||||||
|
|
@ -713,8 +712,6 @@ public sealed class UiBuilder : IDisposable, IUiBuilder
|
||||||
ImGui.End();
|
ImGui.End();
|
||||||
}
|
}
|
||||||
|
|
||||||
var snapshot = this.Draw is null ? null : ImGuiManagedAsserts.GetSnapshot();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.Draw?.InvokeSafely();
|
this.Draw?.InvokeSafely();
|
||||||
|
|
@ -728,10 +725,6 @@ public sealed class UiBuilder : IDisposable, IUiBuilder
|
||||||
this.hasErrorWindow = true;
|
this.hasErrorWindow = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only if Draw was successful
|
|
||||||
if (this.Draw is not null && snapshot is not null)
|
|
||||||
ImGuiManagedAsserts.ReportProblems(this.namespaceName, snapshot);
|
|
||||||
|
|
||||||
this.FrameCount++;
|
this.FrameCount++;
|
||||||
|
|
||||||
if (DoStats)
|
if (DoStats)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
using Dalamud.Configuration.Internal;
|
using Dalamud.Configuration.Internal;
|
||||||
using Dalamud.Interface.Internal.ManagedAsserts;
|
|
||||||
|
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
@ -112,12 +111,7 @@ public class WindowSystem
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
// Log.Verbose($"[WS{(hasNamespace ? "/" + this.Namespace : string.Empty)}] Drawing {window.WindowName}");
|
// Log.Verbose($"[WS{(hasNamespace ? "/" + this.Namespace : string.Empty)}] Drawing {window.WindowName}");
|
||||||
#endif
|
#endif
|
||||||
var snapshot = ImGuiManagedAsserts.GetSnapshot();
|
|
||||||
|
|
||||||
window.DrawInternal(config);
|
window.DrawInternal(config);
|
||||||
|
|
||||||
var source = ($"{this.Namespace}::" ?? string.Empty) + window.WindowName;
|
|
||||||
ImGuiManagedAsserts.ReportProblems(source, snapshot);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var focusedWindow = this.windows.FirstOrDefault(window => window.IsFocused && window.RespectCloseHotkey);
|
var focusedWindow = this.windows.FirstOrDefault(window => window.IsFocused && window.RespectCloseHotkey);
|
||||||
|
|
|
||||||
8
external/cimgui/cimgui.vcxproj
vendored
8
external/cimgui/cimgui.vcxproj
vendored
|
|
@ -58,19 +58,17 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutDir>..\$(Platform)\$(Configuration)\</OutDir>
|
<OutDir>..\$(Platform)\$(Configuration)\</OutDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemDefinitionGroup>
|
<ItemDefinitionGroup>
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<AdditionalIncludeDirectories>..\..\lib\cimgui\imgui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\lib\cimgui\imgui;..\..\lib\cimgui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>_DEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;IMGUI_DISABLE_OBSOLETE_FUNCTIONS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_DEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;IMGUI_DISABLE_OBSOLETE_FUNCTIONS=1;IMGUI_USER_CONFIG="cimgui_user.h";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
@ -86,7 +84,7 @@
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>NDEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;IMGUI_DISABLE_OBSOLETE_FUNCTIONS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>NDEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;IMGUI_DISABLE_OBSOLETE_FUNCTIONS=1;IMGUI_USER_CONFIG="cimgui_user.h";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit a302ebabcca49c2e37711ea14a0b0915d38253b0
|
Subproject commit fd2377934f2cc007982e21ab82e54b41955cb658
|
||||||
Loading…
Add table
Add a link
Reference in a new issue