Add more mod association and modded utility.

This commit is contained in:
Ottermandias 2025-02-13 16:32:23 +01:00
parent ab2a3f5bd9
commit d56c2db547
9 changed files with 277 additions and 90 deletions

View file

@ -17,7 +17,6 @@ using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using OtterGui.Text;
using OtterGuiInternal.Structs;
using Penumbra.GameData.Enums;
using static Glamourer.Gui.Tabs.HeaderDrawer;

View file

@ -15,7 +15,7 @@ namespace Glamourer.Gui.Tabs.DesignTab;
public class ModAssociationsTab(PenumbraService penumbra, DesignFileSystemSelector selector, DesignManager manager, Configuration config)
{
private readonly ModCombo _modCombo = new(penumbra, Glamourer.Log);
private readonly ModCombo _modCombo = new(penumbra, Glamourer.Log, selector);
private (Mod, ModSettings)[]? _copy;
public void Draw()

View file

@ -4,19 +4,18 @@ using ImGuiNET;
using OtterGui.Classes;
using OtterGui.Log;
using OtterGui.Raii;
using OtterGui.Text;
using OtterGui.Widgets;
namespace Glamourer.Gui.Tabs.DesignTab;
public sealed class ModCombo : FilterComboCache<(Mod Mod, ModSettings Settings)>
public sealed class ModCombo : FilterComboCache<(Mod Mod, ModSettings Settings, int Count)>
{
public ModCombo(PenumbraService penumbra, Logger log)
: base(penumbra.GetMods, MouseWheelType.None, log)
{
SearchByParts = false;
}
public ModCombo(PenumbraService penumbra, Logger log, DesignFileSystemSelector selector)
: base(() => penumbra.GetMods(selector.Selected?.FilteredItemNames.ToArray() ?? []), MouseWheelType.None, log)
=> SearchByParts = false;
protected override string ToString((Mod Mod, ModSettings Settings) obj)
protected override string ToString((Mod Mod, ModSettings Settings, int Count) obj)
=> obj.Mod.Name;
protected override bool IsVisible(int globalIndex, LowerString filter)
@ -24,36 +23,45 @@ public sealed class ModCombo : FilterComboCache<(Mod Mod, ModSettings Settings)>
protected override bool DrawSelectable(int globalIdx, bool selected)
{
using var id = ImRaii.PushId(globalIdx);
var (mod, settings) = Items[globalIdx];
using var id = ImUtf8.PushId(globalIdx);
var (mod, settings, count) = Items[globalIdx];
bool ret;
using (var color = ImRaii.PushColor(ImGuiCol.Text, ImGui.GetColorU32(ImGuiCol.TextDisabled), !settings.Enabled))
var color = settings.Enabled
? count > 0
? ColorId.ContainsItemsEnabled.Value()
: ImGui.GetColorU32(ImGuiCol.Text)
: count > 0
? ColorId.ContainsItemsDisabled.Value()
: ImGui.GetColorU32(ImGuiCol.TextDisabled);
using (ImRaii.PushColor(ImGuiCol.Text, color))
{
ret = ImGui.Selectable(mod.Name, selected);
ret = ImUtf8.Selectable(mod.Name, selected);
}
if (ImGui.IsItemHovered())
{
using var style = ImRaii.PushStyle(ImGuiStyleVar.PopupBorderSize, 2 * ImGuiHelpers.GlobalScale);
using var tt = ImRaii.Tooltip();
using var tt = ImUtf8.Tooltip();
var namesDifferent = mod.Name != mod.DirectoryName;
ImGui.Dummy(new Vector2(300 * ImGuiHelpers.GlobalScale, 0));
using (var group = ImRaii.Group())
using (ImUtf8.Group())
{
if (namesDifferent)
ImGui.TextUnformatted("Directory Name");
ImGui.TextUnformatted("Enabled");
ImGui.TextUnformatted("Priority");
ImUtf8.Text("Directory Name"u8);
ImUtf8.Text("Enabled"u8);
ImUtf8.Text("Priority"u8);
ImUtf8.Text("Affected Design Items"u8);
DrawSettingsLeft(settings);
}
ImGui.SameLine(Math.Max(ImGui.GetItemRectSize().X + 3 * ImGui.GetStyle().ItemSpacing.X, 150 * ImGuiHelpers.GlobalScale));
using (var group = ImRaii.Group())
using (ImUtf8.Group())
{
if (namesDifferent)
ImGui.TextUnformatted(mod.DirectoryName);
ImGui.TextUnformatted(settings.Enabled.ToString());
ImGui.TextUnformatted(settings.Priority.ToString());
ImUtf8.Text(mod.DirectoryName);
ImUtf8.Text($"{settings.Enabled}");
ImUtf8.Text($"{settings.Priority}");
ImUtf8.Text($"{count}");
DrawSettingsRight(settings);
}
}
@ -65,7 +73,7 @@ public sealed class ModCombo : FilterComboCache<(Mod Mod, ModSettings Settings)>
{
foreach (var setting in settings.Settings)
{
ImGui.TextUnformatted(setting.Key);
ImUtf8.Text(setting.Key);
for (var i = 1; i < setting.Value.Count; ++i)
ImGui.NewLine();
}
@ -76,10 +84,10 @@ public sealed class ModCombo : FilterComboCache<(Mod Mod, ModSettings Settings)>
foreach (var setting in settings.Settings)
{
if (setting.Value.Count == 0)
ImGui.TextUnformatted("<None Enabled>");
ImUtf8.Text("<None Enabled>"u8);
else
foreach (var option in setting.Value)
ImGui.TextUnformatted(option);
ImUtf8.Text(option);
}
}
}

View file

@ -5,11 +5,15 @@ using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using OtterGui.Text;
using static Glamourer.Gui.Tabs.HeaderDrawer;
namespace Glamourer.Gui.Tabs.DesignTab;
public class MultiDesignPanel(DesignFileSystemSelector selector, DesignManager editor, DesignColors colors)
public class MultiDesignPanel(DesignFileSystemSelector selector, DesignManager editor, DesignColors colors, Configuration config)
{
private readonly Button[] _leftButtons = [];
private readonly Button[] _rightButtons = [new IncognitoButton(config.Ephemeral)];
private readonly DesignColorCombo _colorCombo = new(colors, true);
public void Draw()
@ -17,8 +21,12 @@ public class MultiDesignPanel(DesignFileSystemSelector selector, DesignManager e
if (selector.SelectedPaths.Count == 0)
return;
var width = ImGuiHelpers.ScaledVector2(145, 0);
ImGui.NewLine();
HeaderDrawer.Draw(string.Empty, 0, ImGui.GetColorU32(ImGuiCol.FrameBg), _leftButtons, _rightButtons);
using var child = ImUtf8.Child("##MultiPanel"u8, default, true);
if (!child)
return;
var width = ImGuiHelpers.ScaledVector2(145, 0);
var treeNodePos = ImGui.GetCursorPos();
_numDesigns = DrawDesignList();
DrawCounts(treeNodePos);
@ -135,7 +143,7 @@ public class MultiDesignPanel(DesignFileSystemSelector selector, DesignManager e
{
ImUtf8.TextFrameAligned("Multi Tagger:"u8);
ImGui.SameLine();
var offset = ImGui.GetItemRectSize().X;
var offset = ImGui.GetItemRectSize().X + ImGui.GetStyle().WindowPadding.X;
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X - 2 * (width.X + ImGui.GetStyle().ItemSpacing.X));
ImUtf8.InputText("##tag"u8, ref _tag, "Tag Name..."u8);

View file

@ -1,8 +1,8 @@
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Interface.Utility;
using Glamourer.Designs;
using Glamourer.GameData;
using Glamourer.Interop;
using Glamourer.Interop.Penumbra;
using Glamourer.Services;
using Glamourer.Unlocks;
using ImGuiNET;
@ -23,7 +23,8 @@ public class UnlockOverview(
TextureService textures,
CodeService codes,
JobService jobs,
FavoriteManager favorites)
FavoriteManager favorites,
PenumbraService penumbra)
{
private static readonly Vector4 UnavailableTint = new(0.3f, 0.3f, 0.3f, 1.0f);
@ -32,6 +33,9 @@ public class UnlockOverview(
private Gender _selected3 = Gender.Unknown;
private BonusItemFlag _selected4 = BonusItemFlag.Unknown;
private uint _favoriteColor;
private uint _moddedColor;
private void DrawSelector()
{
using var child = ImRaii.Child("Selector", new Vector2(200 * ImGuiHelpers.GlobalScale, -1), true);
@ -90,6 +94,9 @@ public class UnlockOverview(
if (!child)
return;
_moddedColor = ColorId.ModdedItemMarker.Value();
_favoriteColor = ColorId.FavoriteStarOn.Value();
if (_selected1 is not FullEquipType.Unknown)
DrawItems();
else if (_selected2 is not SubRace.Unknown && _selected3 is not Gender.Unknown)
@ -120,7 +127,7 @@ public class UnlockOverview(
unlocked || codes.Enabled(CodeService.CodeFlag.Shirts) ? Vector4.One : UnavailableTint);
if (favorites.Contains(_selected3, _selected2, customize.Index, customize.Value))
ImGui.GetWindowDrawList().AddRect(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), ColorId.FavoriteStarOn.Value(),
ImGui.GetWindowDrawList().AddRect(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), _favoriteColor,
12 * ImGuiHelpers.GlobalScale, ImDrawFlags.RoundCornersAll, 6 * ImGuiHelpers.GlobalScale);
if (hasIcon && ImGui.IsItemHovered())
@ -192,9 +199,11 @@ public class UnlockOverview(
ImGui.Image(icon, iconSize, Vector2.Zero, Vector2.One,
unlocked || codes.Enabled(CodeService.CodeFlag.Shirts) ? Vector4.One : UnavailableTint);
if (favorites.Contains(item))
ImGui.GetWindowDrawList().AddRect(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), ColorId.FavoriteStarOn.Value(),
ImGui.GetWindowDrawList().AddRect(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), _favoriteColor,
2 * ImGuiHelpers.GlobalScale, ImDrawFlags.RoundCornersAll, 4 * ImGuiHelpers.GlobalScale);
var mods = DrawModdedMarker(item, iconSize);
// TODO handle clicking
if (ImGui.IsItemHovered())
{
@ -206,9 +215,10 @@ public class UnlockOverview(
ImUtf8.Text($"{item.Id.Id}");
ImUtf8.Text($"{item.PrimaryId.Id}-{item.Variant.Id}");
// TODO
ImUtf8.Text("Always Unlocked"); // : $"Unlocked on {time:g}" : "Not Unlocked.");
ImUtf8.Text("Always Unlocked"u8); // : $"Unlocked on {time:g}" : "Not Unlocked.");
// TODO
//tooltip.CreateTooltip(item, string.Empty, false);
DrawModTooltip(mods);
}
}
}
@ -263,6 +273,8 @@ public class UnlockOverview(
ImGui.GetWindowDrawList().AddRect(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), ColorId.FavoriteStarOn.Value(),
2 * ImGuiHelpers.GlobalScale, ImDrawFlags.RoundCornersAll, 4 * ImGuiHelpers.GlobalScale);
var mods = DrawModdedMarker(item, iconSize);
if (ImGui.IsItemClicked())
Glamourer.Messager.Chat.Print(new SeStringBuilder().AddItemLink(item.ItemId.Id, false).BuiltString);
@ -306,6 +318,7 @@ public class UnlockOverview(
ImGui.TextUnformatted("Tradable");
if (item.Flags.HasFlag(ItemFlags.IsCrestWorthy))
ImGui.TextUnformatted("Can apply Crest");
DrawModTooltip(mods);
tooltip.CreateTooltip(item, string.Empty, false);
}
}
@ -316,4 +329,36 @@ public class UnlockOverview(
private static int IconsPerRow(float iconWidth, float iconSpacing)
=> (int)(ImGui.GetContentRegionAvail().X / (iconWidth + iconSpacing));
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
private (string ModDirectory, string ModName)[] DrawModdedMarker(in EquipItem item, Vector2 iconSize)
{
var mods = penumbra.CheckCurrentChangedItem(item.Name);
if (mods.Length == 0)
return mods;
var center = ImGui.GetItemRectMin() + new Vector2(iconSize.X * 0.85f, iconSize.Y * 0.15f);
ImGui.GetWindowDrawList().AddCircleFilled(center, iconSize.X * 0.1f, _moddedColor);
ImGui.GetWindowDrawList().AddCircle(center, iconSize.X * 0.1f, 0xFF000000);
return mods;
}
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
private void DrawModTooltip((string ModDirectory, string ModName)[] mods)
{
switch (mods.Length)
{
case 0: return;
case 1:
ImUtf8.Text("Modded by: "u8, _moddedColor);
ImGui.SameLine(0, 0);
ImUtf8.Text(mods[0].ModName);
return;
default:
ImUtf8.Text("Modded by:"u8, _moddedColor);
foreach (var (_, mod) in mods)
ImUtf8.BulletText(mod);
return;
}
}
}

View file

@ -3,6 +3,7 @@ using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Glamourer.Events;
using Glamourer.Interop;
using Glamourer.Interop.Penumbra;
using Glamourer.Services;
using Glamourer.Unlocks;
using ImGuiNET;
@ -17,12 +18,16 @@ namespace Glamourer.Gui.Tabs.UnlocksTab;
public class UnlockTable : Table<EquipItem>, IDisposable
{
private readonly ObjectUnlocked _event;
private readonly ObjectUnlocked _event;
private readonly PenumbraService _penumbra;
private Guid _lastCurrentCollection = Guid.Empty;
public UnlockTable(ItemManager items, TextureService textures, ItemUnlockManager itemUnlocks,
PenumbraChangedItemTooltip tooltip, ObjectUnlocked @event, JobService jobs, FavoriteManager favorites)
PenumbraChangedItemTooltip tooltip, ObjectUnlocked @event, JobService jobs, FavoriteManager favorites, PenumbraService penumbra)
: base("ItemUnlockTable", new ItemList(items),
new FavoriteColumn(favorites, @event) { Label = "F" },
new ModdedColumn(penumbra) { Label = "M" },
new NameColumn(textures, tooltip) { Label = "Item Name..." },
new SlotColumn { Label = "Equip Slot" },
new TypeColumn { Label = "Item Type..." },
@ -36,14 +41,40 @@ public class UnlockTable : Table<EquipItem>, IDisposable
new TradableColumn { Label = "Trade" }
)
{
_event = @event;
Sortable = true;
Flags |= ImGuiTableFlags.Hideable | ImGuiTableFlags.Reorderable | ImGuiTableFlags.Resizable;
_event = @event;
_penumbra = penumbra;
Sortable = true;
Flags |= ImGuiTableFlags.Hideable | ImGuiTableFlags.Reorderable | ImGuiTableFlags.Resizable;
_event.Subscribe(OnObjectUnlock, ObjectUnlocked.Priority.UnlockTable);
_penumbra.ModSettingChanged += OnModSettingsChanged;
}
private void OnModSettingsChanged(Penumbra.Api.Enums.ModSettingChange type, Guid collection, string mod, bool inherited)
{
if (collection != _lastCurrentCollection)
return;
FilterDirty = true;
SortDirty = true;
}
protected override void PreDraw()
{
var lastCurrentCollection = _penumbra.CurrentCollection.Id;
if (_lastCurrentCollection != lastCurrentCollection)
{
_lastCurrentCollection = lastCurrentCollection;
FilterDirty = true;
SortDirty = true;
}
}
public void Dispose()
=> _event.Unsubscribe(OnObjectUnlock);
{
_event.Unsubscribe(OnObjectUnlock);
_penumbra.ModSettingChanged -= OnModSettingsChanged;
}
private sealed class FavoriteColumn : YesNoColumn<EquipItem>
{
@ -77,6 +108,66 @@ public class UnlockTable : Table<EquipItem>, IDisposable
=> _favorites.Contains(rhs).CompareTo(_favorites.Contains(lhs));
}
private sealed class ModdedColumn : YesNoColumn<EquipItem>
{
public override float Width
=> ImGui.GetFrameHeightWithSpacing();
private readonly PenumbraService _penumbra;
private readonly Dictionary<CustomItemId, int> _compareCache = [];
public ModdedColumn(PenumbraService penumbra)
{
_penumbra = penumbra;
Flags |= ImGuiTableColumnFlags.NoResize;
}
public override void PostSort()
{
_compareCache.Clear();
}
public override void DrawColumn(EquipItem item, int idx)
{
var value = _penumbra.CheckCurrentChangedItem(item.Name);
if (value.Length == 0)
return;
using (ImRaii.PushFont(UiBuilder.IconFont))
{
using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.ModdedItemMarker.Value());
ImGuiUtil.Center(FontAwesomeIcon.Circle.ToIconString());
}
if (ImGui.IsItemHovered())
{
using var tt = ImUtf8.Tooltip();
foreach (var (_, mod) in value)
ImUtf8.BulletText(mod);
}
}
public override bool FilterFunc(EquipItem item)
=> FilterValue.HasFlag(_penumbra.CheckCurrentChangedItem(item.Name).Length > 0 ? YesNoFlag.Yes : YesNoFlag.No);
public override int Compare(EquipItem lhs, EquipItem rhs)
{
if (!_compareCache.TryGetValue(lhs.Id, out var lhsCount))
{
lhsCount = _penumbra.CheckCurrentChangedItem(lhs.Name).Length;
_compareCache[lhs.Id] = lhsCount;
}
if (!_compareCache.TryGetValue(rhs.Id, out var rhsCount))
{
rhsCount = _penumbra.CheckCurrentChangedItem(rhs.Name).Length;
_compareCache[rhs.Id] = rhsCount;
}
return lhsCount.CompareTo(rhsCount);
}
}
private sealed class NameColumn : ColumnString<EquipItem>
{
private readonly TextureService _textures;
@ -317,7 +408,6 @@ public class UnlockTable : Table<EquipItem>, IDisposable
{ }
}
private sealed class JobColumn : ColumnFlags<JobFlag, EquipItem>
{
public override float Width
@ -415,7 +505,6 @@ public class UnlockTable : Table<EquipItem>, IDisposable
}
}
private sealed class DyableColumn : ColumnFlags<DyableColumn.Dyable, EquipItem>
{
[Flags]

View file

@ -38,6 +38,7 @@ public class PenumbraService : IDisposable
public const int RequiredPenumbraFeatureVersionTemp = 4;
public const int RequiredPenumbraFeatureVersionTemp2 = 5;
public const int RequiredPenumbraFeatureVersionTemp3 = 6;
public const int RequiredPenumbraFeatureVersionTemp4 = 7;
private const int Key = -1610;
@ -49,30 +50,33 @@ public class PenumbraService : IDisposable
private readonly EventSubscriber<nint, Guid, nint> _createdCharacterBase;
private readonly EventSubscriber<ModSettingChange, Guid, string, bool> _modSettingChanged;
private global::Penumbra.Api.IpcSubscribers.GetCollectionsByIdentifier? _collectionByIdentifier;
private global::Penumbra.Api.IpcSubscribers.GetCollections? _collections;
private global::Penumbra.Api.IpcSubscribers.RedrawObject? _redraw;
private global::Penumbra.Api.IpcSubscribers.GetDrawObjectInfo? _drawObjectInfo;
private global::Penumbra.Api.IpcSubscribers.GetCutsceneParentIndex? _cutsceneParent;
private global::Penumbra.Api.IpcSubscribers.GetCollectionForObject? _objectCollection;
private global::Penumbra.Api.IpcSubscribers.GetModList? _getMods;
private global::Penumbra.Api.IpcSubscribers.GetCollection? _currentCollection;
private global::Penumbra.Api.IpcSubscribers.GetCurrentModSettingsWithTemp? _getCurrentSettingsWithTemp;
private global::Penumbra.Api.IpcSubscribers.GetCurrentModSettings? _getCurrentSettings;
private global::Penumbra.Api.IpcSubscribers.GetAllModSettings? _getAllSettings;
private global::Penumbra.Api.IpcSubscribers.TryInheritMod? _inheritMod;
private global::Penumbra.Api.IpcSubscribers.TrySetMod? _setMod;
private global::Penumbra.Api.IpcSubscribers.TrySetModPriority? _setModPriority;
private global::Penumbra.Api.IpcSubscribers.TrySetModSetting? _setModSetting;
private global::Penumbra.Api.IpcSubscribers.TrySetModSettings? _setModSettings;
private global::Penumbra.Api.IpcSubscribers.SetTemporaryModSettings? _setTemporaryModSettings;
private global::Penumbra.Api.IpcSubscribers.SetTemporaryModSettingsPlayer? _setTemporaryModSettingsPlayer;
private global::Penumbra.Api.IpcSubscribers.RemoveTemporaryModSettings? _removeTemporaryModSettings;
private global::Penumbra.Api.IpcSubscribers.RemoveTemporaryModSettingsPlayer? _removeTemporaryModSettingsPlayer;
private global::Penumbra.Api.IpcSubscribers.RemoveAllTemporaryModSettings? _removeAllTemporaryModSettings;
private global::Penumbra.Api.IpcSubscribers.RemoveAllTemporaryModSettingsPlayer? _removeAllTemporaryModSettingsPlayer;
private global::Penumbra.Api.IpcSubscribers.QueryTemporaryModSettings? _queryTemporaryModSettings;
private global::Penumbra.Api.IpcSubscribers.OpenMainWindow? _openModPage;
private global::Penumbra.Api.IpcSubscribers.GetCollectionsByIdentifier? _collectionByIdentifier;
private global::Penumbra.Api.IpcSubscribers.GetCollections? _collections;
private global::Penumbra.Api.IpcSubscribers.RedrawObject? _redraw;
private global::Penumbra.Api.IpcSubscribers.GetDrawObjectInfo? _drawObjectInfo;
private global::Penumbra.Api.IpcSubscribers.GetCutsceneParentIndex? _cutsceneParent;
private global::Penumbra.Api.IpcSubscribers.GetCollectionForObject? _objectCollection;
private global::Penumbra.Api.IpcSubscribers.GetModList? _getMods;
private global::Penumbra.Api.IpcSubscribers.GetCollection? _currentCollection;
private global::Penumbra.Api.IpcSubscribers.GetCurrentModSettingsWithTemp? _getCurrentSettingsWithTemp;
private global::Penumbra.Api.IpcSubscribers.GetCurrentModSettings? _getCurrentSettings;
private global::Penumbra.Api.IpcSubscribers.GetAllModSettings? _getAllSettings;
private global::Penumbra.Api.IpcSubscribers.TryInheritMod? _inheritMod;
private global::Penumbra.Api.IpcSubscribers.TrySetMod? _setMod;
private global::Penumbra.Api.IpcSubscribers.TrySetModPriority? _setModPriority;
private global::Penumbra.Api.IpcSubscribers.TrySetModSetting? _setModSetting;
private global::Penumbra.Api.IpcSubscribers.TrySetModSettings? _setModSettings;
private global::Penumbra.Api.IpcSubscribers.SetTemporaryModSettings? _setTemporaryModSettings;
private global::Penumbra.Api.IpcSubscribers.SetTemporaryModSettingsPlayer? _setTemporaryModSettingsPlayer;
private global::Penumbra.Api.IpcSubscribers.RemoveTemporaryModSettings? _removeTemporaryModSettings;
private global::Penumbra.Api.IpcSubscribers.RemoveTemporaryModSettingsPlayer? _removeTemporaryModSettingsPlayer;
private global::Penumbra.Api.IpcSubscribers.RemoveAllTemporaryModSettings? _removeAllTemporaryModSettings;
private global::Penumbra.Api.IpcSubscribers.RemoveAllTemporaryModSettingsPlayer? _removeAllTemporaryModSettingsPlayer;
private global::Penumbra.Api.IpcSubscribers.QueryTemporaryModSettings? _queryTemporaryModSettings;
private global::Penumbra.Api.IpcSubscribers.OpenMainWindow? _openModPage;
private global::Penumbra.Api.IpcSubscribers.GetChangedItems? _getChangedItems;
private IReadOnlyList<(string ModDirectory, IReadOnlyDictionary<string, object?> ChangedItems)>? _changedItems;
private Func<string, (string ModDirectory, string ModName)[]>? _checkCurrentChangedItems;
private readonly IDisposable _initializedEvent;
private readonly IDisposable _disposedEvent;
@ -195,37 +199,58 @@ public class PenumbraService : IDisposable
return ret[0];
}
public IReadOnlyList<(Mod Mod, ModSettings Settings)> GetMods()
public IReadOnlyList<(Mod Mod, ModSettings Settings, int Count)> GetMods(IReadOnlyList<string> data)
{
if (!Available)
return [];
try
{
var allMods = _getMods!.Invoke();
var collection = _currentCollection!.Invoke(ApiCollectionType.Current);
if (_getAllSettings != null)
var allMods = _getMods!.Invoke();
var currentCollection = _currentCollection!.Invoke(ApiCollectionType.Current);
var withSettings = WithSettings(allMods, currentCollection!.Value.Id);
var withCounts = WithCounts(withSettings, allMods.Count);
return OrderList(withCounts, allMods.Count);
IEnumerable<(Mod Mod, ModSettings Settings)> WithSettings(Dictionary<string, string> mods, Guid collection)
{
var allSettings = _getAllSettings.Invoke(collection!.Value.Id, false, false, Key);
if (allSettings.Item1 is PenumbraApiEc.Success)
return allMods.Select(m => (new Mod(m.Value, m.Key),
if (_getAllSettings != null)
{
var allSettings = _getAllSettings.Invoke(collection, false, false, Key);
if (allSettings.Item1 is PenumbraApiEc.Success)
return mods.Select(m => (new Mod(m.Value, m.Key),
allSettings.Item2!.TryGetValue(m.Key, out var s)
? new ModSettings(s.Item3, s.Item2, s.Item1, s.Item4 && s.Item5, false)
: ModSettings.Empty))
.OrderByDescending(p => p.Item2.Enabled)
.ThenBy(p => p.Item1.Name)
.ThenBy(p => p.Item1.DirectoryName)
.ThenByDescending(p => p.Item2.Priority)
.ToList();
? new ModSettings(s.Item3, s.Item2, s.Item1, s is { Item4: true, Item5: true }, false)
: ModSettings.Empty));
}
return mods.Select(m => (new Mod(m.Value, m.Key), GetSettings(collection, m.Key, m.Value, out _)));
}
return allMods
.Select(m => (new Mod(m.Value, m.Key), GetSettings(collection!.Value.Id, m.Key, m.Value, out _)))
.OrderByDescending(p => p.Item2.Enabled)
.ThenBy(p => p.Item1.Name)
.ThenBy(p => p.Item1.DirectoryName)
.ThenByDescending(p => p.Item2.Priority)
.ToList();
IEnumerable<(Mod Mod, ModSettings Settings, int Count)> WithCounts(IEnumerable<(Mod Mod, ModSettings Settings)> mods, int count)
{
if (_changedItems != null && _changedItems.Count == count)
return mods.Select((m, idx) => (m.Mod, m.Settings, CountItems(_changedItems[idx].ChangedItems, data)));
return mods.Select(p => (p.Item1, p.Item2, CountItems(_getChangedItems!.Invoke(p.Item1.DirectoryName, p.Item1.Name), data)));
static int CountItems(IReadOnlyDictionary<string, object?> dict, IReadOnlyList<string> data)
=> data.Count(dict.ContainsKey);
}
static IReadOnlyList<(Mod Mod, ModSettings Settings, int Count)> OrderList(
IEnumerable<(Mod Mod, ModSettings Settings, int Count)> enumerable, int count)
{
var array = new (Mod Mod, ModSettings Settings, int Count)[count];
var i = 0;
foreach (var t in enumerable.OrderByDescending(p => p.Item2.Enabled)
.ThenByDescending(p => p.Item3)
.ThenBy(p => p.Item1.Name)
.ThenBy(p => p.Item1.DirectoryName)
.ThenByDescending(p => p.Item2.Priority))
array[i++] = t;
return array;
}
}
catch (Exception ex)
{
@ -289,6 +314,9 @@ public class PenumbraService : IDisposable
RemoveAllTemporarySettings(collection.Key);
}
public (string ModDirectory, string ModName)[] CheckCurrentChangedItem(string changedItem)
=> _checkCurrentChangedItems?.Invoke(changedItem) ?? [];
private void SetModTemporary(StringBuilder sb, Mod mod, ModSettings settings, Guid collection, ObjectIndex? index)
{
var ex = settings.Remove
@ -476,6 +504,7 @@ public class PenumbraService : IDisposable
_setModSetting = new global::Penumbra.Api.IpcSubscribers.TrySetModSetting(_pluginInterface);
_setModSettings = new global::Penumbra.Api.IpcSubscribers.TrySetModSettings(_pluginInterface);
_openModPage = new global::Penumbra.Api.IpcSubscribers.OpenMainWindow(_pluginInterface);
_getChangedItems = new global::Penumbra.Api.IpcSubscribers.GetChangedItems(_pluginInterface);
if (CurrentMinor >= RequiredPenumbraFeatureVersionTemp)
{
_setTemporaryModSettings = new global::Penumbra.Api.IpcSubscribers.SetTemporaryModSettings(_pluginInterface);
@ -488,10 +517,16 @@ public class PenumbraService : IDisposable
if (CurrentMinor >= RequiredPenumbraFeatureVersionTemp2)
{
_queryTemporaryModSettings = new global::Penumbra.Api.IpcSubscribers.QueryTemporaryModSettings(_pluginInterface);
if (CurrentMinor >= RequiredPenumbraFeatureVersionTemp2)
if (CurrentMinor >= RequiredPenumbraFeatureVersionTemp3)
{
_getCurrentSettingsWithTemp = new global::Penumbra.Api.IpcSubscribers.GetCurrentModSettingsWithTemp(_pluginInterface);
_getAllSettings = new global::Penumbra.Api.IpcSubscribers.GetAllModSettings(_pluginInterface);
if (CurrentMinor >= RequiredPenumbraFeatureVersionTemp4)
{
_changedItems = new global::Penumbra.Api.IpcSubscribers.GetChangedItemAdapterList(_pluginInterface).Invoke();
_checkCurrentChangedItems =
new global::Penumbra.Api.IpcSubscribers.CheckCurrentChangedItemFunc(_pluginInterface).Invoke();
}
}
}
}
@ -541,6 +576,9 @@ public class PenumbraService : IDisposable
_removeAllTemporaryModSettings = null;
_removeAllTemporaryModSettingsPlayer = null;
_queryTemporaryModSettings = null;
_getChangedItems = null;
_changedItems = null;
_checkCurrentChangedItems = null;
Available = false;
Glamourer.Log.Debug("Glamourer detached from Penumbra.");
}

@ -1 +1 @@
Subproject commit 3c1260c9833303c2d33d12d6f77dc2b1afea3f34
Subproject commit 0b6085ce720ffb7c78cf42d4e51861f34db27744

@ -1 +1 @@
Subproject commit c67809057fac73a0fd407e3ad567f0aa6bc0bc37
Subproject commit 70f046830cc7cd35b3480b12b7efe94182477fbb