mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Update variables drawer.
This commit is contained in:
parent
b377ca372c
commit
22541b3fd8
2 changed files with 154 additions and 132 deletions
|
|
@ -6,7 +6,6 @@ using Dalamud.Utility;
|
|||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Group;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
using ImGuiNET;
|
||||
|
|
@ -35,8 +34,6 @@ using Penumbra.UI.Classes;
|
|||
using Penumbra.Util;
|
||||
using static OtterGui.Raii.ImRaii;
|
||||
using CharacterBase = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.CharacterBase;
|
||||
using CharacterUtility = Penumbra.Interop.Services.CharacterUtility;
|
||||
using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager;
|
||||
using ImGuiClip = OtterGui.ImGuiClip;
|
||||
using Penumbra.Api.IpcTester;
|
||||
using Penumbra.Interop.Hooks.PostProcessing;
|
||||
|
|
@ -80,8 +77,7 @@ public class DebugTab : Window, ITab, IUiService
|
|||
private readonly HttpApi _httpApi;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly StainService _stains;
|
||||
private readonly CharacterUtility _characterUtility;
|
||||
private readonly ResidentResourceManager _residentResources;
|
||||
private readonly GlobalVariablesDrawer _globalVariablesDrawer;
|
||||
private readonly ResourceManagerService _resourceManager;
|
||||
private readonly CollectionResolver _collectionResolver;
|
||||
private readonly DrawObjectState _drawObjectState;
|
||||
|
|
@ -109,13 +105,12 @@ public class DebugTab : Window, ITab, IUiService
|
|||
public DebugTab(PerformanceTracker performance, Configuration config, CollectionManager collectionManager, ObjectManager objects,
|
||||
IClientState clientState, IDataManager dataManager,
|
||||
ValidityChecker validityChecker, ModManager modManager, HttpApi httpApi, ActorManager actors, StainService stains,
|
||||
CharacterUtility characterUtility, ResidentResourceManager residentResources,
|
||||
ResourceManagerService resourceManager, CollectionResolver collectionResolver,
|
||||
DrawObjectState drawObjectState, PathState pathState, SubfileHelper subfileHelper, IdentifiedCollectionCache identifiedCollectionCache,
|
||||
CutsceneService cutsceneService, ModImportManager modImporter, ImportPopup importPopup, FrameworkManager framework,
|
||||
TextureManager textureManager, ShaderReplacementFixer shaderReplacementFixer, RedrawService redraws, DictEmote emotes,
|
||||
Diagnostics diagnostics, IpcTester ipcTester, CrashHandlerPanel crashHandlerPanel, TexHeaderDrawer texHeaderDrawer,
|
||||
HookOverrideDrawer hookOverrides, RsfService rsfService)
|
||||
HookOverrideDrawer hookOverrides, RsfService rsfService, GlobalVariablesDrawer globalVariablesDrawer)
|
||||
: base("Penumbra Debug Window", ImGuiWindowFlags.NoCollapse)
|
||||
{
|
||||
IsOpen = true;
|
||||
|
|
@ -132,8 +127,6 @@ public class DebugTab : Window, ITab, IUiService
|
|||
_httpApi = httpApi;
|
||||
_actors = actors;
|
||||
_stains = stains;
|
||||
_characterUtility = characterUtility;
|
||||
_residentResources = residentResources;
|
||||
_resourceManager = resourceManager;
|
||||
_collectionResolver = collectionResolver;
|
||||
_drawObjectState = drawObjectState;
|
||||
|
|
@ -154,6 +147,7 @@ public class DebugTab : Window, ITab, IUiService
|
|||
_texHeaderDrawer = texHeaderDrawer;
|
||||
_hookOverrides = hookOverrides;
|
||||
_rsfService = rsfService;
|
||||
_globalVariablesDrawer = globalVariablesDrawer;
|
||||
_objects = objects;
|
||||
_clientState = clientState;
|
||||
_dataManager = dataManager;
|
||||
|
|
@ -185,14 +179,13 @@ public class DebugTab : Window, ITab, IUiService
|
|||
DrawActorsDebug();
|
||||
DrawCollectionCaches();
|
||||
_texHeaderDrawer.Draw();
|
||||
DrawDebugCharacterUtility();
|
||||
DrawShaderReplacementFixer();
|
||||
DrawData();
|
||||
DrawCrcCache();
|
||||
DrawResourceProblems();
|
||||
_hookOverrides.Draw();
|
||||
DrawPlayerModelInfo();
|
||||
DrawGlobalVariableInfo();
|
||||
_globalVariablesDrawer.Draw();
|
||||
DrawDebugTabIpc();
|
||||
}
|
||||
|
||||
|
|
@ -217,9 +210,11 @@ public class DebugTab : Window, ITab, IUiService
|
|||
{
|
||||
if (resourceNode)
|
||||
foreach (var (path, resource) in collection._cache!.CustomResources)
|
||||
{
|
||||
ImUtf8.TreeNode($"{path} -> 0x{(ulong)resource.ResourceHandle:X}",
|
||||
ImGuiTreeNodeFlags.Bullet | ImGuiTreeNodeFlags.Leaf).Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
using var modNode = ImUtf8.TreeNode("Enabled Mods"u8);
|
||||
if (modNode)
|
||||
|
|
@ -485,9 +480,11 @@ public class DebugTab : Window, ITab, IUiService
|
|||
? $"{identifier.DataId} | {obj.AsObject->BaseId}"
|
||||
: identifier.DataId.ToString();
|
||||
ImGuiUtil.DrawTableColumn(id);
|
||||
ImGuiUtil.DrawTableColumn(obj.Address != nint.Zero ? $"0x{(*(nint*)obj.Address):X}" : "NULL");
|
||||
ImGuiUtil.DrawTableColumn(obj.Address != nint.Zero ? $"0x{*(nint*)obj.Address:X}" : "NULL");
|
||||
ImGuiUtil.DrawTableColumn(obj.Address != nint.Zero ? $"0x{obj.AsObject->EntityId:X}" : "NULL");
|
||||
ImGuiUtil.DrawTableColumn(obj.Address != nint.Zero ? obj.AsObject->IsCharacter() ? $"Character: {obj.AsCharacter->ObjectKind}" : "No Character" : "NULL");
|
||||
ImGuiUtil.DrawTableColumn(obj.Address != nint.Zero
|
||||
? obj.AsObject->IsCharacter() ? $"Character: {obj.AsCharacter->ObjectKind}" : "No Character"
|
||||
: "NULL");
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
@ -795,68 +792,6 @@ public class DebugTab : Window, ITab, IUiService
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw information about the character utility class from SE,
|
||||
/// displaying all files, their sizes, the default files and the default sizes.
|
||||
/// </summary>
|
||||
private unsafe void DrawDebugCharacterUtility()
|
||||
{
|
||||
if (!ImGui.CollapsingHeader("Character Utility"))
|
||||
return;
|
||||
|
||||
using var table = Table("##CharacterUtility", 7, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit,
|
||||
-Vector2.UnitX);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
for (var idx = 0; idx < CharacterUtility.ReverseIndices.Length; ++idx)
|
||||
{
|
||||
var intern = CharacterUtility.ReverseIndices[idx];
|
||||
var resource = _characterUtility.Address->Resource(idx);
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted($"[{idx}]");
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted($"0x{(ulong)resource:X}");
|
||||
ImGui.TableNextColumn();
|
||||
if (resource == null)
|
||||
{
|
||||
ImGui.TableNextRow();
|
||||
continue;
|
||||
}
|
||||
|
||||
UiHelpers.Text(resource);
|
||||
ImGui.TableNextColumn();
|
||||
var data = (nint)resource->CsHandle.GetData();
|
||||
var length = resource->CsHandle.GetLength();
|
||||
if (ImGui.Selectable($"0x{data:X}"))
|
||||
if (data != nint.Zero && length > 0)
|
||||
ImGui.SetClipboardText(string.Join("\n",
|
||||
new ReadOnlySpan<byte>((byte*)data, (int)length).ToArray().Select(b => b.ToString("X2"))));
|
||||
|
||||
ImGuiUtil.HoverTooltip("Click to copy bytes to clipboard.");
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted(length.ToString());
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
if (intern.Value != -1)
|
||||
{
|
||||
ImGui.Selectable($"0x{_characterUtility.DefaultResource(intern).Address:X}");
|
||||
if (ImGui.IsItemClicked())
|
||||
ImGui.SetClipboardText(string.Join("\n",
|
||||
new ReadOnlySpan<byte>((byte*)_characterUtility.DefaultResource(intern).Address,
|
||||
_characterUtility.DefaultResource(intern).Size).ToArray().Select(b => b.ToString("X2"))));
|
||||
|
||||
ImGuiUtil.HoverTooltip("Click to copy bytes to clipboard.");
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted($"{_characterUtility.DefaultResource(intern).Size}");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.TableNextColumn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawShaderReplacementFixer()
|
||||
{
|
||||
|
|
@ -946,45 +881,6 @@ public class DebugTab : Window, ITab, IUiService
|
|||
ImGui.TextUnformatted($"{slowPathCallDeltas.Skin}");
|
||||
}
|
||||
|
||||
/// <summary> Draw information about the resident resource files. </summary>
|
||||
private unsafe void DrawDebugResidentResources()
|
||||
{
|
||||
using var tree = TreeNode("Resident Resources");
|
||||
if (!tree)
|
||||
return;
|
||||
|
||||
if (_residentResources.Address == null || _residentResources.Address->NumResources == 0)
|
||||
return;
|
||||
|
||||
using var table = Table("##ResidentResources", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit,
|
||||
-Vector2.UnitX);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < _residentResources.Address->NumResources; ++i)
|
||||
{
|
||||
var resource = _residentResources.Address->ResourceList[i];
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted($"0x{(ulong)resource:X}");
|
||||
ImGui.TableNextColumn();
|
||||
UiHelpers.Text(resource);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawCopyableAddress(string label, nint address)
|
||||
{
|
||||
using (var _ = PushFont(UiBuilder.MonoFont))
|
||||
{
|
||||
if (ImGui.Selectable($"0x{address:X16} {label}"))
|
||||
ImGui.SetClipboardText($"{address:X16}");
|
||||
}
|
||||
|
||||
ImGuiUtil.HoverTooltip("Click to copy address to clipboard.");
|
||||
}
|
||||
|
||||
private static unsafe void DrawCopyableAddress(string label, void* address)
|
||||
=> DrawCopyableAddress(label, (nint)address);
|
||||
|
||||
/// <summary> Draw information about the models, materials and resources currently loaded by the local player. </summary>
|
||||
private unsafe void DrawPlayerModelInfo()
|
||||
{
|
||||
|
|
@ -993,13 +889,13 @@ public class DebugTab : Window, ITab, IUiService
|
|||
if (!ImGui.CollapsingHeader($"Player Model Info: {name}##Draw") || player == null)
|
||||
return;
|
||||
|
||||
DrawCopyableAddress("PlayerCharacter", player.Address);
|
||||
DrawCopyableAddress("PlayerCharacter"u8, player.Address);
|
||||
|
||||
var model = (CharacterBase*)((Character*)player.Address)->GameObject.GetDrawObject();
|
||||
if (model == null)
|
||||
return;
|
||||
|
||||
DrawCopyableAddress("CharacterBase", model);
|
||||
DrawCopyableAddress("CharacterBase"u8, model);
|
||||
|
||||
using (var t1 = Table("##table", 2, ImGuiTableFlags.SizingFixedFit))
|
||||
{
|
||||
|
|
@ -1054,20 +950,6 @@ public class DebugTab : Window, ITab, IUiService
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary> Draw information about some game global variables. </summary>
|
||||
private unsafe void DrawGlobalVariableInfo()
|
||||
{
|
||||
var header = ImGui.CollapsingHeader("Global Variables");
|
||||
ImGuiUtil.HoverTooltip("Draw information about global variables. Can provide useful starting points for a memory viewer.");
|
||||
if (!header)
|
||||
return;
|
||||
|
||||
DrawCopyableAddress("CharacterUtility", _characterUtility.Address);
|
||||
DrawCopyableAddress("ResidentResourceManager", _residentResources.Address);
|
||||
DrawCopyableAddress("Device", Device.Instance());
|
||||
DrawDebugResidentResources();
|
||||
}
|
||||
|
||||
private string _crcInput = string.Empty;
|
||||
private FullPath _crcPath = FullPath.Empty;
|
||||
|
||||
|
|
@ -1169,4 +1051,18 @@ public class DebugTab : Window, ITab, IUiService
|
|||
_config.Ephemeral.DebugSeparateWindow = false;
|
||||
_config.Ephemeral.Save();
|
||||
}
|
||||
|
||||
public static unsafe void DrawCopyableAddress(ReadOnlySpan<byte> label, void* address)
|
||||
{
|
||||
using (var _ = ImRaii.PushFont(UiBuilder.MonoFont))
|
||||
{
|
||||
if (ImUtf8.Selectable($"0x{(nint)address:X16} {label}"))
|
||||
ImUtf8.SetClipboardText($"0x{(nint)address:X16}");
|
||||
}
|
||||
|
||||
ImUtf8.HoverTooltip("Click to copy address to clipboard."u8);
|
||||
}
|
||||
|
||||
public static unsafe void DrawCopyableAddress(ReadOnlySpan<byte> label, nint address)
|
||||
=> DrawCopyableAddress(label, (void*)address);
|
||||
}
|
||||
|
|
|
|||
126
Penumbra/UI/Tabs/Debug/GlobalVariablesDrawer.cs
Normal file
126
Penumbra/UI/Tabs/Debug/GlobalVariablesDrawer.cs
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using ImGuiNET;
|
||||
using OtterGui.Services;
|
||||
using OtterGui.Text;
|
||||
using Penumbra.Interop.Services;
|
||||
|
||||
namespace Penumbra.UI.Tabs.Debug;
|
||||
|
||||
public unsafe class GlobalVariablesDrawer(CharacterUtility characterUtility, ResidentResourceManager residentResources) : IUiService
|
||||
{
|
||||
/// <summary> Draw information about some game global variables. </summary>
|
||||
public void Draw()
|
||||
{
|
||||
var header = ImUtf8.CollapsingHeader("Global Variables"u8);
|
||||
ImUtf8.HoverTooltip("Draw information about global variables. Can provide useful starting points for a memory viewer."u8);
|
||||
if (!header)
|
||||
return;
|
||||
|
||||
DebugTab.DrawCopyableAddress("CharacterUtility"u8, characterUtility.Address);
|
||||
DebugTab.DrawCopyableAddress("ResidentResourceManager"u8, residentResources.Address);
|
||||
DebugTab.DrawCopyableAddress("Device"u8, Device.Instance());
|
||||
DrawCharacterUtility();
|
||||
DrawResidentResources();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw information about the character utility class from SE,
|
||||
/// displaying all files, their sizes, the default files and the default sizes.
|
||||
/// </summary>
|
||||
private void DrawCharacterUtility()
|
||||
{
|
||||
using var tree = ImUtf8.TreeNode("Character Utility"u8);
|
||||
if (!tree)
|
||||
return;
|
||||
|
||||
using var table = ImUtf8.Table("##CharacterUtility"u8, 7, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit,
|
||||
-Vector2.UnitX);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
for (var idx = 0; idx < CharacterUtility.ReverseIndices.Length; ++idx)
|
||||
{
|
||||
var intern = CharacterUtility.ReverseIndices[idx];
|
||||
var resource = characterUtility.Address->Resource(idx);
|
||||
ImUtf8.DrawTableColumn($"[{idx}]");
|
||||
ImGui.TableNextColumn();
|
||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)resource:X}");
|
||||
if (resource == null)
|
||||
{
|
||||
ImGui.TableNextRow();
|
||||
continue;
|
||||
}
|
||||
|
||||
ImUtf8.DrawTableColumn(resource->CsHandle.FileName.AsSpan());
|
||||
ImGui.TableNextColumn();
|
||||
var data = (nint)resource->CsHandle.GetData();
|
||||
var length = resource->CsHandle.GetLength();
|
||||
if (ImUtf8.Selectable($"0x{data:X}"))
|
||||
if (data != nint.Zero && length > 0)
|
||||
ImUtf8.SetClipboardText(string.Join("\n",
|
||||
new ReadOnlySpan<byte>((byte*)data, (int)length).ToArray().Select(b => b.ToString("X2"))));
|
||||
|
||||
ImUtf8.HoverTooltip("Click to copy bytes to clipboard."u8);
|
||||
ImUtf8.DrawTableColumn(length.ToString());
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
if (intern.Value != -1)
|
||||
{
|
||||
ImUtf8.Selectable($"0x{characterUtility.DefaultResource(intern).Address:X}");
|
||||
if (ImGui.IsItemClicked())
|
||||
ImUtf8.SetClipboardText(string.Join("\n",
|
||||
new ReadOnlySpan<byte>((byte*)characterUtility.DefaultResource(intern).Address,
|
||||
characterUtility.DefaultResource(intern).Size).ToArray().Select(b => b.ToString("X2"))));
|
||||
|
||||
ImUtf8.HoverTooltip("Click to copy bytes to clipboard."u8);
|
||||
|
||||
ImUtf8.DrawTableColumn($"{characterUtility.DefaultResource(intern).Size}");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.TableNextColumn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Draw information about the resident resource files. </summary>
|
||||
private void DrawResidentResources()
|
||||
{
|
||||
using var tree = ImUtf8.TreeNode("Resident Resources"u8);
|
||||
if (!tree)
|
||||
return;
|
||||
|
||||
if (residentResources.Address == null || residentResources.Address->NumResources == 0)
|
||||
return;
|
||||
|
||||
using var table = ImUtf8.Table("##ResidentResources"u8, 5, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit,
|
||||
-Vector2.UnitX);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
for (var idx = 0; idx < residentResources.Address->NumResources; ++idx)
|
||||
{
|
||||
var resource = residentResources.Address->ResourceList[idx];
|
||||
ImUtf8.DrawTableColumn($"[{idx}]");
|
||||
ImGui.TableNextColumn();
|
||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)resource:X}");
|
||||
if (resource == null)
|
||||
{
|
||||
ImGui.TableNextRow();
|
||||
continue;
|
||||
}
|
||||
|
||||
ImUtf8.DrawTableColumn(resource->CsHandle.FileName.AsSpan());
|
||||
ImGui.TableNextColumn();
|
||||
var data = (nint)resource->CsHandle.GetData();
|
||||
var length = resource->CsHandle.GetLength();
|
||||
if (ImUtf8.Selectable($"0x{data:X}"))
|
||||
if (data != nint.Zero && length > 0)
|
||||
ImUtf8.SetClipboardText(string.Join("\n",
|
||||
new ReadOnlySpan<byte>((byte*)data, (int)length).ToArray().Select(b => b.ToString("X2"))));
|
||||
|
||||
ImUtf8.HoverTooltip("Click to copy bytes to clipboard."u8);
|
||||
ImUtf8.DrawTableColumn(length.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue