diff --git a/Glamourer/Config/Configuration.cs b/Glamourer/Config/Configuration.cs index b7c9424..5308a38 100644 --- a/Glamourer/Config/Configuration.cs +++ b/Glamourer/Config/Configuration.cs @@ -23,6 +23,9 @@ public sealed partial class Configuration : IPluginConfiguration, ISavable, ISer [JsonIgnore] public readonly UiConfig Ui; + [JsonIgnore] + public readonly FilterConfig Filters; + public bool AttachToPcp { get; set; } = true; public bool UseRestrictedGearProtection { get; set; } = false; public bool OpenFoldersByDefault { get; set; } = false; @@ -54,6 +57,11 @@ public sealed partial class Configuration : IPluginConfiguration, ISavable, ISer public bool PreventRandomRepeats { get; set; } = false; public string PcpFolder { get; set; } = "PCP"; public string PcpColor { get; set; } = ""; + public bool RememberActorFilter { get; set; } = false; + public bool RememberDesignFilter { get; set; } = false; + public bool RememberNpcFilter { get; set; } = true; + public bool RememberAutomationFilter { get; set; } = false; + public bool RememberUnlocksFilters { get; set; } = true; public RoughnessSetting RoughnessSetting { get; set; } = RoughnessSetting.AsIs; @@ -95,11 +103,12 @@ public sealed partial class Configuration : IPluginConfiguration, ISavable, ISer [JsonIgnore] private readonly SaveService _saveService; - public Configuration(SaveService saveService, ConfigMigrationService migrator, EphemeralConfig ephemeral, UiConfig ui) + public Configuration(SaveService saveService, ConfigMigrationService migrator, EphemeralConfig ephemeral, UiConfig ui, FilterConfig filters) { _saveService = saveService; Ephemeral = ephemeral; Ui = ui; + Filters = filters; Load(migrator); } diff --git a/Glamourer/Config/FilterConfig.cs b/Glamourer/Config/FilterConfig.cs new file mode 100644 index 0000000..26e011b --- /dev/null +++ b/Glamourer/Config/FilterConfig.cs @@ -0,0 +1,201 @@ +using Glamourer.Gui.Tabs.UnlocksTab; +using Glamourer.Services; +using ImSharp.Table; +using Luna; +using Luna.Generators; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Penumbra.GameData.DataContainers; +using Penumbra.GameData.Enums; +using Penumbra.GameData.Structs; + +namespace Glamourer.Config; + +public sealed partial class FilterConfig : ConfigurationFile +{ + private readonly DictJob _jobs; + + public FilterConfig(SaveService saveService, MessageService messager, DictJob jobs) + : base(saveService, messager, TimeSpan.FromMinutes(5)) + { + _jobs = jobs; + _unlocksJobFilter = _jobs.AllAvailableJobs; + Load(); + } + + public override int CurrentVersion + => 1; + + protected override void AddData(JsonTextWriter j) + { + WriteFilter(j, ActorFilter, "Actors"); + WriteFilter(j, DesignFilter, "Designs"); + WriteFilter(j, NpcFilter, "Npcs"); + WriteAutomation(j); + WriteUnlocksTab(j); + } + + protected override void LoadData(JObject j) + { + _actorFilter = j["Actors"]?["Filter"]?.Value() ?? string.Empty; + _designFilter = j["Designs"]?["Filter"]?.Value() ?? string.Empty; + _npcFilter = j["Npcs"]?["Filter"]?.Value() ?? string.Empty; + _automationFilter = j["Automation"]?["Filter"]?.Value() ?? string.Empty; + _automationStateFilter = j["Automation"]?["State"]?.Value(); + LoadUnlocksTab(j); + } + + [ConfigProperty] + private string _designFilter = string.Empty; + + [ConfigProperty] + private string _actorFilter = string.Empty; + + [ConfigProperty] + private string _automationFilter = string.Empty; + + [ConfigProperty] + private bool? _automationStateFilter; + + [ConfigProperty] + private string _npcFilter = string.Empty; + + [ConfigProperty] + private YesNoColumn.YesNoFlag _unlocksFavoriteFilter = YesNoColumn.YesOrNo; + + [ConfigProperty] + private UnlockCacheItem.Modded _unlocksModdedFilter = UnlockCacheItem.ModdedAll; + + [ConfigProperty] + private string _unlocksNameFilter = string.Empty; + + [ConfigProperty] + private string _unlocksTypeFilter = string.Empty; + + [ConfigProperty] + private EquipFlag _unlocksSlotFilter = UnlockCacheItem.SlotsAll; + + [ConfigProperty] + private YesNoColumn.YesNoFlag _unlocksUnlockedFilter = YesNoColumn.YesOrNo; + + [ConfigProperty] + private string _unlocksItemIdFilter = string.Empty; + + [ConfigProperty] + private string _unlocksModelDataFilter = string.Empty; + + [ConfigProperty] + private string _unlocksLevelFilter = string.Empty; + + [ConfigProperty] + private JobFlag _unlocksJobFilter; + + [ConfigProperty] + private UnlockCacheItem.Dyability _unlocksDyabilityFilter = UnlockCacheItem.DyableAll; + + [ConfigProperty] + private YesNoColumn.YesNoFlag _unlocksTradableFilter = YesNoColumn.YesOrNo; + + [ConfigProperty] + private YesNoColumn.YesNoFlag _unlocksCrestFilter = YesNoColumn.YesOrNo; + + private void WriteUnlocksTab(JsonTextWriter j) + { + var obj = new JObject(); + if (UnlocksFavoriteFilter is not YesNoColumn.YesOrNo) + obj["Favorite"] = (uint)UnlocksFavoriteFilter; + if (UnlocksCrestFilter is not YesNoColumn.YesOrNo) + obj["Crest"] = (uint)UnlocksCrestFilter; + if (UnlocksTradableFilter is not YesNoColumn.YesOrNo) + obj["Tradable"] = (uint)UnlocksTradableFilter; + if (UnlocksUnlockedFilter is not YesNoColumn.YesOrNo) + obj["Unlocked"] = (uint)UnlocksUnlockedFilter; + + if (UnlocksModdedFilter is not UnlockCacheItem.ModdedAll) + obj["Modded"] = (uint)UnlocksModdedFilter; + + if (UnlocksDyabilityFilter is not UnlockCacheItem.DyableAll) + obj["Dyability"] = (uint)UnlocksDyabilityFilter; + + if (UnlocksSlotFilter is not UnlockCacheItem.SlotsAll) + obj["Slot"] = (uint)UnlocksSlotFilter; + + if (UnlocksJobFilter != _jobs.AllAvailableJobs) + obj["Job"] = (ulong)UnlocksJobFilter; + + if (UnlocksLevelFilter.Length > 0) + obj["Level"] = UnlocksLevelFilter; + if (UnlocksModelDataFilter.Length > 0) + obj["ModelData"] = UnlocksModelDataFilter; + if (UnlocksItemIdFilter.Length > 0) + obj["ItemId"] = UnlocksItemIdFilter; + if (UnlocksNameFilter.Length > 0) + obj["Name"] = UnlocksNameFilter; + if (UnlocksTypeFilter.Length > 0) + obj["Type"] = UnlocksTypeFilter; + + if (obj.Count <= 0) + return; + + j.WritePropertyName("Unlocks"); + obj.WriteTo(j); + } + + private void LoadUnlocksTab(JObject j) + { + if (j["Unlocks"] is not JObject unlocks) + return; + + _unlocksFavoriteFilter = unlocks["Favorite"]?.Value() is { } f ? (YesNoColumn.YesNoFlag)f : YesNoColumn.YesOrNo; + _unlocksCrestFilter = unlocks["Crest"]?.Value() is { } c ? (YesNoColumn.YesNoFlag)c : YesNoColumn.YesOrNo; + _unlocksTradableFilter = unlocks["Tradable"]?.Value() is { } t ? (YesNoColumn.YesNoFlag)t : YesNoColumn.YesOrNo; + _unlocksUnlockedFilter = unlocks["Unlocked"]?.Value() is { } u ? (YesNoColumn.YesNoFlag)u : YesNoColumn.YesOrNo; + _unlocksModdedFilter = unlocks["Modded"]?.Value() is { } m ? (UnlockCacheItem.Modded)m : UnlockCacheItem.ModdedAll; + _unlocksDyabilityFilter = unlocks["Dyability"]?.Value() is { } d ? (UnlockCacheItem.Dyability)d : UnlockCacheItem.DyableAll; + _unlocksSlotFilter = unlocks["Slot"]?.Value() is { } s ? (EquipFlag)s : UnlockCacheItem.SlotsAll; + _unlocksJobFilter = unlocks["Job"]?.Value() is { } job ? (JobFlag)job : _jobs.AllAvailableJobs; + _unlocksLevelFilter = unlocks["Level"]?.Value() ?? string.Empty; + _unlocksModelDataFilter = unlocks["ModelData"]?.Value() ?? string.Empty; + _unlocksItemIdFilter = unlocks["ItemId"]?.Value() ?? string.Empty; + _unlocksNameFilter = unlocks["Name"]?.Value() ?? string.Empty; + _unlocksTypeFilter = unlocks["Type"]?.Value() ?? string.Empty; + } + + + public override string ToFilePath(FilenameService fileNames) + => fileNames.FilterFile; + + private void WriteAutomation(JsonTextWriter j) + { + if (AutomationStateFilter is null && AutomationFilter.Length is 0) + return; + + j.WritePropertyName("Automation"); + j.WriteStartObject(); + if (AutomationStateFilter is not null) + { + j.WritePropertyName("State"); + j.WriteValue(AutomationStateFilter.Value); + } + + if (AutomationFilter.Length > 0) + { + j.WritePropertyName("Filter"); + j.WriteValue(AutomationFilter); + } + + j.WriteEndObject(); + } + + private static void WriteFilter(JsonTextWriter j, string filter, string tabName) + { + if (filter.Length is 0) + return; + + j.WritePropertyName(tabName); + j.WriteStartObject(); + j.WritePropertyName("Filter"); + j.WriteValue(filter); + j.WriteEndObject(); + } +} diff --git a/Glamourer/Config/UiConfig.cs b/Glamourer/Config/UiConfig.cs index e76266a..cbcf00e 100644 --- a/Glamourer/Config/UiConfig.cs +++ b/Glamourer/Config/UiConfig.cs @@ -3,14 +3,19 @@ using Luna; using Luna.Generators; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using Penumbra.GameData.Actors; +using Penumbra.GameData.Structs; namespace Glamourer.Config; public sealed partial class UiConfig : ConfigurationFile { - public UiConfig(SaveService saveService, MessageService messageService) - : base(saveService, messageService) + private readonly ActorManager _actors; + + public UiConfig(SaveService saveService, MessageService messageService, ActorManager actors) + : base(saveService, messageService, TimeSpan.FromMinutes(5)) { + _actors = actors; Load(); } @@ -26,6 +31,15 @@ public sealed partial class UiConfig : ConfigurationFile [ConfigProperty] private TwoPanelWidth _npcTabScale = new(250, ScalingMode.Absolute); + [ConfigProperty] + private NpcId _selectedNpc = 0; + + [ConfigProperty] + private int _selectedAutomationIndex = -1; + + [ConfigProperty] + private ActorIdentifier _selectedActor = ActorIdentifier.Invalid; + public override int CurrentVersion => 1; @@ -35,16 +49,36 @@ public sealed partial class UiConfig : ConfigurationFile DesignsTabScale.WriteJson(j, "DesignsTab"); AutomationTabScale.WriteJson(j, "AutomationTab"); NpcTabScale.WriteJson(j, "NpcTab"); + if (_selectedNpc.Id is not 0) + { + j.WritePropertyName("SelectedNpc"); + j.WriteValue(_selectedNpc); + } + + if (_selectedAutomationIndex >= 0) + { + j.WritePropertyName("SelectedAutomationIndex"); + j.WriteValue(_selectedAutomationIndex); + } + + if (_selectedActor.IsValid) + { + j.WritePropertyName("SelectedActor"); + _selectedActor.ToJson().WriteTo(j); + } } protected override void LoadData(JObject j) { - _actorsTabScale = TwoPanelWidth.ReadJson(j, "ActorsTab", new TwoPanelWidth(250, ScalingMode.Absolute)); - _designsTabScale = TwoPanelWidth.ReadJson(j, "DesignsTab", new TwoPanelWidth(0.3f, ScalingMode.Percentage)); - _automationTabScale = TwoPanelWidth.ReadJson(j, "AutomationTab", new TwoPanelWidth(0.3f, ScalingMode.Percentage)); - _npcTabScale = TwoPanelWidth.ReadJson(j, "NpcTab", new TwoPanelWidth(250, ScalingMode.Absolute)); + _actorsTabScale = TwoPanelWidth.ReadJson(j, "ActorsTab", new TwoPanelWidth(250, ScalingMode.Absolute)); + _designsTabScale = TwoPanelWidth.ReadJson(j, "DesignsTab", new TwoPanelWidth(0.3f, ScalingMode.Percentage)); + _automationTabScale = TwoPanelWidth.ReadJson(j, "AutomationTab", new TwoPanelWidth(0.3f, ScalingMode.Percentage)); + _npcTabScale = TwoPanelWidth.ReadJson(j, "NpcTab", new TwoPanelWidth(250, ScalingMode.Absolute)); + _selectedNpc = j["SelectedNpc"]?.Value() ?? 0; + _selectedAutomationIndex = j["SelectedAutomationIndex"]?.Value() ?? -1; + _selectedActor = _actors.FromJson(j["SelectedActor"] as JObject); } public override string ToFilePath(FilenameService fileNames) - => fileNames.UiConfiguration; + => fileNames.UiConfigurationFile; } diff --git a/Glamourer/Designs/DesignColors.cs b/Glamourer/Designs/DesignColors.cs index 44be523..8e57e86 100644 --- a/Glamourer/Designs/DesignColors.cs +++ b/Glamourer/Designs/DesignColors.cs @@ -81,12 +81,16 @@ public sealed class DesignColors : ISavable, IReadOnlyDictionary public void Save(StreamWriter writer) { + var dict = new JObject(); + foreach (var (name, color) in _colors) + dict[name] = color.Color; var jObj = new JObject { ["Version"] = 1, ["MissingColor"] = MissingColor.Color, - ["Definitions"] = JToken.FromObject(_colors), + ["Definitions"] = dict, }; + writer.Write(jObj.ToString(Formatting.Indented)); } diff --git a/Glamourer/Gui/Tabs/ActorTab/ActorFilter.cs b/Glamourer/Gui/Tabs/ActorTab/ActorFilter.cs index e03c1cf..9bf396e 100644 --- a/Glamourer/Gui/Tabs/ActorTab/ActorFilter.cs +++ b/Glamourer/Gui/Tabs/ActorTab/ActorFilter.cs @@ -1,4 +1,5 @@ using Dalamud.Plugin.Services; +using Glamourer.Config; using ImSharp; using Luna; using Penumbra.GameData.Enums; @@ -23,7 +24,7 @@ public sealed class ActorFilter : TextFilterBase, IUiService private FilterMethod _method = FilterMethod.Empty; - public ActorFilter(IPlayerState playerState) + public ActorFilter(IPlayerState playerState, Configuration config) { _playerState = playerState; FilterChanged += () => @@ -39,7 +40,10 @@ public sealed class ActorFilter : TextFilterBase, IUiService "" or "" => FilterMethod.Homeworld, _ => FilterMethod.Text, }; + config.Filters.ActorFilter = Text; }; + if (config.RememberActorFilter) + Set(config.Filters.ActorFilter); } public override bool DrawFilter(ReadOnlySpan label, Vector2 availableRegion) @@ -78,9 +82,21 @@ public sealed class ActorFilter : TextFilterBase, IUiService Im.Text(""u8, color); Im.Line.NoSpacing(); Im.Text(": show only players from your world."u8); + + if (Text.Length > 0) + Im.Text("\nMiddle-click to clear filters."u8); return ret; } + protected override bool OnMiddleClick() + { + if (!Im.Item.MiddleClicked()) + return false; + + Im.Id.ClearActive(); + return Clear(); + } + protected override string ToFilterString(in ActorCacheItem item, int globalIndex) => item.DisplayText.Utf16; diff --git a/Glamourer/Gui/Tabs/ActorTab/ActorSelection.cs b/Glamourer/Gui/Tabs/ActorTab/ActorSelection.cs index 8b5d965..8873ccb 100644 --- a/Glamourer/Gui/Tabs/ActorTab/ActorSelection.cs +++ b/Glamourer/Gui/Tabs/ActorTab/ActorSelection.cs @@ -1,5 +1,6 @@ using Dalamud.Game.ClientState.Conditions; using Dalamud.Plugin.Services; +using Glamourer.Config; using Glamourer.State; using ImSharp; using Luna; @@ -9,7 +10,7 @@ using Penumbra.GameData.Interop; namespace Glamourer.Gui.Tabs.ActorTab; -public sealed class ActorSelection(StateManager manager, ActorObjectManager objects, ICondition conditions) : IUiService +public sealed class ActorSelection(StateManager manager, ActorObjectManager objects, ICondition conditions, UiConfig config) : IUiService { private static readonly StringU8 NoSelection = new("No Actor Selected"u8); @@ -23,7 +24,8 @@ public sealed class ActorSelection(StateManager manager, ActorObjectManager obje public void Select(ActorIdentifier identifier, ActorData data) { - Identifier = identifier.CreatePermanent(); + Identifier = identifier.CreatePermanent(); + config.SelectedActor = Identifier; if (Identifier.IsValid) { ActorName = new StringU8(data.Label); diff --git a/Glamourer/Gui/Tabs/ActorTab/ActorSelector.cs b/Glamourer/Gui/Tabs/ActorTab/ActorSelector.cs index d4f3f9c..6921cd9 100644 --- a/Glamourer/Gui/Tabs/ActorTab/ActorSelector.cs +++ b/Glamourer/Gui/Tabs/ActorTab/ActorSelector.cs @@ -1,4 +1,5 @@ -using Glamourer.Interop.Penumbra; +using Glamourer.Config; +using Glamourer.Interop.Penumbra; using ImSharp; using Luna; using Penumbra.GameData.Actors; @@ -14,25 +15,58 @@ public readonly struct ActorCacheItem(ActorIdentifier identifier, ActorData data public readonly StringU8 IncognitoText = new(identifier.Incognito(data.Label)); } -public sealed class ActorSelector(ActorSelection selection, ActorObjectManager objects, ActorFilter filter, PenumbraService penumbra, Config.EphemeralConfig config) : IPanel +public sealed class ActorSelector( + ActorSelection selection, + ActorObjectManager objects, + ActorFilter filter, + PenumbraService penumbra, + Configuration config) : IPanel { public ReadOnlySpan Id => "ActorSelector"u8; - public void Draw() + public unsafe void Draw() { Im.Cursor.Y += Im.Style.FramePadding.Y; - var cache = CacheManager.Instance.GetOrCreateCache(Im.Id.Current, () => new ActorSelectorCache(objects, filter, penumbra)); - using var clip = new Im.ListClipper(cache.Count, Im.Style.TextHeightWithSpacing); + var cache = CacheManager.Instance.GetOrCreateCache(Im.Id.Current, () => new ActorSelectorCache(objects, filter, penumbra)); + HandleRememberedSelection(); + using var clip = new Im.ListClipper(cache.Count, Im.Style.TextHeightWithSpacing); foreach (var actor in clip.Iterate(cache)) { Im.Cursor.X += Im.Style.FramePadding.X; var selected = actor.Identifier.Equals(selection.Identifier); - if (Im.Selectable(config.IncognitoMode ? actor.IncognitoText : actor.DisplayText.Utf8, selected) && !selected) + if (Im.Selectable(config.Ephemeral.IncognitoMode ? actor.IncognitoText : actor.DisplayText.Utf8, selected) && !selected) selection.Select(actor.Identifier, actor.Data); } } + private unsafe void HandleRememberedSelection() + { + // We already have a valid selection. + if (selection.Identifier.IsValid) + return; + + // We do not have a remembered selection. + if (!config.Ui.SelectedActor.IsValid) + return; + + // We have no actor corresponding to the selection available to create a new state. + if (!objects.TryGetValue(config.Ui.SelectedActor, out var data)) + return; + + // The actor has no model yet. + if (data.Objects.First().Model is not { IsCharacterBase: true } model) + return; + + // The model still has a staging area, so is not fully loaded. + if (model.AsCharacterBase->PerSlotStagingArea is not null || model.AsCharacterBase->TempData is not null) + return; + + // The model should be fully loaded, so the selection can probably create the expected state. + selection.Select(config.Ui.SelectedActor, data); + } + + private sealed class ActorSelectorCache : BasicFilterCache { private readonly ActorObjectManager _objects; diff --git a/Glamourer/Gui/Tabs/AutomationTab/AutomationFilter.cs b/Glamourer/Gui/Tabs/AutomationTab/AutomationFilter.cs index bb75008..7a08c4c 100644 --- a/Glamourer/Gui/Tabs/AutomationTab/AutomationFilter.cs +++ b/Glamourer/Gui/Tabs/AutomationTab/AutomationFilter.cs @@ -1,4 +1,5 @@ -using ImSharp; +using Glamourer.Config; +using ImSharp; using Luna; namespace Glamourer.Gui.Tabs.AutomationTab; @@ -10,6 +11,21 @@ public sealed class AutomationFilter : TextFilterBase, IUiS protected override string ToFilterString(in AutomationCacheItem item, int globalIndex) => item.Name.Utf16; + public AutomationFilter(Configuration config) + { + if (config.RememberAutomationFilter) + { + _setStateFilter = config.Filters.AutomationStateFilter; + Set(config.Filters.AutomationFilter); + } + + FilterChanged += () => + { + config.Filters.AutomationFilter = Text; + config.Filters.AutomationStateFilter = _setStateFilter; + }; + } + public override bool WouldBeVisible(in AutomationCacheItem item, int globalIndex) => _setStateFilter switch { @@ -54,11 +70,15 @@ public sealed class AutomationFilter : TextFilterBase, IUiS return ret; } - public override void Clear() + public override bool Clear() { var changes = _setStateFilter is not null; _setStateFilter = null; - if (!Set(string.Empty) && changes) - InvokeEvent(); + if (!SetInternal(string.Empty) && !changes) + return false; + + InvokeEvent(); + return true; + } } diff --git a/Glamourer/Gui/Tabs/AutomationTab/AutomationSelection.cs b/Glamourer/Gui/Tabs/AutomationTab/AutomationSelection.cs index 89d520d..ee4498f 100644 --- a/Glamourer/Gui/Tabs/AutomationTab/AutomationSelection.cs +++ b/Glamourer/Gui/Tabs/AutomationTab/AutomationSelection.cs @@ -1,4 +1,5 @@ using Glamourer.Automation; +using Glamourer.Config; using Glamourer.Events; using ImSharp; using Luna; @@ -10,6 +11,7 @@ public sealed class AutomationSelection : IUiService, IDisposable public static readonly StringU8 NoSelection = new("No Set Selected"u8); private readonly AutomationChanged _automationChanged; + private readonly UiConfig _config; public int DraggedDesignIndex = -1; @@ -18,10 +20,12 @@ public sealed class AutomationSelection : IUiService, IDisposable public StringU8 Name { get; private set; } = NoSelection; public StringU8 Incognito { get; private set; } = NoSelection; - public AutomationSelection(AutomationChanged automationChanged) + public AutomationSelection(AutomationChanged automationChanged, UiConfig config, AutoDesignManager autoDesigns) { _automationChanged = automationChanged; + _config = config; _automationChanged.Subscribe(OnAutomationChanged, AutomationChanged.Priority.SetSelector); + InitialSelect(autoDesigns); } public void Dispose() @@ -47,15 +51,34 @@ public sealed class AutomationSelection : IUiService, IDisposable Set = item?.Set; if (Set is null) { - Index = -1; - Name = NoSelection; - Incognito = NoSelection; + _config.SelectedAutomationIndex = -1; + Index = -1; + Name = NoSelection; + Incognito = NoSelection; } else { - Index = item!.Value.Index; - Name = item!.Value.Name.Utf8; - Incognito = item!.Value.Incognito; + _config.SelectedAutomationIndex = item!.Value.Index; + Index = item!.Value.Index; + Name = item!.Value.Name.Utf8; + Incognito = item!.Value.Incognito; } } + + private void InitialSelect(AutoDesignManager autoDesigns) + { + if (_config.SelectedAutomationIndex < 0) + return; + + if (autoDesigns.Count <= _config.SelectedAutomationIndex) + { + _config.SelectedAutomationIndex = -1; + return; + } + + Set = autoDesigns[_config.SelectedAutomationIndex]; + Index = _config.SelectedAutomationIndex; + Name = new StringU8(Set.Name); + Incognito = new StringU8($"Auto Design Set #{Index + 1}"); + } } diff --git a/Glamourer/Gui/Tabs/DebugTab/DebugTab.cs b/Glamourer/Gui/Tabs/DebugTab/DebugTab.cs index 24b6fa6..820b6e3 100644 --- a/Glamourer/Gui/Tabs/DebugTab/DebugTab.cs +++ b/Glamourer/Gui/Tabs/DebugTab/DebugTab.cs @@ -1,6 +1,10 @@ using Glamourer.Config; +using Glamourer.Services; using ImSharp; +using InteropGenerator.Runtime; using Luna; +using Penumbra.GameData.Files.ShaderStructs; +using Vortice.Direct3D11.Debug; namespace Glamourer.Gui.Tabs.DebugTab; @@ -33,9 +37,29 @@ public sealed class DebugTab(ServiceManager manager) : ITab return; if (Im.Tree.Header("General"u8)) + { + if (Im.Button("Open Config Directory"u8)) + OpenFileOrFolder(manager.GetService().ConfigurationDirectory); StartTimeTracker.Draw("Timers"u8, manager.GetService()); + } foreach (var header in _headers) header.Draw(); } + + private static void OpenFileOrFolder(string text) + { + try + { + var process = new ProcessStartInfo(text) + { + UseShellExecute = true, + }; + Process.Start(process); + } + catch + { + // Ignored + } + } } diff --git a/Glamourer/Gui/Tabs/DebugTab/PenumbraPanel.cs b/Glamourer/Gui/Tabs/DebugTab/PenumbraPanel.cs index f4543ec..fc2dbcf 100644 --- a/Glamourer/Gui/Tabs/DebugTab/PenumbraPanel.cs +++ b/Glamourer/Gui/Tabs/DebugTab/PenumbraPanel.cs @@ -55,7 +55,7 @@ public sealed class PenumbraPanel(PenumbraService penumbra, PenumbraChangedItemT table.NextColumn(); Im.Item.SetNextWidthScaled(200); Im.Input.Scalar("##CutsceneIndex"u8, ref _gameObjectIndex); - table.DrawColumn(penumbra.Available ? $"{penumbra.CutsceneParent((ushort)_gameObjectIndex)}" : "Penumbra Unavailable"u8); + table.DrawColumn(penumbra.Available ? $"{penumbra.ResolveService.CutsceneParent((ushort)_gameObjectIndex)}" : "Penumbra Unavailable"u8); table.DrawFrameColumn("Redraw Object"u8); table.NextColumn(); diff --git a/Glamourer/Gui/Tabs/DesignTab/ModCombo.cs b/Glamourer/Gui/Tabs/DesignTab/ModCombo.cs index 98575a9..00fd665 100644 --- a/Glamourer/Gui/Tabs/DesignTab/ModCombo.cs +++ b/Glamourer/Gui/Tabs/DesignTab/ModCombo.cs @@ -101,7 +101,7 @@ public sealed class ModCombo(PenumbraService penumbra, DesignFileSystem fileSyst { foreach (var setting in settings.Settings) { - if (setting.Value.Count == 0) + if (setting.Value.Count is 0) Im.Text(""u8); else foreach (var option in setting.Value) diff --git a/Glamourer/Gui/Tabs/DesignTab/Selector/DesignFileSystemDrawer.cs b/Glamourer/Gui/Tabs/DesignTab/Selector/DesignFileSystemDrawer.cs index 9bb29da..b0f8dfe 100644 --- a/Glamourer/Gui/Tabs/DesignTab/Selector/DesignFileSystemDrawer.cs +++ b/Glamourer/Gui/Tabs/DesignTab/Selector/DesignFileSystemDrawer.cs @@ -16,7 +16,7 @@ public sealed class DesignFileSystemDrawer : FileSystemDrawer, IFileSystemFilter, IUiService { + public DesignFilter(Configuration config) + { + if (config.RememberDesignFilter) + Set(config.Filters.DesignFilter); + FilterChanged += () => config.Filters.DesignFilter = Text; + } + protected override void DrawTooltip() { if (!Im.Item.Hovered()) diff --git a/Glamourer/Gui/Tabs/NpcTab/NpcFilter.cs b/Glamourer/Gui/Tabs/NpcTab/NpcFilter.cs index cab073e..ea5cf01 100644 --- a/Glamourer/Gui/Tabs/NpcTab/NpcFilter.cs +++ b/Glamourer/Gui/Tabs/NpcTab/NpcFilter.cs @@ -1,4 +1,5 @@ -using ImSharp; +using Glamourer.Config; +using ImSharp; using Luna; namespace Glamourer.Gui.Tabs.NpcTab; @@ -12,6 +13,13 @@ public sealed class NpcFilter : TokenizedFilter config.Filters.NpcFilter = Text; + } + protected override void DrawTooltip() { if (!Im.Item.Hovered()) diff --git a/Glamourer/Gui/Tabs/NpcTab/NpcSelection.cs b/Glamourer/Gui/Tabs/NpcTab/NpcSelection.cs index 71bcf2f..2b684b9 100644 --- a/Glamourer/Gui/Tabs/NpcTab/NpcSelection.cs +++ b/Glamourer/Gui/Tabs/NpcTab/NpcSelection.cs @@ -1,4 +1,5 @@ -using Glamourer.Designs; +using Glamourer.Config; +using Glamourer.Designs; using Glamourer.GameData; using ImSharp; using Luna; @@ -10,15 +11,18 @@ public sealed class NpcSelection : IUiService, IDisposable private readonly LocalNpcAppearanceData _data; private readonly DesignColors _colors; private readonly DesignConverter _converter; + private readonly UiConfig _config; - public NpcSelection(LocalNpcAppearanceData data, DesignColors colors, DesignConverter converter) + public NpcSelection(LocalNpcAppearanceData data, DesignColors colors, DesignConverter converter, UiConfig config, NpcCustomizeSet npcs) { _data = data; _colors = colors; _converter = converter; + _config = config; _data.DataChanged += OnDataChanged; _colors.ColorChanged += OnColorChanged; + InitialSelect(npcs); } private void OnColorChanged() @@ -81,12 +85,13 @@ public sealed class NpcSelection : IUiService, IDisposable public void Update(in NpcCacheItem item) { - Data = item.Npc; - Name = item.Name.Utf8; - Favorite = item.Favorite; - ColorText = item.ColorText; - ColorTextU8 = ColorText.Length > 0 ? new StringU8(ColorText) : DesignColors.AutomaticNameU8; - Color = item.Color; + Data = item.Npc; + Name = item.Name.Utf8; + Favorite = item.Favorite; + ColorText = item.ColorText; + ColorTextU8 = ColorText.Length > 0 ? new StringU8(ColorText) : DesignColors.AutomaticNameU8; + Color = item.Color; + _config.SelectedNpc = Data.Id; } public void Dispose() @@ -94,4 +99,20 @@ public sealed class NpcSelection : IUiService, IDisposable _data.DataChanged -= OnDataChanged; _colors.ColorChanged -= OnColorChanged; } + + private void InitialSelect(NpcCustomizeSet npcs) + { + if (_config.SelectedNpc.Id is 0) + return; + + if (!npcs.FindFirst(n => n.Id == _config.SelectedNpc.Id, out var npc)) + return; + + Data = npc; + Name = new StringU8(npc.Name); + ColorText = _data.GetColor(npc); + ColorTextU8 = ColorText.Length is not 0 ? new StringU8(ColorText) : DesignColors.AutomaticNameU8; + (var color, Favorite) = _data.GetData(npc); + Color = color.ToVector(); + } } diff --git a/Glamourer/Gui/Tabs/SettingsTab/SettingsTab.cs b/Glamourer/Gui/Tabs/SettingsTab/SettingsTab.cs index 6acb3fd..6ec8209 100644 --- a/Glamourer/Gui/Tabs/SettingsTab/SettingsTab.cs +++ b/Glamourer/Gui/Tabs/SettingsTab/SettingsTab.cs @@ -300,6 +300,31 @@ public sealed class SettingsTab( Checkbox("Debug Mode"u8, "Show the debug tab. Only useful for debugging or advanced use. Not recommended in general."u8, config.DebugMode, v => config.DebugMode = v); + + Im.Dummy(Vector2.Zero); + Im.Separator(); + Im.Dummy(Vector2.Zero); + + Checkbox("Remember Design Filter Across Sessions"u8, + "Whether the filter in the Designs tab should remember its input and start with its list filtered identically to the last session."u8, + config.RememberDesignFilter, v => config.RememberDesignFilter = v); + + Checkbox("Remember Actor Filter Across Sessions"u8, + "Whether the filter in the Actors tab should remember its input and start with its list filtered identically to the last session."u8, + config.RememberActorFilter, v => config.RememberActorFilter = v); + + Checkbox("Remember Automation Filters Across Sessions"u8, + "Whether the filters in the Automation tab should remember their respective inputs and start with their list filtered identically to the last session."u8, + config.RememberAutomationFilter, v => config.RememberAutomationFilter = v); + + Checkbox("Remember NPC Filter Across Sessions"u8, + "Whether the filter in the NPCs tab should remember its input and start with its list filtered identically to the last session."u8, + config.RememberNpcFilter, v => config.RememberNpcFilter = v); + + Checkbox("Remember Unlocks Filters Across Sessions"u8, + "Whether the filters in the Unlocks tab should remember their respective inputs and start with its table filtered identically to the last session."u8, + config.RememberUnlocksFilters, v => config.RememberUnlocksFilters = v); + Im.Line.New(); } diff --git a/Glamourer/Gui/Tabs/UnlocksTab/UnlockCacheItem.cs b/Glamourer/Gui/Tabs/UnlocksTab/UnlockCacheItem.cs index fb305c6..6e548a4 100644 --- a/Glamourer/Gui/Tabs/UnlocksTab/UnlockCacheItem.cs +++ b/Glamourer/Gui/Tabs/UnlocksTab/UnlockCacheItem.cs @@ -16,6 +16,30 @@ public readonly struct UnlockCacheItem(in EquipItem item, in EquipItem offhand, Two = 4, } + [Flags] + public enum Modded + { + Relevant = 1, + Ignored = 2, + None = 4, + } + + public const Modded ModdedAll = Modded.Relevant | Modded.Ignored | Modded.None; + + public const Dyability DyableAll = Dyability.No | Dyability.Yes | Dyability.Two; + + public const EquipFlag SlotsAll = EquipFlag.Head + | EquipFlag.Body + | EquipFlag.Hands + | EquipFlag.Legs + | EquipFlag.Feet + | EquipFlag.Ears + | EquipFlag.Neck + | EquipFlag.Wrist + | EquipFlag.RFinger + | EquipFlag.Mainhand + | EquipFlag.Offhand; + public readonly EquipItem Item = item; public readonly StringPair Name = new(item.Name); public readonly EquipFlag Slot = item.Type.ToSlot().ToFlag(); diff --git a/Glamourer/Gui/Tabs/UnlocksTab/UnlockTable.cs b/Glamourer/Gui/Tabs/UnlocksTab/UnlockTable.cs index 961f65f..b3c8e24 100644 --- a/Glamourer/Gui/Tabs/UnlocksTab/UnlockTable.cs +++ b/Glamourer/Gui/Tabs/UnlocksTab/UnlockTable.cs @@ -27,10 +27,22 @@ public sealed class UnlockTable : TableBase, private readonly IgnoredMods _ignoredMods; public UnlockTable(JobService jobs, ItemManager items, ItemUnlockManager unlocks, PenumbraChangedItemTooltip tooltip, - ObjectUnlocked unlockEvent, FavoriteManager favorites, PenumbraService penumbra, TextureService textures, IgnoredMods ignoredMods) - : base(new StringU8("Unlock Table"u8), new FavoriteColumn(favorites), new ModdedColumn(), new NameColumn(textures, tooltip), - new SlotColumn(), new TypeColumn(), new UnlockDateColumn(), new ItemIdColumn(), new ModelDataColumn(), new JobColumn(jobs), - new RequiredLevelColumn(), new DyableColumn(), new CrestColumn(), new TradableColumn()) + ObjectUnlocked unlockEvent, FavoriteManager favorites, PenumbraService penumbra, TextureService textures, IgnoredMods ignoredMods, + Configuration config) + : base(new StringU8("Unlock Table"u8), + new FavoriteColumn(config, favorites), + new ModdedColumn(config), + new NameColumn(config, textures, tooltip), + new SlotColumn(config), + new TypeColumn(config), + new UnlockDateColumn(config), + new ItemIdColumn(config), + new ModelDataColumn(config), + new JobColumn(config, jobs), + new RequiredLevelColumn(config), + new DyableColumn(config), + new CrestColumn(config), + new TradableColumn(config)) { _jobs = jobs; _items = items; @@ -86,12 +98,15 @@ public sealed class UnlockTable : TableBase, { private readonly FavoriteManager _favorites; - public FavoriteColumn(FavoriteManager favorites) + public FavoriteColumn(Configuration config, FavoriteManager favorites) { _favorites = favorites; Flags |= TableColumnFlags.NoResize; Label = new StringU8("F"u8); FilterLabel = new StringU8("Favorite"u8); + if (config.RememberUnlocksFilters) + Filter.LoadValue(config.Filters.UnlocksFavoriteFilter); + Filter.FilterChanged += () => config.Filters.UnlocksFavoriteFilter = Filter.FilterValue; } public override float ComputeWidth(IEnumerable allItems) @@ -104,23 +119,18 @@ public sealed class UnlockTable : TableBase, => item.Favorite; } - private sealed class ModdedColumn : FlagColumn + private sealed class ModdedColumn : FlagColumn { - [Flags] - public enum Modded - { - Relevant = 1, - Ignored = 2, - None = 4, - } - private static readonly AwesomeIcon Dot = FontAwesomeIcon.Circle; private static readonly AwesomeIcon Hollow = FontAwesomeIcon.DotCircle; - public ModdedColumn() + public ModdedColumn(Configuration config) { Flags |= TableColumnFlags.NoResize; Label = new StringU8("M"); + if (config.RememberUnlocksFilters) + Filter.LoadValue(config.Filters.UnlocksModdedFilter); + Filter.FilterChanged += () => config.Filters.UnlocksModdedFilter = Filter.FilterValue; } public override float ComputeWidth(IEnumerable allItems) @@ -149,18 +159,19 @@ public sealed class UnlockTable : TableBase, } } - protected override Modded GetValue(in UnlockCacheItem item, int globalIndex) - => item.RelevantMods > 0 ? Modded.Relevant : item.Mods.Length > 0 ? Modded.Ignored : Modded.None; + protected override UnlockCacheItem.Modded GetValue(in UnlockCacheItem item, int globalIndex) + => item.RelevantMods > 0 ? UnlockCacheItem.Modded.Relevant : + item.Mods.Length > 0 ? UnlockCacheItem.Modded.Ignored : UnlockCacheItem.Modded.None; protected override StringU8 DisplayString(in UnlockCacheItem item, int globalIndex) => StringU8.Empty; - protected override IReadOnlyList<(Modded Value, StringU8 Name)> EnumData + protected override IReadOnlyList<(UnlockCacheItem.Modded Value, StringU8 Name)> EnumData => [ - (Modded.Relevant, new StringU8("Any Relevant Mods"u8)), - (Modded.Ignored, new StringU8("Only Ignored Mods"u8)), - (Modded.None, new StringU8("Unmodded"u8)), + (UnlockCacheItem.Modded.Relevant, new StringU8("Any Relevant Mods"u8)), + (UnlockCacheItem.Modded.Ignored, new StringU8("Only Ignored Mods"u8)), + (UnlockCacheItem.Modded.None, new StringU8("Unmodded"u8)), ]; @@ -179,13 +190,16 @@ public sealed class UnlockTable : TableBase, private readonly TextureService _textures; private readonly PenumbraChangedItemTooltip _tooltip; - public NameColumn(TextureService textures, PenumbraChangedItemTooltip tooltip) + public NameColumn(Configuration config, TextureService textures, PenumbraChangedItemTooltip tooltip) { _textures = textures; _tooltip = tooltip; Flags |= TableColumnFlags.NoHide | TableColumnFlags.NoReorder; Label = new StringU8("Item Name..."u8); UnscaledWidth = 400; + if (config.RememberUnlocksFilters) + Filter.Set(config.Filters.UnlocksNameFilter); + Filter.FilterChanged += () => config.Filters.UnlocksNameFilter = Filter.Text; } public override void DrawColumn(in UnlockCacheItem item, int _) @@ -215,8 +229,13 @@ public sealed class UnlockTable : TableBase, private sealed class TypeColumn : TextColumn { - public TypeColumn() - => Label = new StringU8("Item Type..."u8); + public TypeColumn(Configuration config) + { + Label = new StringU8("Item Type..."u8); + if (config.RememberUnlocksFilters) + Filter.Set(config.Filters.UnlocksTypeFilter); + Filter.FilterChanged += () => config.Filters.UnlocksTypeFilter = Filter.Text; + } public override float ComputeWidth(IEnumerable _) => FullEquipType.CrossPeinHammer.ToNameU8().CalculateSize().X; @@ -233,10 +252,13 @@ public sealed class UnlockTable : TableBase, private sealed class SlotColumn : FlagColumn { - public SlotColumn() + public SlotColumn(Configuration config) { Flags &= ~TableColumnFlags.NoResize; Label = new StringU8("Equip Slot"u8); + if (config.RememberUnlocksFilters) + Filter.LoadValue(config.Filters.UnlocksSlotFilter); + Filter.FilterChanged += () => config.Filters.UnlocksSlotFilter = Filter.FilterValue; } public override float ComputeWidth(IEnumerable _) @@ -269,11 +291,14 @@ public sealed class UnlockTable : TableBase, private sealed class UnlockDateColumn : YesNoColumn { - public UnlockDateColumn() + public UnlockDateColumn(Configuration config) { Flags &= ~TableColumnFlags.NoResize; Label = new StringU8("Unlocked"u8); FilterLabel = Label; + if (config.RememberUnlocksFilters) + Filter.LoadValue(config.Filters.UnlocksUnlockedFilter); + Filter.FilterChanged += () => config.Filters.UnlocksUnlockedFilter = Filter.FilterValue; } public override float ComputeWidth(IEnumerable allItems) @@ -297,10 +322,13 @@ public sealed class UnlockTable : TableBase, private sealed class ItemIdColumn : NumberColumn { - public ItemIdColumn() + public ItemIdColumn(Configuration config) { Label = new StringU8("Item Id..."u8); UnscaledWidth = 70; + if (config.RememberUnlocksFilters) + Filter.Set(config.Filters.UnlocksItemIdFilter); + Filter.FilterChanged += () => config.Filters.UnlocksItemIdFilter = Filter.Text; } public override uint ToValue(in UnlockCacheItem item, int globalIndex) @@ -315,10 +343,13 @@ public sealed class UnlockTable : TableBase, private sealed class ModelDataColumn : TextColumn { - public ModelDataColumn() + public ModelDataColumn(Configuration config) { Label = new StringU8("Model Data..."u8); UnscaledWidth = 100; + if (config.RememberUnlocksFilters) + Filter.Set(config.Filters.UnlocksModelDataFilter); + Filter.FilterChanged += () => config.Filters.UnlocksModelDataFilter = Filter.Text; } public override void DrawColumn(in UnlockCacheItem item, int globalIndex) @@ -363,10 +394,13 @@ public sealed class UnlockTable : TableBase, private sealed class RequiredLevelColumn : NumberColumn { - public RequiredLevelColumn() + public RequiredLevelColumn(Configuration config) { Label = new StringU8("Level..."u8); UnscaledWidth = 70; + if (config.RememberUnlocksFilters) + Filter.Set(config.Filters.UnlocksLevelFilter); + Filter.FilterChanged += () => config.Filters.UnlocksLevelFilter = Filter.Text; } public override byte ToValue(in UnlockCacheItem item, int globalIndex) @@ -383,7 +417,7 @@ public sealed class UnlockTable : TableBase, { private readonly JobService _jobs; - public JobColumn(JobService jobs) + public JobColumn(Configuration config, JobService jobs) : base(false) { _jobs = jobs; @@ -392,6 +426,9 @@ public sealed class UnlockTable : TableBase, Label = new StringU8("Jobs"u8); Filter = new JobFilter(this); UnscaledWidth = 200; + if (config.RememberUnlocksFilters) + Filter.LoadValue(config.Filters.UnlocksJobFilter); + Filter.FilterChanged += () => config.Filters.UnlocksJobFilter = Filter.FilterValue; } protected override StringU8 DisplayString(in UnlockCacheItem item, int globalIndex) @@ -444,10 +481,13 @@ public sealed class UnlockTable : TableBase, private sealed class DyableColumn : FlagColumn { - public DyableColumn() + public DyableColumn(Configuration config) { Flags &= ~TableColumnFlags.NoResize; Label = new StringU8("Dye"u8); + if (config.RememberUnlocksFilters) + Filter.LoadValue(config.Filters.UnlocksDyabilityFilter); + Filter.FilterChanged += () => config.Filters.UnlocksDyabilityFilter = Filter.FilterValue; } public override float ComputeWidth(IEnumerable _) @@ -487,8 +527,13 @@ public sealed class UnlockTable : TableBase, private sealed class TradableColumn : LunaStyle.YesNoColumn { - public TradableColumn() - => Label = new StringU8("Trade"u8); + public TradableColumn(Configuration config) + { + Label = new StringU8("Trade"u8); + if (config.RememberUnlocksFilters) + Filter.LoadValue(config.Filters.UnlocksTradableFilter); + Filter.FilterChanged += () => config.Filters.UnlocksTradableFilter = Filter.FilterValue; + } protected override bool GetValue(in UnlockCacheItem item, int globalIndex, int triEnumIndex) => item.Tradable; @@ -496,8 +541,13 @@ public sealed class UnlockTable : TableBase, private sealed class CrestColumn : LunaStyle.YesNoColumn { - public CrestColumn() - => Label = new StringU8("Crest"u8); + public CrestColumn(Configuration config) + { + Label = new StringU8("Crest"u8); + if (config.RememberUnlocksFilters) + Filter.LoadValue(config.Filters.UnlocksCrestFilter); + Filter.FilterChanged += () => config.Filters.UnlocksCrestFilter = Filter.FilterValue; + } protected override bool GetValue(in UnlockCacheItem item, int globalIndex, int triEnumIndex) => item.Crest; diff --git a/Glamourer/Interop/Penumbra/PenumbraService.cs b/Glamourer/Interop/Penumbra/PenumbraService.cs index 382960d..103aacd 100644 --- a/Glamourer/Interop/Penumbra/PenumbraService.cs +++ b/Glamourer/Interop/Penumbra/PenumbraService.cs @@ -35,6 +35,15 @@ public readonly record struct ModSettings(Dictionary> Setti => new(); } +public sealed class CutsceneResolveService : IService +{ + public Func? CheckCutsceneParent; + + /// Obtain the parent of a cutscene actor if it is known. + public short CutsceneParent(ushort idx) + => (short)(CheckCutsceneParent?.Invoke(idx) ?? -1); +} + public sealed class PenumbraService : IDisposable, IService { public const int RequiredPenumbraBreakingVersion = 5; @@ -45,6 +54,8 @@ public sealed class PenumbraService : IDisposable, IService private const int KeyManual = -6160; private const string NameManual = "Glamourer (Manually)"; + public readonly CutsceneResolveService ResolveService; + private readonly IDalamudPluginInterface _pluginInterface; private readonly Configuration _config; private readonly EventSubscriber _tooltipSubscriber; @@ -84,7 +95,6 @@ public sealed class PenumbraService : IDisposable, IService private global::Penumbra.Api.IpcSubscribers.UnregisterSettingsSection? _unregisterSettingsSection; private IReadOnlyList<(string ModDirectory, IReadOnlyDictionary ChangedItems)>? _changedItems; private Func? _checkCurrentChangedItems; - private Func? _checkCutsceneParent; private Func? _getGameObject; private readonly IDisposable _initializedEvent; @@ -97,10 +107,12 @@ public sealed class PenumbraService : IDisposable, IService public int CurrentMinor { get; private set; } public DateTime AttachTime { get; private set; } - public PenumbraService(IDalamudPluginInterface pi, PenumbraReloaded penumbraReloaded, Configuration config) + public PenumbraService(IDalamudPluginInterface pi, PenumbraReloaded penumbraReloaded, CutsceneResolveService resolveService, + Configuration config) { _pluginInterface = pi; _penumbraReloaded = penumbraReloaded; + ResolveService = resolveService; _config = config; _initializedEvent = global::Penumbra.Api.IpcSubscribers.Initialized.Subscriber(pi, Reattach); _disposedEvent = global::Penumbra.Api.IpcSubscribers.Disposed.Subscriber(pi, Unattach); @@ -192,7 +204,7 @@ public sealed class PenumbraService : IDisposable, IService private ModSettings GetSettings(Guid collection, string modDirectory, string modName, out string source) { - if (_getCurrentSettingsWithTemp != null) + if (_getCurrentSettingsWithTemp is not null) { source = string.Empty; var (ec, tuple) = _getCurrentSettingsWithTemp!.Invoke(collection, modDirectory, modName, false, false, KeyFixed); @@ -204,7 +216,7 @@ public sealed class PenumbraService : IDisposable, IService : ModSettings.Empty; } - if (_queryTemporaryModSettings != null) + if (_queryTemporaryModSettings is not null) { var tempEc = _queryTemporaryModSettings.Invoke(collection, modDirectory, out var tempTuple, out source, 0, modName); if (tempEc is PenumbraApiEc.Success && tempTuple != null) @@ -485,9 +497,6 @@ public sealed class PenumbraService : IDisposable, IService public Actor GameObjectFromDrawObject(Model drawObject) => _getGameObject?.Invoke(drawObject.Address) ?? Actor.Null; - /// Obtain the parent of a cutscene actor if it is known. - public short CutsceneParent(ushort idx) - => (short)(_checkCutsceneParent?.Invoke(idx) ?? -1); /// Try to redraw the given actor. public void RedrawObject(Actor actor, RedrawType settings) @@ -554,7 +563,7 @@ public sealed class PenumbraService : IDisposable, IService _collectionByIdentifier = new global::Penumbra.Api.IpcSubscribers.GetCollectionsByIdentifier(_pluginInterface); _collections = new global::Penumbra.Api.IpcSubscribers.GetCollections(_pluginInterface); _redraw = new global::Penumbra.Api.IpcSubscribers.RedrawObject(_pluginInterface); - _checkCutsceneParent = new global::Penumbra.Api.IpcSubscribers.GetCutsceneParentIndexFunc(_pluginInterface).Invoke(); + ResolveService.CheckCutsceneParent = new global::Penumbra.Api.IpcSubscribers.GetCutsceneParentIndexFunc(_pluginInterface).Invoke(); _getGameObject = new global::Penumbra.Api.IpcSubscribers.GetGameObjectFromDrawObjectFunc(_pluginInterface).Invoke(); _objectCollection = new global::Penumbra.Api.IpcSubscribers.GetCollectionForObject(_pluginInterface); _getMods = new global::Penumbra.Api.IpcSubscribers.GetModList(_pluginInterface); @@ -623,7 +632,7 @@ public sealed class PenumbraService : IDisposable, IService _collections = null; _redraw = null; _getGameObject = null; - _checkCutsceneParent = null; + ResolveService.CheckCutsceneParent = null; _objectCollection = null; _getMods = null; _currentCollection = null; diff --git a/Glamourer/Services/BackupService.cs b/Glamourer/Services/BackupService.cs index fdd3f90..17fd3bf 100644 --- a/Glamourer/Services/BackupService.cs +++ b/Glamourer/Services/BackupService.cs @@ -10,7 +10,7 @@ public sealed class BackupService(Logger log, FilenameService provider) : BaseBa var list = new List(16) { new(fileNames.ConfigurationFile), - new(fileNames.UiConfiguration), + new(fileNames.UiConfigurationFile), new(fileNames.MigrationDesignFileSystem), new(fileNames.MigrationDesignFile), new(fileNames.AutomationFile), diff --git a/Glamourer/Services/FilenameService.cs b/Glamourer/Services/FilenameService.cs index e59d97c..433cb07 100644 --- a/Glamourer/Services/FilenameService.cs +++ b/Glamourer/Services/FilenameService.cs @@ -18,7 +18,8 @@ public sealed class FilenameService(IDalamudPluginInterface pi) : BaseFilePathPr public readonly string EphemeralConfigFile = Path.Combine(pi.ConfigDirectory.FullName, "ephemeral_config.json"); public readonly string NpcAppearanceFile = Path.Combine(pi.ConfigDirectory.FullName, "npc_appearance_data.json"); public readonly string CollectionOverrideFile = Path.Combine(pi.ConfigDirectory.FullName, "collection_overrides.json"); - public readonly string UiConfiguration = Path.Combine(pi.ConfigDirectory.FullName, "ui_config.json"); + public readonly string UiConfigurationFile = Path.Combine(pi.ConfigDirectory.FullName, "ui_config.json"); + public readonly string FilterFile = Path.Combine(pi.ConfigDirectory.FullName, "filters.json"); public readonly string FileSystemFolder = Path.Combine(pi.ConfigDirectory.FullName, "design_filesystem"); public readonly string FileSystemEmptyFolders = Path.Combine(pi.ConfigDirectory.FullName, "design_filesystem", "empty_folders.json"); public readonly string FileSystemExpandedFolders = Path.Combine(pi.ConfigDirectory.FullName, "design_filesystem", "expanded_folders.json"); diff --git a/Glamourer/Services/ServiceManager.cs b/Glamourer/Services/ServiceManager.cs index e06cdb4..18b559c 100644 --- a/Glamourer/Services/ServiceManager.cs +++ b/Glamourer/Services/ServiceManager.cs @@ -18,7 +18,7 @@ public static class StaticServiceManager .AddExistingService(log) .AddSingleton() .AddSingleton() - .AddSingleton(p => new CutsceneResolver(p.GetRequiredService().CutsceneParent)) + .AddSingleton(p => new CutsceneResolver(p.GetRequiredService().CutsceneParent)) .AddExistingService(glamourer); services.AddIServices(typeof(EquipItem).Assembly); services.AddIServices(typeof(Glamourer).Assembly); diff --git a/Luna b/Luna index 4a46e85..bc900c5 160000 --- a/Luna +++ b/Luna @@ -1 +1 @@ -Subproject commit 4a46e8551dd4438465c013c4a01d2936e5b4d4da +Subproject commit bc900c5b5959915a87f60487f5b67aa358b195be diff --git a/Penumbra.Api b/Penumbra.Api index 9cfcaf3..c7c1cae 160000 --- a/Penumbra.Api +++ b/Penumbra.Api @@ -1 +1 @@ -Subproject commit 9cfcaf39fef363e281f066b55811deef72908f2f +Subproject commit c7c1cae55b34c59580492a8e279205844e2116e2 diff --git a/Penumbra.GameData b/Penumbra.GameData index f75aa96..2d83cda 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit f75aa967763347148401ec2cb800dcba2523f8c0 +Subproject commit 2d83cda9e72c132b90bba20dd862a442a218b6c2