mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 20:24:17 +01:00
Add filtering mods by changed item categories.
This commit is contained in:
parent
2051197c65
commit
4aa19e49d5
5 changed files with 89 additions and 34 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit 3787e82d1b84d2542b6e4238060d75383a4b12a1
|
||||
Subproject commit 58a3e7947c207452f5fa0d328c47c5ed6bdd9a0f
|
||||
|
|
@ -242,7 +242,7 @@ public static class EquipmentSwap
|
|||
if (!slot.IsEquipmentPiece())
|
||||
throw new ItemSwap.InvalidItemTypeException();
|
||||
|
||||
modelId = i.ModelId;
|
||||
modelId = i.PrimaryId;
|
||||
variant = i.Variant;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<char> 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<Item> _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));
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ public class IndividualAssignmentUi : IDisposable
|
|||
/// <summary> Create combos when ready. </summary>
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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<Mod, ModFileSyste
|
|||
var itemPos = ImGui.GetItemRectMax().X;
|
||||
var maxWidth = ImGui.GetWindowPos().X + ImGui.GetWindowContentRegionMax().X;
|
||||
var priorityString = $"[{state.Priority}]";
|
||||
var Size = ImGui.CalcTextSize(priorityString).X;
|
||||
var Size = ImGui.CalcTextSize(priorityString).X;
|
||||
var remainingSpace = maxWidth - itemPos;
|
||||
var offset = remainingSpace - Size;
|
||||
if (ImGui.GetScrollMaxY() == 0)
|
||||
|
|
@ -507,10 +509,11 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
|
|||
public int Priority;
|
||||
}
|
||||
|
||||
private const StringComparison IgnoreCase = StringComparison.OrdinalIgnoreCase;
|
||||
private LowerString _modFilter = LowerString.Empty;
|
||||
private int _filterType = -1;
|
||||
private ModFilter _stateFilter = ModFilterExtensions.UnfilteredStateMods;
|
||||
private const StringComparison IgnoreCase = StringComparison.OrdinalIgnoreCase;
|
||||
private LowerString _modFilter = LowerString.Empty;
|
||||
private int _filterType = -1;
|
||||
private ModFilter _stateFilter = ModFilterExtensions.UnfilteredStateMods;
|
||||
private ChangedItemDrawer.ChangedItemIcon _slotFilter = 0;
|
||||
|
||||
private void SetFilterTooltip()
|
||||
{
|
||||
|
|
@ -518,7 +521,8 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
|
|||
+ "Enter c:[string] to filter for mods changing specific items.\n"
|
||||
+ "Enter t:[string] to filter for mods set to specific tags.\n"
|
||||
+ "Enter n:[string] to filter only for mod names and no paths.\n"
|
||||
+ "Enter a:[string] to filter for mods by specific authors.\n\n"
|
||||
+ "Enter a:[string] to filter for mods by specific authors.\n"
|
||||
+ $"Enter s:[string] to filter for mods by the categories of the items they change (1-{ChangedItemDrawer.NumCategories+1} or partial category name).\n"
|
||||
+ "Use None as a placeholder value that only matches empty lists or names.";
|
||||
}
|
||||
|
||||
|
|
@ -539,6 +543,8 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
|
|||
'C' => 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, ModFileSyste
|
|||
|
||||
private const int EmptyOffset = 128;
|
||||
|
||||
private static (LowerString, int) ParseFilter(string value, int id)
|
||||
private (LowerString, int) ParseFilter(string value, int id)
|
||||
{
|
||||
value = value[2..];
|
||||
var lower = new LowerString(value);
|
||||
if (id == 5 && !ChangedItemDrawer.TryParsePartial(lower.Lower, out _slotFilter))
|
||||
_slotFilter = 0;
|
||||
|
||||
return (lower, lower.Lower is "none" ? id + EmptyOffset : id);
|
||||
}
|
||||
|
||||
|
|
@ -602,9 +611,11 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
|
|||
2 => !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
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue