Minor interface adjustments (#2121)

- Further ImRaii safety in UiDebug2
- Set some mistakenly internal methods in ImGuiComponents to public
- Added SpanFullWidth flag to trees in Util.ShowStruct
This commit is contained in:
ItsBexy 2024-11-24 13:37:39 -07:00 committed by GitHub
parent de999b7895
commit c950b15a22
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 282 additions and 264 deletions

View file

@ -28,6 +28,8 @@ using Windows.Win32.Storage.FileSystem;
using Windows.Win32.System.Memory;
using Windows.Win32.System.Ole;
using Dalamud.Interface.Utility.Raii;
using static TerraFX.Interop.Windows.Windows;
using Win32_PInvoke = Windows.Win32.PInvoke;
@ -1028,74 +1030,71 @@ public static class Util
dm.Invoke(null, new[] { obj, path, addr });
}
#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
private static unsafe void ShowSpanPrivate<T>(ulong addr, IList<string> path, int offset, bool isTop, in Span<T> spanobj)
{
#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
if (isTop)
{
fixed (void* p = spanobj)
{
if (!ImGui.TreeNode(
$"Span<{typeof(T).Name}> of length {spanobj.Length:n0} (0x{spanobj.Length:X})" +
$"##print-obj-{addr:X}-{string.Join("-", path)}-head"))
using var tree = ImRaii.TreeNode($"Span<{typeof(T).Name}> of length {spanobj.Length:n0} (0x{spanobj.Length:X})" + $"##print-obj-{addr:X}-{string.Join("-", path)}-head", ImGuiTreeNodeFlags.SpanFullWidth);
if (tree.Success)
{
return;
ShowSpanEntryPrivate(addr, path, offset, spanobj);
}
}
}
try
else
{
const int batchSize = 20;
if (spanobj.Length > batchSize)
{
var skip = batchSize;
while ((spanobj.Length + skip - 1) / skip > batchSize)
skip *= batchSize;
for (var i = 0; i < spanobj.Length; i += skip)
{
var next = Math.Min(i + skip, spanobj.Length);
path.Add($"{offset + i:X}_{skip}");
if (ImGui.TreeNode(
$"{offset + i:n0} ~ {offset + next - 1:n0} (0x{offset + i:X} ~ 0x{offset + next - 1:X})" +
$"##print-obj-{addr:X}-{string.Join("-", path)}"))
{
try
{
ShowSpanPrivate(addr, path, offset + i, false, spanobj[i..next]);
}
finally
{
ImGui.TreePop();
}
}
path.RemoveAt(path.Count - 1);
}
}
else
{
fixed (T* p = spanobj)
{
var pointerType = typeof(T*);
for (var i = 0; i < spanobj.Length; i++)
{
ImGui.TextUnformatted($"[{offset + i:n0} (0x{offset + i:X})] ");
ImGui.SameLine();
path.Add($"{offset + i}");
ShowValue(addr, path, pointerType, Pointer.Box(p + i, pointerType), true);
}
}
}
ShowSpanEntryPrivate(addr, path, offset, spanobj);
}
finally
{
if (isTop)
ImGui.TreePop();
}
#pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
}
private static unsafe void ShowSpanEntryPrivate<T>(ulong addr, IList<string> path, int offset, Span<T> spanobj) {
const int batchSize = 20;
if (spanobj.Length > batchSize)
{
var skip = batchSize;
while ((spanobj.Length + skip - 1) / skip > batchSize)
{
skip *= batchSize;
}
for (var i = 0; i < spanobj.Length; i += skip)
{
var next = Math.Min(i + skip, spanobj.Length);
path.Add($"{offset + i:X}_{skip}");
using (var tree = ImRaii.TreeNode($"{offset + i:n0} ~ {offset + next - 1:n0} (0x{offset + i:X} ~ 0x{offset + next - 1:X})" + $"##print-obj-{addr:X}-{string.Join("-", path)}", ImGuiTreeNodeFlags.SpanFullWidth))
{
if (tree.Success)
{
ShowSpanEntryPrivate(addr, path, offset + i, spanobj[i..next]);
}
}
path.RemoveAt(path.Count - 1);
}
}
else
{
fixed (T* p = spanobj)
{
var pointerType = typeof(T*);
for (var i = 0; i < spanobj.Length; i++)
{
ImGui.TextUnformatted($"[{offset + i:n0} (0x{offset + i:X})] ");
ImGui.SameLine();
path.Add($"{offset + i}");
ShowValue(addr, path, pointerType, Pointer.Box(p + i, pointerType), true);
}
}
}
}
#pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
private static unsafe void ShowValue(ulong addr, IList<string> path, Type type, object value, bool hideAddress)
{
if (type.IsPointer)
@ -1111,9 +1110,10 @@ public static class Util
if (moduleStartAddr > 0 && unboxedAddr >= moduleStartAddr && unboxedAddr <= moduleEndAddr)
{
ImGui.SameLine();
ImGui.PushStyleColor(ImGuiCol.Text, 0xffcbc0ff);
ImGuiHelpers.ClickToCopyText($"ffxiv_dx11.exe+{unboxedAddr - moduleStartAddr:X}");
ImGui.PopStyleColor();
using (ImRaii.PushColor(ImGuiCol.Text, 0xffcbc0ff))
{
ImGuiHelpers.ClickToCopyText($"ffxiv_dx11.exe+{unboxedAddr - moduleStartAddr:X}");
}
}
ImGui.SameLine();
@ -1165,125 +1165,135 @@ public static class Util
/// <param name="hideAddress">Do not print addresses. Use when displaying a copied value.</param>
private static void ShowStructInternal(object obj, ulong addr, bool autoExpand = false, IEnumerable<string>? path = null, bool hideAddress = false)
{
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(3, 2));
path ??= new List<string>();
var pathList = path is List<string> ? (List<string>)path : path.ToList();
if (moduleEndAddr == 0 && moduleStartAddr == 0)
using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(3, 2)))
{
try
path ??= new List<string>();
var pathList = path as List<string> ?? path.ToList();
if (moduleEndAddr == 0 && moduleStartAddr == 0)
{
var processModule = Process.GetCurrentProcess().MainModule;
if (processModule != null)
try
{
moduleStartAddr = (ulong)processModule.BaseAddress.ToInt64();
moduleEndAddr = moduleStartAddr + (ulong)processModule.ModuleMemorySize;
var processModule = Process.GetCurrentProcess().MainModule;
if (processModule != null)
{
moduleStartAddr = (ulong)processModule.BaseAddress.ToInt64();
moduleEndAddr = moduleStartAddr + (ulong)processModule.ModuleMemorySize;
}
else
{
moduleEndAddr = 1;
}
}
else
catch
{
moduleEndAddr = 1;
}
}
catch
if (autoExpand)
{
moduleEndAddr = 1;
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
}
}
ImGui.PushStyleColor(ImGuiCol.Text, 0xFF00FFFF);
if (autoExpand)
{
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
}
using var col = ImRaii.PushColor(ImGuiCol.Text, 0xFF00FFFF);
using var tree = ImRaii.TreeNode($"{obj}##print-obj-{addr:X}-{string.Join("-", pathList)}", ImGuiTreeNodeFlags.SpanFullWidth);
col.Pop();
if (ImGui.TreeNode($"{obj}##print-obj-{addr:X}-{string.Join("-", pathList)}"))
{
ImGui.PopStyleColor();
foreach (var f in obj.GetType()
.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance))
if (tree.Success)
{
var fixedBuffer = (FixedBufferAttribute)f.GetCustomAttribute(typeof(FixedBufferAttribute));
var offset = (FieldOffsetAttribute)f.GetCustomAttribute(typeof(FieldOffsetAttribute));
ImGui.PopStyleColor();
foreach (var f in obj.GetType()
.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance))
{
var fixedBuffer = (FixedBufferAttribute)f.GetCustomAttribute(typeof(FixedBufferAttribute));
var offset = (FieldOffsetAttribute)f.GetCustomAttribute(typeof(FieldOffsetAttribute));
if (fixedBuffer != null)
{
ImGui.Text($"fixed");
ImGui.SameLine();
ImGui.TextColored(new Vector4(0.2f, 0.9f, 0.9f, 1),
$"{fixedBuffer.ElementType.Name}[0x{fixedBuffer.Length:X}]");
}
else
{
if (offset != null)
if (fixedBuffer != null)
{
ImGui.TextDisabled($"[0x{offset.Value:X}]");
ImGui.Text("fixed");
ImGui.SameLine();
ImGui.TextColored(new Vector4(0.2f, 0.9f, 0.9f, 1), $"{fixedBuffer.ElementType.Name}[0x{fixedBuffer.Length:X}]");
}
ImGui.TextColored(new Vector4(0.2f, 0.9f, 0.9f, 1), $"{f.FieldType.Name}");
}
ImGui.SameLine();
ImGui.TextColored(new Vector4(0.2f, 0.9f, 0.4f, 1), $"{f.Name}: ");
ImGui.SameLine();
pathList.Add(f.Name);
try
{
if (f.FieldType.IsGenericType && (f.FieldType.IsByRef || f.FieldType.IsByRefLike))
ImGui.Text("Cannot preview ref typed fields."); // object never contains ref struct
else if (f.FieldType == typeof(bool) && offset != null)
ShowValue(addr, pathList, f.FieldType, Marshal.ReadByte((nint)addr + offset.Value) > 0, hideAddress);
else
ShowValue(addr, pathList, f.FieldType, f.GetValue(obj), hideAddress);
{
if (offset != null)
{
ImGui.TextDisabled($"[0x{offset.Value:X}]");
ImGui.SameLine();
}
ImGui.TextColored(new Vector4(0.2f, 0.9f, 0.9f, 1), $"{f.FieldType.Name}");
}
ImGui.SameLine();
ImGui.TextColored(new Vector4(0.2f, 0.9f, 0.4f, 1), $"{f.Name}: ");
ImGui.SameLine();
pathList.Add(f.Name);
try
{
if (f.FieldType.IsGenericType && (f.FieldType.IsByRef || f.FieldType.IsByRefLike))
{
ImGui.Text("Cannot preview ref typed fields."); // object never contains ref struct
}
else if (f.FieldType == typeof(bool) && offset != null)
{
ShowValue(addr, pathList, f.FieldType, Marshal.ReadByte((nint)addr + offset.Value) > 0, hideAddress);
}
else
{
ShowValue(addr, pathList, f.FieldType, f.GetValue(obj), hideAddress);
}
}
catch (Exception ex)
{
using (ImRaii.PushColor(ImGuiCol.Text, new Vector4(1f, 0.4f, 0.4f, 1f)))
{
ImGui.TextUnformatted($"Error: {ex.GetType().Name}: {ex.Message}");
}
}
finally
{
pathList.RemoveAt(pathList.Count - 1);
}
}
catch (Exception ex)
foreach (var p in obj.GetType().GetProperties().Where(static p => p.GetGetMethod()?.GetParameters().Length == 0))
{
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(1f, 0.4f, 0.4f, 1f));
ImGui.TextUnformatted($"Error: {ex.GetType().Name}: {ex.Message}");
ImGui.PopStyleColor();
}
finally
{
pathList.RemoveAt(pathList.Count - 1);
ImGui.TextColored(new Vector4(0.2f, 0.9f, 0.9f, 1), $"{p.PropertyType.Name}");
ImGui.SameLine();
ImGui.TextColored(new Vector4(0.2f, 0.6f, 0.4f, 1), $"{p.Name}: ");
ImGui.SameLine();
pathList.Add(p.Name);
try
{
if (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == GenericSpanType)
{
ShowSpanProperty(addr, pathList, p, obj);
}
else if (p.PropertyType.IsGenericType && (p.PropertyType.IsByRef || p.PropertyType.IsByRefLike))
{
ImGui.Text("Cannot preview ref typed properties.");
}
else
{
ShowValue(addr, pathList, p.PropertyType, p.GetValue(obj), hideAddress);
}
}
catch (Exception ex)
{
using (ImRaii.PushColor(ImGuiCol.Text, new Vector4(1f, 0.4f, 0.4f, 1f)))
{
ImGui.TextUnformatted($"Error: {ex.GetType().Name}: {ex.Message}");
}
}
finally
{
pathList.RemoveAt(pathList.Count - 1);
}
}
}
foreach (var p in obj.GetType().GetProperties().Where(p => p.GetGetMethod()?.GetParameters().Length == 0))
{
ImGui.TextColored(new Vector4(0.2f, 0.9f, 0.9f, 1), $"{p.PropertyType.Name}");
ImGui.SameLine();
ImGui.TextColored(new Vector4(0.2f, 0.6f, 0.4f, 1), $"{p.Name}: ");
ImGui.SameLine();
pathList.Add(p.Name);
try
{
if (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == GenericSpanType)
ShowSpanProperty(addr, pathList, p, obj);
else if (p.PropertyType.IsGenericType && (p.PropertyType.IsByRef || p.PropertyType.IsByRefLike))
ImGui.Text("Cannot preview ref typed properties.");
else
ShowValue(addr, pathList, p.PropertyType, p.GetValue(obj), hideAddress);
}
catch (Exception ex)
{
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(1f, 0.4f, 0.4f, 1f));
ImGui.TextUnformatted($"Error: {ex.GetType().Name}: {ex.Message}");
ImGui.PopStyleColor();
}
finally
{
pathList.RemoveAt(pathList.Count - 1);
}
}
ImGui.TreePop();
}
else
{
ImGui.PopStyleColor();
}
ImGui.PopStyleVar();
}
}