Esempio n. 1
0
        // Draw information about the resident resource files.
        public unsafe void DrawDebugResidentResources()
        {
            if (!ImGui.CollapsingHeader("Resident Resources"))
            {
                return;
            }

            if (Penumbra.ResidentResources.Address == null || Penumbra.ResidentResources.Address->NumResources == 0)
            {
                return;
            }

            using var table = ImRaii.Table("##ResidentResources", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit,
                                           -Vector2.UnitX);
            if (!table)
            {
                return;
            }

            for (var i = 0; i < Penumbra.ResidentResources.Address->NumResources; ++i)
            {
                var resource = Penumbra.ResidentResources.Address->ResourceList[i];
                ImGui.TableNextColumn();
                ImGui.TextUnformatted($"0x{( ulong )resource:X}");
                ImGui.TableNextColumn();
                Text(resource);
            }
        }
Esempio n. 2
0
    // The headers for the different meta changes all have basically the same structure for different types.
    private void DrawEditHeader <T>(IReadOnlyCollection <T> items, string label, int numColumns, Action <T, Mod.Editor, Vector2> draw,
                                    Action <Mod.Editor, Vector2> drawNew)
    {
        const ImGuiTableFlags flags = ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.BordersInnerV;

        if (!ImGui.CollapsingHeader($"{items.Count} {label}"))
        {
            return;
        }

        using (var table = ImRaii.Table(label, numColumns, flags))
        {
            if (table)
            {
                drawNew(_editor !, _iconSize);
                ImGui.Separator();
                foreach (var(item, index) in items.ToArray().WithIndex())
                {
                    using var id = ImRaii.PushId(index);
                    draw(item, _editor !, _iconSize);
                }
            }
        }

        ImGui.NewLine();
    }
Esempio n. 3
0
        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());
            });
        }
Esempio n. 4
0
        // Draw general information about mod and collection state.
        private void DrawDebugTabGeneral()
        {
            if (!ImGui.CollapsingHeader("General"))
            {
                return;
            }

            using var table = ImRaii.Table("##DebugGeneralTable", 2, ImGuiTableFlags.SizingFixedFit,
                                           new Vector2(-1, ImGui.GetTextLineHeightWithSpacing() * 1));
            if (!table)
            {
                return;
            }

            var manager = Penumbra.ModManager;

            PrintValue("Penumbra Version", $"{Penumbra.Version} {DebugVersionString}");
            PrintValue("Git Commit Hash", Penumbra.CommitHash);
            PrintValue("Current Collection", Penumbra.CollectionManager.Current.Name);
            PrintValue("    has Cache", Penumbra.CollectionManager.Current.HasCache.ToString());
            PrintValue("Default Collection", Penumbra.CollectionManager.Default.Name);
            PrintValue("    has Cache", Penumbra.CollectionManager.Default.HasCache.ToString());
            PrintValue("Mod Manager BasePath", manager.BasePath.Name);
            PrintValue("Mod Manager BasePath-Full", manager.BasePath.FullName);
            PrintValue("Mod Manager BasePath IsRooted", Path.IsPathRooted(Penumbra.Config.ModDirectory).ToString());
            PrintValue("Mod Manager BasePath Exists", Directory.Exists(manager.BasePath.FullName).ToString());
            PrintValue("Mod Manager Valid", manager.Valid.ToString());
            PrintValue("Path Resolver Enabled", _window._penumbra.PathResolver.Enabled.ToString());
            PrintValue("Music Manager Streaming Disabled", (!_window._penumbra.MusicManager.StreamingEnabled).ToString());
            PrintValue("Web Server Enabled", (_window._penumbra.WebServer != null).ToString());
        }
Esempio n. 5
0
    private static bool DrawMatrixInput(float width, ref Matrix4x4 matrix)
    {
        using var table = ImRaii.Table(string.Empty, 5, ImGuiTableFlags.BordersInner | ImGuiTableFlags.SizingFixedFit);
        if (!table)
        {
            return(false);
        }

        var changes = false;

        ImGui.TableNextColumn();
        ImGui.TableNextColumn();
        ImGuiUtil.Center("R");
        ImGui.TableNextColumn();
        ImGuiUtil.Center("G");
        ImGui.TableNextColumn();
        ImGuiUtil.Center("B");
        ImGui.TableNextColumn();
        ImGuiUtil.Center("A");

        var inputWidth = width / 6;

        ImGui.TableNextColumn();
        ImGui.AlignTextToFramePadding();
        ImGui.Text("R    ");
        changes |= DragFloat("##RR", inputWidth, ref matrix.M11);
        changes |= DragFloat("##RG", inputWidth, ref matrix.M12);
        changes |= DragFloat("##RB", inputWidth, ref matrix.M13);
        changes |= DragFloat("##RA", inputWidth, ref matrix.M14);

        ImGui.TableNextColumn();
        ImGui.AlignTextToFramePadding();
        ImGui.Text("G    ");
        changes |= DragFloat("##GR", inputWidth, ref matrix.M21);
        changes |= DragFloat("##GG", inputWidth, ref matrix.M22);
        changes |= DragFloat("##GB", inputWidth, ref matrix.M23);
        changes |= DragFloat("##GA", inputWidth, ref matrix.M24);

        ImGui.TableNextColumn();
        ImGui.AlignTextToFramePadding();
        ImGui.Text("B    ");
        changes |= DragFloat("##BR", inputWidth, ref matrix.M31);
        changes |= DragFloat("##BG", inputWidth, ref matrix.M32);
        changes |= DragFloat("##BB", inputWidth, ref matrix.M33);
        changes |= DragFloat("##BA", inputWidth, ref matrix.M34);

        ImGui.TableNextColumn();
        ImGui.AlignTextToFramePadding();
        ImGui.Text("A    ");
        changes |= DragFloat("##AR", inputWidth, ref matrix.M41);
        changes |= DragFloat("##AG", inputWidth, ref matrix.M42);
        changes |= DragFloat("##AB", inputWidth, ref matrix.M43);
        changes |= DragFloat("##AA", inputWidth, ref matrix.M44);

        return(changes);
    }
Esempio n. 6
0
        // Draw information about the character utility class from SE,
        // displaying all files, their sizes, the default files and the default sizes.
        public unsafe void DrawDebugCharacterUtility()
        {
            if (!ImGui.CollapsingHeader("Character Utility"))
            {
                return;
            }

            using var table = ImRaii.Table("##CharacterUtility", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit,
                                           -Vector2.UnitX);
            if (!table)
            {
                return;
            }

            for (var i = 0; i < CharacterUtility.RelevantIndices.Length; ++i)
            {
                var idx      = CharacterUtility.RelevantIndices[i];
                var resource = ( ResourceHandle * )Penumbra.CharacterUtility.Address->Resources[idx];
                ImGui.TableNextColumn();
                ImGui.TextUnformatted($"0x{( ulong )resource:X}");
                ImGui.TableNextColumn();
                Text(resource);
                ImGui.TableNextColumn();
                ImGui.Selectable($"0x{resource->GetData().Data:X}");
                if (ImGui.IsItemClicked())
                {
                    var(data, length) = resource->GetData();
                    if (data != IntPtr.Zero && length > 0)
                    {
                        ImGui.SetClipboardText(string.Join("\n",
                                                           new ReadOnlySpan <byte>(( byte * )data, length).ToArray().Select(b => b.ToString("X2"))));
                    }
                }

                ImGuiUtil.HoverTooltip("Click to copy bytes to clipboard.");

                ImGui.TableNextColumn();
                ImGui.TextUnformatted($"{resource->GetData().Length}");
                ImGui.TableNextColumn();
                ImGui.Selectable($"0x{Penumbra.CharacterUtility.DefaultResources[ i ].Address:X}");
                if (ImGui.IsItemClicked())
                {
                    ImGui.SetClipboardText(string.Join("\n",
                                                       new ReadOnlySpan <byte>(( byte * )Penumbra.CharacterUtility.DefaultResources[i].Address,
                                                                               Penumbra.CharacterUtility.DefaultResources[i].Size).ToArray().Select(b => b.ToString("X2"))));
                }

                ImGuiUtil.HoverTooltip("Click to copy bytes to clipboard.");

                ImGui.TableNextColumn();
                ImGui.TextUnformatted($"{Penumbra.CharacterUtility.DefaultResources[ i ].Size}");
            }
        }
Esempio n. 7
0
        // Draw resources with unusual reference count.
        private static unsafe void DrawResourceProblems()
        {
            var header = ImGui.CollapsingHeader("Resource Problems");

            ImGuiUtil.HoverTooltip("Draw resources with unusually high reference count to detect overflows.");
            if (!header)
            {
                return;
            }

            using var table = ImRaii.Table("##ProblemsTable", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit);
            if (!table)
            {
                return;
            }

            ResourceLoader.IterateResources((_, r) =>
            {
                if (r->RefCount < 10000)
                {
                    return;
                }

                ImGui.TableNextColumn();
                ImGui.TextUnformatted(r->Category.ToString());
                ImGui.TableNextColumn();
                ImGui.TextUnformatted(r->FileType.ToString("X"));
                ImGui.TableNextColumn();
                ImGui.TextUnformatted(r->Id.ToString("X"));
                ImGui.TableNextColumn();
                ImGui.TextUnformatted((( ulong )r).ToString("X"));
                ImGui.TableNextColumn();
                ImGui.TextUnformatted(r->RefCount.ToString());
                ImGui.TableNextColumn();
                ref var name = ref r->FileName;
                if (name.Capacity > 15)
                {
                    ImGuiNative.igTextUnformatted(name.BufferPtr, name.BufferPtr + name.Length);
                }
                else
                {
                    fixed(byte *ptr = name.Buffer)
                    {
                        ImGuiNative.igTextUnformatted(ptr, ptr + name.Length);
                    }
                }
            });
Esempio n. 8
0
        // 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);
                    }
                }
            }
        }
Esempio n. 9
0
        // Draw all resources currently replaced by Penumbra and (if existing) the resources they replace.
        // Resources are collected by iterating through the
        private static unsafe void DrawDebugTabReplacedResources()
        {
            if (!ImGui.CollapsingHeader("Replaced Resources"))
            {
                return;
            }

            Penumbra.ResourceLoader.UpdateDebugInfo();

            if (Penumbra.ResourceLoader.DebugList.Count == 0)
            {
                return;
            }

            using var table = ImRaii.Table("##ReplacedResources", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit,
                                           -Vector2.UnitX);
            if (!table)
            {
                return;
            }

            foreach (var data in Penumbra.ResourceLoader.DebugList.Values.ToArray())
            {
                if (data.ManipulatedPath.Crc64 == 0)
                {
                    continue;
                }

                var refCountManip = data.ManipulatedResource == null ? 0 : data.ManipulatedResource->RefCount;
                var refCountOrig  = data.OriginalResource == null ? 0 : data.OriginalResource->RefCount;
                ImGui.TableNextColumn();
                ImGui.TextUnformatted(data.ManipulatedPath.ToString());
                ImGui.TableNextColumn();
                ImGui.TextUnformatted((( ulong )data.ManipulatedResource).ToString("X"));
                ImGui.TableNextColumn();
                ImGui.TextUnformatted(refCountManip.ToString());
                ImGui.TableNextColumn();
                ImGui.TextUnformatted(data.OriginalPath.ToString());
                ImGui.TableNextColumn();
                ImGui.TextUnformatted((( ulong )data.OriginalResource).ToString("X"));
                ImGui.TableNextColumn();
                ImGui.TextUnformatted(refCountOrig.ToString());
            }
        }
Esempio n. 10
0
            public static void Draw(ModPanel panel, int groupIdx)
            {
                using var table = ImRaii.Table(string.Empty, 4, ImGuiTableFlags.SizingFixedFit);
                if (!table)
                {
                    return;
                }

                ImGui.TableSetupColumn("idx", ImGuiTableColumnFlags.WidthFixed, 60 * ImGuiHelpers.GlobalScale);
                ImGui.TableSetupColumn("name", ImGuiTableColumnFlags.WidthFixed,
                                       panel._window._inputTextWidth.X - 62 * ImGuiHelpers.GlobalScale);
                ImGui.TableSetupColumn("delete", ImGuiTableColumnFlags.WidthFixed, panel._window._iconButtonSize.X);
                ImGui.TableSetupColumn("priority", ImGuiTableColumnFlags.WidthFixed, 50 * ImGuiHelpers.GlobalScale);

                var group = panel._mod.Groups[groupIdx];

                for (var optionIdx = 0; optionIdx < group.Count; ++optionIdx)
                {
                    EditOption(panel, group, groupIdx, optionIdx);
                }

                DrawNewOption(panel._mod, groupIdx, panel._window._iconButtonSize);
            }
Esempio n. 11
0
        // Draw the effective tab if ShowAdvanced is on.
        public void Draw()
        {
            if (!Penumbra.Config.ShowAdvanced)
            {
                return;
            }

            using var tab = ImRaii.TabItem("Effective Changes");
            if (!tab)
            {
                return;
            }

            SetupEffectiveSizes();
            DrawFilters();
            using var child = ImRaii.Child("##EffectiveChangesTab", -Vector2.One, false);
            if (!child)
            {
                return;
            }

            var height = ImGui.GetTextLineHeightWithSpacing() + 2 * ImGui.GetStyle().CellPadding.Y;
            var skips  = ImGuiClip.GetNecessarySkips(height);

            using var table = ImRaii.Table("##EffectiveChangesTable", 3, ImGuiTableFlags.RowBg);
            if (!table)
            {
                return;
            }

            ImGui.TableSetupColumn("##gamePath", ImGuiTableColumnFlags.WidthFixed, _effectiveLeftTextLength);
            ImGui.TableSetupColumn(string.Empty, ImGuiTableColumnFlags.WidthFixed, _effectiveArrowLength);
            ImGui.TableSetupColumn("##file", ImGuiTableColumnFlags.WidthFixed, _effectiveRightTextLength);

            DrawEffectiveRows(Penumbra.CollectionManager.Current, skips, height,
                              _effectiveFilePathFilter.Length > 0 || _effectiveGamePathFilter.Length > 0);
        }
    // Draw a simple clipped table containing all changed items.
    private void DrawChangedItemTab()
    {
        // Functions in here for less pollution.
        bool FilterChangedItem(KeyValuePair <string, (SingleArray <IMod>, object?)> item)
        => (_changedItemFilter.IsEmpty ||
            ChangedItemName(item.Key, item.Value.Item2)
            .Contains(_changedItemFilter.Lower, StringComparison.InvariantCultureIgnoreCase)) &&
        (_changedItemModFilter.IsEmpty || item.Value.Item1.Any(m => m.Name.Contains(_changedItemModFilter)));

        void DrawChangedItemColumn(KeyValuePair <string, (SingleArray <IMod>, object?)> item)
        {
            ImGui.TableNextColumn();
            DrawChangedItem(item.Key, item.Value.Item2, false);
            ImGui.TableNextColumn();
            if (item.Value.Item1.Count > 0)
            {
                ImGui.TextUnformatted(item.Value.Item1[0].Name);
                if (item.Value.Item1.Count > 1)
                {
                    ImGuiUtil.HoverTooltip(string.Join("\n", item.Value.Item1.Skip(1).Select(m => m.Name)));
                }
            }

            ImGui.TableNextColumn();
            if (item.Value.Item2 is Item it)
            {
                using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.ItemId.Value());
                ImGuiUtil.RightAlign($"({( ( Quad )it.ModelMain ).A})");
            }
        }

        using var tab = ImRaii.TabItem("Changed Items");
        if (!tab)
        {
            return;
        }

        // Draw filters.
        var varWidth = ImGui.GetContentRegionAvail().X
                       - 400 * ImGuiHelpers.GlobalScale
                       - ImGui.GetStyle().ItemSpacing.X;

        ImGui.SetNextItemWidth(400 * ImGuiHelpers.GlobalScale);
        LowerString.InputWithHint("##changedItemsFilter", "Filter Item...", ref _changedItemFilter, 128);
        ImGui.SameLine();
        ImGui.SetNextItemWidth(varWidth);
        LowerString.InputWithHint("##changedItemsModFilter", "Filter Mods...", ref _changedItemModFilter, 128);

        using var child = ImRaii.Child("##changedItemsChild", -Vector2.One);
        if (!child)
        {
            return;
        }

        // Draw table of changed items.
        var height = ImGui.GetTextLineHeightWithSpacing() + 2 * ImGui.GetStyle().CellPadding.Y;
        var skips  = ImGuiClip.GetNecessarySkips(height);

        using var list = ImRaii.Table("##changedItems", 3, ImGuiTableFlags.RowBg, -Vector2.One);
        if (!list)
        {
            return;
        }

        const ImGuiTableColumnFlags flags = ImGuiTableColumnFlags.NoResize | ImGuiTableColumnFlags.WidthFixed;

        ImGui.TableSetupColumn("items", flags, 400 * ImGuiHelpers.GlobalScale);
        ImGui.TableSetupColumn("mods", flags, varWidth - 100 * ImGuiHelpers.GlobalScale);
        ImGui.TableSetupColumn("id", flags, 100 * ImGuiHelpers.GlobalScale);

        var items = Penumbra.CollectionManager.Current.ChangedItems;
        var rest  = _changedItemFilter.IsEmpty && _changedItemModFilter.IsEmpty
            ? ImGuiClip.ClippedDraw(items, skips, DrawChangedItemColumn, items.Count)
            : ImGuiClip.FilteredClippedDraw(items, skips, FilterChangedItem, DrawChangedItemColumn);

        ImGuiClip.DrawEndDummy(rest, height);
    }
Esempio n. 13
0
        // Draw information about the models, materials and resources currently loaded by the local player.
        private static unsafe void DrawPlayerModelInfo()
        {
            var player = Dalamud.ClientState.LocalPlayer;
            var name   = player?.Name.ToString() ?? "NULL";

            if (!ImGui.CollapsingHeader($"Player Model Info: {name}##Draw") || player == null)
            {
                return;
            }

            var model = ( CharacterBase * )(( Character * )player.Address)->GameObject.GetDrawObject();

            if (model == null)
            {
                return;
            }

            using var table = ImRaii.Table($"##{name}DrawTable", 5, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit);
            if (!table)
            {
                return;
            }

            ImGui.TableNextColumn();
            ImGui.TableHeader("Slot");
            ImGui.TableNextColumn();
            ImGui.TableHeader("Imc Ptr");
            ImGui.TableNextColumn();
            ImGui.TableHeader("Imc File");
            ImGui.TableNextColumn();
            ImGui.TableHeader("Model Ptr");
            ImGui.TableNextColumn();
            ImGui.TableHeader("Model File");

            for (var i = 0; i < model->SlotCount; ++i)
            {
                var imc = ( ResourceHandle * )model->IMCArray[i];
                ImGui.TableNextRow();
                ImGui.TableNextColumn();
                ImGui.TextUnformatted($"Slot {i}");
                ImGui.TableNextColumn();
                ImGui.TextUnformatted(imc == null ? "NULL" : $"0x{( ulong )imc:X}");
                ImGui.TableNextColumn();
                if (imc != null)
                {
                    Text(imc);
                }

                var mdl = ( RenderModel * )model->ModelArray[i];
                ImGui.TableNextColumn();
                ImGui.TextUnformatted(mdl == null ? "NULL" : $"0x{( ulong )mdl:X}");
                if (mdl == null || mdl->ResourceHandle == null || mdl->ResourceHandle->Category != ResourceCategory.Chara)
                {
                    continue;
                }

                ImGui.TableNextColumn();
                {
                    Text(mdl->ResourceHandle);
                }
            }
        }