mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 10:17:22 +01:00
Merge pull request #2156 from goaaats/intree_imgui
Add proper ImGui assert mechanism
This commit is contained in:
commit
b822807eab
12 changed files with 238 additions and 207 deletions
|
|
@ -243,7 +243,7 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
|
|||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not ImGui asserts should be enabled at startup.
|
||||
/// </summary>
|
||||
public bool AssertsEnabledAtStartup { get; set; }
|
||||
public bool? ImGuiAssertsEnabledAtStartup { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
? Plugin.Internal.AutoUpdate.AutoUpdateBehavior.UpdateAll
|
||||
: 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
|
||||
}
|
||||
|
||||
|
|
|
|||
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.Interface.Colors;
|
||||
using Dalamud.Interface.GameFonts;
|
||||
using Dalamud.Interface.Internal.ManagedAsserts;
|
||||
using Dalamud.Interface.ManagedFontAtlas.Internals;
|
||||
using Dalamud.Interface.Utility;
|
||||
|
||||
|
|
@ -185,7 +184,7 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
|||
return true;
|
||||
if (!ImGui.GetIO().ConfigInputTextCursorBlink)
|
||||
return true;
|
||||
var textState = TextState;
|
||||
var textState = CustomNativeFunctions.igCustom_GetInputTextState();
|
||||
if (textState->Id == 0 || (textState->Flags & ImGuiInputTextFlags.ReadOnly) != 0)
|
||||
return true;
|
||||
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>
|
||||
private bool ShowPartialConversion => this.partialConversionFrom != 0 ||
|
||||
this.partialConversionTo != this.compositionString.Length;
|
||||
|
|
@ -341,7 +337,8 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
|||
|
||||
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
|
||||
switch (args.Message)
|
||||
|
|
@ -570,19 +567,20 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
|||
|
||||
this.ReflectCharacterEncounters(newString);
|
||||
|
||||
var textState = CustomNativeFunctions.igCustom_GetInputTextState();
|
||||
if (this.temporaryUndoSelection is not null)
|
||||
{
|
||||
TextState->Undo();
|
||||
TextState->SelectionTuple = this.temporaryUndoSelection.Value;
|
||||
textState->Undo();
|
||||
textState->SelectionTuple = this.temporaryUndoSelection.Value;
|
||||
this.temporaryUndoSelection = null;
|
||||
}
|
||||
|
||||
TextState->SanitizeSelectionRange();
|
||||
if (TextState->ReplaceSelectionAndPushUndo(newString))
|
||||
this.temporaryUndoSelection = TextState->SelectionTuple;
|
||||
textState->SanitizeSelectionRange();
|
||||
if (textState->ReplaceSelectionAndPushUndo(newString))
|
||||
this.temporaryUndoSelection = textState->SelectionTuple;
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
|
@ -627,7 +625,10 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
|
|||
this.partialConversionFrom = this.partialConversionTo = 0;
|
||||
this.compositionCursorOffset = 0;
|
||||
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.immCandNative = default;
|
||||
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
|
||||
private static class ImeDebug
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ using Dalamud.Game.Internal;
|
|||
using Dalamud.Hooking;
|
||||
using Dalamud.Interface.Animation.EasingFunctions;
|
||||
using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.Internal.ManagedAsserts;
|
||||
using Dalamud.Interface.Internal.Windows;
|
||||
using Dalamud.Interface.Internal.Windows.Data;
|
||||
using Dalamud.Interface.Internal.Windows.PluginInstaller;
|
||||
|
|
@ -163,7 +162,7 @@ internal class DalamudInterface : IInternalDisposableService
|
|||
this.WindowSystem.AddWindow(this.branchSwitcherWindow);
|
||||
this.WindowSystem.AddWindow(this.hitchSettingsWindow);
|
||||
|
||||
ImGuiManagedAsserts.AssertsEnabled = configuration.AssertsEnabledAtStartup;
|
||||
this.interfaceManager.ShowAsserts = configuration.ImGuiAssertsEnabledAtStartup ?? false;
|
||||
this.isImGuiDrawDevMenu = this.isImGuiDrawDevMenu || configuration.DevBarOpenAtStartup;
|
||||
|
||||
this.interfaceManager.Draw += this.OnDraw;
|
||||
|
|
@ -832,6 +831,12 @@ internal class DalamudInterface : IInternalDisposableService
|
|||
hook.Enable();
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui.MenuItem("Cause ImGui assert"))
|
||||
{
|
||||
ImGui.PopStyleVar();
|
||||
ImGui.PopStyleVar();
|
||||
}
|
||||
|
||||
ImGui.EndMenu();
|
||||
}
|
||||
|
|
@ -865,15 +870,16 @@ internal class DalamudInterface : IInternalDisposableService
|
|||
|
||||
ImGui.Separator();
|
||||
|
||||
var val = ImGuiManagedAsserts.AssertsEnabled;
|
||||
var val = this.interfaceManager.ShowAsserts;
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ using Dalamud.Hooking.WndProcHook;
|
|||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Dalamud.Interface.ImGuiNotification.Internal;
|
||||
using Dalamud.Interface.Internal.DesignSystem;
|
||||
using Dalamud.Interface.Internal.ManagedAsserts;
|
||||
using Dalamud.Interface.Internal.ReShadeHandling;
|
||||
using Dalamud.Interface.ManagedFontAtlas;
|
||||
using Dalamud.Interface.ManagedFontAtlas.Internals;
|
||||
|
|
@ -93,6 +92,8 @@ internal partial class InterfaceManager : IInternalDisposableService
|
|||
|
||||
private readonly ConcurrentQueue<Action> runBeforeImGuiRender = new();
|
||||
private readonly ConcurrentQueue<Action> runAfterImGuiRender = new();
|
||||
|
||||
private readonly AssertHandler assertHandler = new();
|
||||
|
||||
private RawDX11Scene? scene;
|
||||
|
||||
|
|
@ -267,11 +268,20 @@ internal partial class InterfaceManager : IInternalDisposableService
|
|||
/// </remarks>
|
||||
public long CumulativePresentCalls { get; private set; }
|
||||
|
||||
/// <inheritdoc cref="AssertHandler.ShowAsserts"/>
|
||||
public bool ShowAsserts
|
||||
{
|
||||
get => this.assertHandler.ShowAsserts;
|
||||
set => this.assertHandler.ShowAsserts = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.assertHandler.Dispose();
|
||||
|
||||
// Unload hooks from the framework thread if possible.
|
||||
// We're currently off the framework thread, as this function can only be called from
|
||||
// ServiceManager.UnloadAllServices, which is called from EntryPoint.RunThread.
|
||||
|
|
@ -565,6 +575,7 @@ internal partial class InterfaceManager : IInternalDisposableService
|
|||
{
|
||||
try
|
||||
{
|
||||
this.assertHandler.Setup();
|
||||
newScene = new RawDX11Scene((nint)swapChain);
|
||||
}
|
||||
catch (DllNotFoundException ex)
|
||||
|
|
@ -1128,15 +1139,11 @@ internal partial class InterfaceManager : IInternalDisposableService
|
|||
WindowSystem.HasAnyWindowSystemFocus = false;
|
||||
WindowSystem.FocusedWindowSystemNamespace = string.Empty;
|
||||
|
||||
var snap = ImGuiManagedAsserts.GetSnapshot();
|
||||
|
||||
if (this.IsDispatchingEvents)
|
||||
{
|
||||
this.Draw?.Invoke();
|
||||
Service<NotificationManager>.GetNullable()?.Draw();
|
||||
}
|
||||
|
||||
ImGuiManagedAsserts.ReportProblems("Dalamud Core", snap);
|
||||
}
|
||||
|
||||
/// <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.devPluginTempLocation = string.Empty;
|
||||
}
|
||||
|
||||
var config = Service<DalamudConfiguration>.Get();
|
||||
if (!config.ImGuiAssertsEnabledAtStartup.HasValue)
|
||||
config.ImGuiAssertsEnabledAtStartup = true;
|
||||
}
|
||||
|
||||
public override void PostDraw()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ using Dalamud.Game.ClientState.Conditions;
|
|||
using Dalamud.Game.Gui;
|
||||
using Dalamud.Interface.FontIdentifier;
|
||||
using Dalamud.Interface.Internal;
|
||||
using Dalamud.Interface.Internal.ManagedAsserts;
|
||||
using Dalamud.Interface.ManagedFontAtlas;
|
||||
using Dalamud.Interface.ManagedFontAtlas.Internals;
|
||||
using Dalamud.Plugin.Internal.Types;
|
||||
|
|
@ -713,8 +712,6 @@ public sealed class UiBuilder : IDisposable, IUiBuilder
|
|||
ImGui.End();
|
||||
}
|
||||
|
||||
var snapshot = this.Draw is null ? null : ImGuiManagedAsserts.GetSnapshot();
|
||||
|
||||
try
|
||||
{
|
||||
this.Draw?.InvokeSafely();
|
||||
|
|
@ -728,10 +725,6 @@ public sealed class UiBuilder : IDisposable, IUiBuilder
|
|||
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++;
|
||||
|
||||
if (DoStats)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
|
||||
using Dalamud.Configuration.Internal;
|
||||
using Dalamud.Interface.Internal.ManagedAsserts;
|
||||
|
||||
using ImGuiNET;
|
||||
using Serilog;
|
||||
|
|
@ -112,12 +111,7 @@ public class WindowSystem
|
|||
#if DEBUG
|
||||
// Log.Verbose($"[WS{(hasNamespace ? "/" + this.Namespace : string.Empty)}] Drawing {window.WindowName}");
|
||||
#endif
|
||||
var snapshot = ImGuiManagedAsserts.GetSnapshot();
|
||||
|
||||
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);
|
||||
|
|
|
|||
8
external/cimgui/cimgui.vcxproj
vendored
8
external/cimgui/cimgui.vcxproj
vendored
|
|
@ -58,19 +58,17 @@
|
|||
<PropertyGroup>
|
||||
<OutDir>..\$(Platform)\$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\lib\cimgui\imgui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\lib\cimgui\imgui;..\..\lib\cimgui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<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>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
|
|
@ -86,7 +84,7 @@
|
|||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<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>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit a302ebabcca49c2e37711ea14a0b0915d38253b0
|
||||
Subproject commit fd2377934f2cc007982e21ab82e54b41955cb658
|
||||
Loading…
Add table
Add a link
Reference in a new issue