From 4aa19e49d59ac3a31f9ba05d7ba37243f8fb2d0f Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Fri, 22 Dec 2023 14:22:03 +0100 Subject: [PATCH] Add filtering mods by changed item categories. --- Penumbra.GameData | 2 +- Penumbra/Mods/ItemSwap/EquipmentSwap.cs | 2 +- Penumbra/UI/ChangedItemDrawer.cs | 92 ++++++++++++++----- .../CollectionTab/IndividualAssignmentUi.cs | 2 +- Penumbra/UI/ModsTab/ModFileSystemSelector.cs | 25 +++-- 5 files changed, 89 insertions(+), 34 deletions(-) diff --git a/Penumbra.GameData b/Penumbra.GameData index 3787e82d..58a3e794 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit 3787e82d1b84d2542b6e4238060d75383a4b12a1 +Subproject commit 58a3e7947c207452f5fa0d328c47c5ed6bdd9a0f diff --git a/Penumbra/Mods/ItemSwap/EquipmentSwap.cs b/Penumbra/Mods/ItemSwap/EquipmentSwap.cs index f7f82a59..516df251 100644 --- a/Penumbra/Mods/ItemSwap/EquipmentSwap.cs +++ b/Penumbra/Mods/ItemSwap/EquipmentSwap.cs @@ -242,7 +242,7 @@ public static class EquipmentSwap if (!slot.IsEquipmentPiece()) throw new ItemSwap.InvalidItemTypeException(); - modelId = i.ModelId; + modelId = i.PrimaryId; variant = i.Variant; } diff --git a/Penumbra/UI/ChangedItemDrawer.cs b/Penumbra/UI/ChangedItemDrawer.cs index 0a1d58f9..638afef0 100644 --- a/Penumbra/UI/ChangedItemDrawer.cs +++ b/Penumbra/UI/ChangedItemDrawer.cs @@ -43,8 +43,71 @@ public class ChangedItemDrawer : IDisposable Emote = 0x01_00_00, } - public const ChangedItemIcon AllFlags = (ChangedItemIcon)0x01FFFF; - public const ChangedItemIcon DefaultFlags = AllFlags & ~ChangedItemIcon.Offhand; + private static readonly ChangedItemIcon[] Order = + [ + ChangedItemIcon.Head, + ChangedItemIcon.Body, + ChangedItemIcon.Hands, + ChangedItemIcon.Legs, + ChangedItemIcon.Feet, + ChangedItemIcon.Ears, + ChangedItemIcon.Neck, + ChangedItemIcon.Wrists, + ChangedItemIcon.Finger, + ChangedItemIcon.Mainhand, + ChangedItemIcon.Offhand, + ChangedItemIcon.Customization, + ChangedItemIcon.Action, + ChangedItemIcon.Emote, + ChangedItemIcon.Monster, + ChangedItemIcon.Demihuman, + ChangedItemIcon.Unknown, + ]; + + private static readonly string[] LowerNames = Order.Select(f => ToDescription(f).ToLowerInvariant()).ToArray(); + + public static bool TryParseIndex(ReadOnlySpan input, out ChangedItemIcon slot) + { + // Handle numeric cases before TryParse because numbers + // are not logical otherwise. + if (int.TryParse(input, out var idx)) + { + // We assume users will use 1-based index, but if they enter 0, just use the first. + if (idx == 0) + { + slot = Order[0]; + return true; + } + + // Use 1-based index. + --idx; + if (idx >= 0 && idx < Order.Length) + { + slot = Order[idx]; + return true; + } + } + + slot = 0; + return false; + } + + public static bool TryParsePartial(string lowerInput, out ChangedItemIcon slot) + { + if (TryParseIndex(lowerInput, out slot)) + return true; + + slot = 0; + foreach (var (item, flag) in LowerNames.Zip(Order)) + if (item.Contains(lowerInput, StringComparison.Ordinal)) + slot |= flag; + + return slot != 0; + } + + public const ChangedItemIcon AllFlags = (ChangedItemIcon)0x01FFFF; + public static readonly int NumCategories = Order.Length; + public const ChangedItemIcon DefaultFlags = AllFlags & ~ChangedItemIcon.Offhand; private readonly Configuration _config; private readonly ExcelSheet _items; @@ -163,26 +226,7 @@ public class ChangedItemDrawer : IDisposable using var _ = ImRaii.PushId("ChangedItemIconFilter"); var size = TypeFilterIconSize; using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero); - var order = new[] - { - ChangedItemIcon.Head, - ChangedItemIcon.Body, - ChangedItemIcon.Hands, - ChangedItemIcon.Legs, - ChangedItemIcon.Feet, - ChangedItemIcon.Ears, - ChangedItemIcon.Neck, - ChangedItemIcon.Wrists, - ChangedItemIcon.Finger, - ChangedItemIcon.Mainhand, - ChangedItemIcon.Offhand, - ChangedItemIcon.Customization, - ChangedItemIcon.Action, - ChangedItemIcon.Emote, - ChangedItemIcon.Monster, - ChangedItemIcon.Demihuman, - ChangedItemIcon.Unknown, - }; + bool DrawIcon(ChangedItemIcon type, ref ChangedItemIcon typeFilter) { @@ -217,13 +261,13 @@ public class ChangedItemDrawer : IDisposable return ret; } - foreach (var iconType in order) + foreach (var iconType in Order) { ret |= DrawIcon(iconType, ref typeFilter); ImGui.SameLine(); } - ImGui.SetCursorPos(new(ImGui.GetContentRegionMax().X - size.X, ImGui.GetCursorPosY() + yOffset)); + ImGui.SetCursorPos(new Vector2(ImGui.GetContentRegionMax().X - size.X, ImGui.GetCursorPosY() + yOffset)); ImGui.Image(_icons[AllFlags].ImGuiHandle, size, Vector2.Zero, Vector2.One, typeFilter == 0 ? new Vector4(0.6f, 0.3f, 0.3f, 1f) : typeFilter == AllFlags ? new Vector4(0.75f, 0.75f, 0.75f, 1f) : new Vector4(0.5f, 0.5f, 1f, 1f)); diff --git a/Penumbra/UI/CollectionTab/IndividualAssignmentUi.cs b/Penumbra/UI/CollectionTab/IndividualAssignmentUi.cs index d3e4ab5e..a0e35cff 100644 --- a/Penumbra/UI/CollectionTab/IndividualAssignmentUi.cs +++ b/Penumbra/UI/CollectionTab/IndividualAssignmentUi.cs @@ -126,7 +126,7 @@ public class IndividualAssignmentUi : IDisposable /// Create combos when ready. private void SetupCombos() { - _worldCombo = new WorldCombo(_actors.Data.Worlds, Penumbra.Log, WorldId.AnyWorld); + _worldCombo = new WorldCombo(_actors.Data.Worlds, Penumbra.Log); _mountCombo = new NpcCombo("##mountCombo", _actors.Data.Mounts, Penumbra.Log); _companionCombo = new NpcCombo("##companionCombo", _actors.Data.Companions, Penumbra.Log); _ornamentCombo = new NpcCombo("##ornamentCombo", _actors.Data.Ornaments, Penumbra.Log); diff --git a/Penumbra/UI/ModsTab/ModFileSystemSelector.cs b/Penumbra/UI/ModsTab/ModFileSystemSelector.cs index 8f12afbb..c42b1018 100644 --- a/Penumbra/UI/ModsTab/ModFileSystemSelector.cs +++ b/Penumbra/UI/ModsTab/ModFileSystemSelector.cs @@ -12,6 +12,8 @@ using Penumbra.Api.Enums; using Penumbra.Collections; using Penumbra.Collections.Manager; using Penumbra.Communication; +using Penumbra.GameData.Enums; +using Penumbra.GameData.Structs; using Penumbra.Mods; using Penumbra.Mods.Manager; using Penumbra.Mods.Subclasses; @@ -190,7 +192,7 @@ public sealed class ModFileSystemSelector : FileSystemSelector filterValue.Length == 2 ? (LowerString.Empty, -1) : ParseFilter(filterValue, 3), 't' => filterValue.Length == 2 ? (LowerString.Empty, -1) : ParseFilter(filterValue, 4), 'T' => filterValue.Length == 2 ? (LowerString.Empty, -1) : ParseFilter(filterValue, 4), + 's' => filterValue.Length == 2 ? (LowerString.Empty, -1) : ParseFilter(filterValue, 5), + 'S' => filterValue.Length == 2 ? (LowerString.Empty, -1) : ParseFilter(filterValue, 5), _ => (new LowerString(filterValue), 0), }, _ => (new LowerString(filterValue), 0), @@ -549,10 +555,13 @@ public sealed class ModFileSystemSelector : FileSystemSelector !mod.Author.Contains(_modFilter), 3 => !mod.LowerChangedItemsString.Contains(_modFilter.Lower), 4 => !mod.AllTagsLower.Contains(_modFilter.Lower), + 5 => mod.ChangedItems.All(p => (ChangedItemDrawer.GetCategoryIcon(p.Key, p.Value) & _slotFilter) == 0), 2 + EmptyOffset => !mod.Author.IsEmpty, 3 + EmptyOffset => mod.LowerChangedItemsString.Length > 0, 4 + EmptyOffset => mod.AllTagsLower.Length > 0, + 5 + EmptyOffset => mod.ChangedItems.Count == 0, _ => false, // Should never happen }; }