Penumbra/Penumbra/UI/Tabs/Debug/GlobalVariablesDrawer.cs

252 lines
10 KiB
C#

using Dalamud.Bindings.ImGui;
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
using FFXIVClientStructs.FFXIV.Client.System.Scheduler;
using FFXIVClientStructs.FFXIV.Client.System.Scheduler.Resource;
using FFXIVClientStructs.Interop;
using FFXIVClientStructs.STD;
using OtterGui.Services;
using OtterGui.Text;
using Penumbra.Interop.Services;
using Penumbra.Interop.Structs;
using Penumbra.String;
using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager;
namespace Penumbra.UI.Tabs.Debug;
public unsafe class GlobalVariablesDrawer(
CharacterUtility characterUtility,
ResidentResourceManager residentResources,
SchedulerResourceManagementService scheduler) : 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;
var actionManager = (ActionTimelineManager**)ActionTimelineManager.Instance();
using (ImUtf8.Group())
{
Penumbra.Dynamis.DrawPointer(characterUtility.Address);
Penumbra.Dynamis.DrawPointer(residentResources.Address);
Penumbra.Dynamis.DrawPointer(ScheduleManagement.Instance());
Penumbra.Dynamis.DrawPointer(actionManager);
Penumbra.Dynamis.DrawPointer(actionManager != null ? *actionManager : null);
Penumbra.Dynamis.DrawPointer(scheduler.Address);
Penumbra.Dynamis.DrawPointer(scheduler.Address != null ? *scheduler.Address : null);
Penumbra.Dynamis.DrawPointer(Device.Instance());
}
ImGui.SameLine();
using (ImUtf8.Group())
{
ImUtf8.Text("CharacterUtility"u8);
ImUtf8.Text("ResidentResourceManager"u8);
ImUtf8.Text("ScheduleManagement"u8);
ImUtf8.Text("ActionTimelineManager*"u8);
ImUtf8.Text("ActionTimelineManager"u8);
ImUtf8.Text("SchedulerResourceManagement*"u8);
ImUtf8.Text("SchedulerResourceManagement"u8);
ImUtf8.Text("Device"u8);
}
DrawCharacterUtility();
DrawResidentResources();
DrawSchedulerResourcesMap();
DrawSchedulerResourcesList();
}
/// <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();
Penumbra.Dynamis.DrawPointer(resource);
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();
Penumbra.Dynamis.DrawPointer(data);
ImUtf8.DrawTableColumn(length.ToString());
ImGui.TableNextColumn();
if (intern.Value != -1)
{
Penumbra.Dynamis.DrawPointer(characterUtility.DefaultResource(intern).Address);
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();
Penumbra.Dynamis.DrawPointer(resource);
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();
Penumbra.Dynamis.DrawPointer(data);
ImUtf8.DrawTableColumn(length.ToString());
}
}
private string _schedulerFilterList = string.Empty;
private string _schedulerFilterMap = string.Empty;
private CiByteString _schedulerFilterListU8 = CiByteString.Empty;
private CiByteString _schedulerFilterMapU8 = CiByteString.Empty;
private int _shownResourcesList = 0;
private int _shownResourcesMap = 0;
private void DrawSchedulerResourcesMap()
{
using var tree = ImUtf8.TreeNode("Scheduler Resources (Map)"u8);
if (!tree)
return;
if (scheduler.Address == null || scheduler.Scheduler == null)
return;
if (ImUtf8.InputText("##SchedulerMapFilter"u8, ref _schedulerFilterMap, "Filter..."u8))
_schedulerFilterMapU8 = CiByteString.FromString(_schedulerFilterMap, out var t, MetaDataComputation.All, false)
? t
: CiByteString.Empty;
ImUtf8.Text($"{_shownResourcesMap} / {scheduler.Scheduler->Resources.LongCount}");
using var table = ImUtf8.Table("##SchedulerMapResources"u8, 10, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit,
-Vector2.UnitX);
if (!table)
return;
// TODO Remove cast when it'll have the right type in CS.
var map = (StdMap<int, Pointer<SchedulerResource>>*)&scheduler.Scheduler->Resources;
var total = 0;
_shownResourcesMap = 0;
foreach (var (key, resourcePtr) in *map)
{
var resource = resourcePtr.Value;
if (_schedulerFilterMap.Length is 0 || resource->Name.Buffer.IndexOf(_schedulerFilterMapU8.Span) >= 0)
{
ImUtf8.DrawTableColumn($"[{total:D4}]");
ImUtf8.DrawTableColumn($"{resource->Name.Unk1}");
ImUtf8.DrawTableColumn(new CiByteString(resource->Name.Buffer, MetaDataComputation.None).Span);
ImUtf8.DrawTableColumn($"{resource->Consumers}");
ImUtf8.DrawTableColumn($"{resource->Unk1}"); // key
ImGui.TableNextColumn();
Penumbra.Dynamis.DrawPointer(resource);
ImGui.TableNextColumn();
var resourceHandle = *((ResourceHandle**)resource + 3);
Penumbra.Dynamis.DrawPointer(resourceHandle);
ImGui.TableNextColumn();
ImUtf8.CopyOnClickSelectable(resourceHandle->FileName().Span);
ImGui.TableNextColumn();
uint dataLength = 0;
Penumbra.Dynamis.DrawPointer(resource->GetResourceData(&dataLength));
ImUtf8.DrawTableColumn($"{dataLength}");
++_shownResourcesMap;
}
++total;
}
}
private void DrawSchedulerResourcesList()
{
using var tree = ImUtf8.TreeNode("Scheduler Resources (List)"u8);
if (!tree)
return;
if (scheduler.Address == null || scheduler.Scheduler == null)
return;
if (ImUtf8.InputText("##SchedulerListFilter"u8, ref _schedulerFilterList, "Filter..."u8))
_schedulerFilterListU8 = CiByteString.FromString(_schedulerFilterList, out var t, MetaDataComputation.All, false)
? t
: CiByteString.Empty;
ImUtf8.Text($"{_shownResourcesList} / {scheduler.Scheduler->Resources.LongCount}");
using var table = ImUtf8.Table("##SchedulerListResources"u8, 10, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit,
-Vector2.UnitX);
if (!table)
return;
var resource = scheduler.Scheduler->Begin;
var total = 0;
_shownResourcesList = 0;
while (resource != null && total < scheduler.Scheduler->Resources.Count)
{
if (_schedulerFilterList.Length is 0 || resource->Name.Buffer.IndexOf(_schedulerFilterListU8.Span) >= 0)
{
ImUtf8.DrawTableColumn($"[{total:D4}]");
ImUtf8.DrawTableColumn($"{resource->Name.Unk1}");
ImUtf8.DrawTableColumn(new CiByteString(resource->Name.Buffer, MetaDataComputation.None).Span);
ImUtf8.DrawTableColumn($"{resource->Consumers}");
ImUtf8.DrawTableColumn($"{resource->Unk1}"); // key
ImGui.TableNextColumn();
Penumbra.Dynamis.DrawPointer(resource);
ImGui.TableNextColumn();
var resourceHandle = *((ResourceHandle**)resource + 3);
Penumbra.Dynamis.DrawPointer(resourceHandle);
ImGui.TableNextColumn();
ImUtf8.CopyOnClickSelectable(resourceHandle->FileName().Span);
ImGui.TableNextColumn();
uint dataLength = 0;
Penumbra.Dynamis.DrawPointer(resource->GetResourceData(&dataLength));
ImUtf8.DrawTableColumn($"{dataLength}");
++_shownResourcesList;
}
resource = resource->Previous;
++total;
}
}
}