private unsafe void DrawResourceMap(ResourceCategory category, uint ext, StdMap <uint, Pointer <ResourceHandle> > *map) { if (map == null) { return; } var label = GetNodeLabel(( uint )category, ext, map->Count); using var tree = ImRaii.TreeNode(label); if (!tree || map->Count == 0) { return; } using var table = ImRaii.Table("##table", 4, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg); if (!table) { return; } ImGui.TableSetupColumn("Hash", ImGuiTableColumnFlags.WidthFixed, _hashColumnWidth); ImGui.TableSetupColumn("Ptr", ImGuiTableColumnFlags.WidthFixed, _hashColumnWidth); ImGui.TableSetupColumn("Path", ImGuiTableColumnFlags.WidthFixed, _pathColumnWidth); ImGui.TableSetupColumn("Refs", ImGuiTableColumnFlags.WidthFixed, _refsColumnWidth); ImGui.TableHeadersRow(); ResourceLoader.IterateResourceMap(map, (hash, r) => { // Filter unwanted names. if (_resourceManagerFilter.Length != 0 && !r->FileName.ToString().Contains(_resourceManagerFilter, StringComparison.InvariantCultureIgnoreCase)) { return; } var address = $"0x{( ulong )r:X}"; ImGuiUtil.TextNextColumn($"0x{hash:X8}"); ImGui.TableNextColumn(); ImGuiUtil.CopyOnClickSelectable(address); var resource = (Interop.Structs.ResourceHandle *)r; ImGui.TableNextColumn(); Text(resource); if (ImGui.IsItemClicked()) { var data = Interop.Structs.ResourceHandle.GetData(resource); if (data != null) { var length = ( int )Interop.Structs.ResourceHandle.GetLength(resource); ImGui.SetClipboardText(string.Join(" ", new ReadOnlySpan <byte>(data, length).ToArray().Select(b => b.ToString("X2")))); } } ImGuiUtil.HoverTooltip("Click to copy byte-wise file data to clipboard, if any."); ImGuiUtil.TextNextColumn(r->RefCount.ToString()); }); }
// Draw a full category for the resource manager. private unsafe void DrawCategoryContainer(ResourceCategory category, StdMap <uint, Pointer <StdMap <uint, Pointer <ResourceHandle> > > > *map) { if (map == null) { return; } using var tree = ImRaii.TreeNode($"({( uint )category:D2}) {category} - {map->Count}###{( uint )category}"); if (tree) { SetTableWidths(); ResourceLoader.IterateExtMap(map, (ext, m) => DrawResourceMap(category, ext, m)); } }
// Draw information about which draw objects correspond to which game objects // and which paths are due to be loaded by which collection. private unsafe void DrawPathResolverDebug() { if (!ImGui.CollapsingHeader("Path Resolver")) { return; } using var drawTree = ImRaii.TreeNode("Draw Object to Object"); if (drawTree) { using var table = ImRaii.Table("###DrawObjectResolverTable", 5, ImGuiTableFlags.SizingFixedFit); if (table) { foreach (var(ptr, (c, idx)) in _window._penumbra.PathResolver.DrawObjectToObject) { ImGui.TableNextColumn(); ImGui.TextUnformatted(ptr.ToString("X")); ImGui.TableNextColumn(); ImGui.TextUnformatted(idx.ToString()); ImGui.TableNextColumn(); ImGui.TextUnformatted(Dalamud.Objects[idx]?.Address.ToString() ?? "NULL"); ImGui.TableNextColumn(); ImGui.TextUnformatted(Dalamud.Objects[idx]?.Name.ToString() ?? "NULL"); ImGui.TableNextColumn(); ImGui.TextUnformatted(c.Name); } } } drawTree.Dispose(); using var pathTree = ImRaii.TreeNode("Path Collections"); if (pathTree) { using var table = ImRaii.Table("###PathCollectionResolverTable", 2, ImGuiTableFlags.SizingFixedFit); if (table) { foreach (var(path, collection) in _window._penumbra.PathResolver.PathCollections) { ImGui.TableNextColumn(); ImGuiNative.igTextUnformatted(path.Path, path.Path + path.Length); ImGui.TableNextColumn(); ImGui.TextUnformatted(collection.Name); } } } }