From ed6f32f757b6f84ff375745214ce141d9daedea7 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Fri, 1 Mar 2024 14:29:36 +0100 Subject: [PATCH] Improve QDB. --- Glamourer/Configuration.cs | 85 +++++----- Glamourer/Gui/DesignQuickBar.cs | 151 +++++++++++++++--- Glamourer/Gui/GlamourerWindowSystem.cs | 1 + Glamourer/Gui/MainWindow.cs | 4 - Glamourer/Gui/Tabs/SettingsTab/SettingsTab.cs | 59 ++++++- Glamourer/Services/ConfigMigrationService.cs | 32 ++-- Glamourer/State/StateManager.cs | 54 ++++++- 7 files changed, 299 insertions(+), 87 deletions(-) diff --git a/Glamourer/Configuration.cs b/Glamourer/Configuration.cs index 36e12f5..d7b9ec1 100644 --- a/Glamourer/Configuration.cs +++ b/Glamourer/Configuration.cs @@ -18,35 +18,38 @@ public class Configuration : IPluginConfiguration, ISavable [JsonIgnore] public readonly EphemeralConfig Ephemeral; - public bool UseRestrictedGearProtection { get; set; } = false; - public bool OpenFoldersByDefault { get; set; } = false; - public bool AutoRedrawEquipOnChanges { get; set; } = false; - public bool EnableAutoDesigns { get; set; } = true; - public bool HideApplyCheckmarks { get; set; } = false; - public bool SmallEquip { get; set; } = false; - public bool UnlockedItemMode { get; set; } = false; - public byte DisableFestivals { get; set; } = 1; - public bool EnableGameContextMenu { get; set; } = true; - public bool HideWindowInCutscene { get; set; } = false; - public bool ShowAutomationSetEditing { get; set; } = true; - public bool ShowAllAutomatedApplicationRules { get; set; } = true; - public bool ShowUnlockedItemWarnings { get; set; } = true; - public bool RevertManualChangesOnZoneChange { get; set; } = false; - public bool ShowQuickBarInTabs { get; set; } = true; - public bool OpenWindowAtStart { get; set; } = false; - public bool UseAdvancedParameters { get; set; } = true; - public bool UseAdvancedDyes { get; set; } = true; - public bool KeepAdvancedDyesAttached { get; set; } = true; - public bool ShowRevertAdvancedParametersButton { get; set; } = true; - public bool ShowPalettePlusImport { get; set; } = true; - public bool UseFloatForColors { get; set; } = true; - public bool UseRgbForColors { get; set; } = true; - public bool ShowColorConfig { get; set; } = true; - public bool ChangeEntireItem { get; set; } = false; - public bool AlwaysApplyAssociatedMods { get; set; } = false; - public ModifiableHotkey ToggleQuickDesignBar { get; set; } = new(VirtualKey.NO_KEY); - public DoubleModifier DeleteDesignModifier { get; set; } = new(ModifierHotkey.Control, ModifierHotkey.Shift); - public ChangeLogDisplayType ChangeLogDisplayType { get; set; } = ChangeLogDisplayType.New; + public bool UseRestrictedGearProtection { get; set; } = false; + public bool OpenFoldersByDefault { get; set; } = false; + public bool AutoRedrawEquipOnChanges { get; set; } = false; + public bool EnableAutoDesigns { get; set; } = true; + public bool HideApplyCheckmarks { get; set; } = false; + public bool SmallEquip { get; set; } = false; + public bool UnlockedItemMode { get; set; } = false; + public byte DisableFestivals { get; set; } = 1; + public bool EnableGameContextMenu { get; set; } = true; + public bool HideWindowInCutscene { get; set; } = false; + public bool ShowAutomationSetEditing { get; set; } = true; + public bool ShowAllAutomatedApplicationRules { get; set; } = true; + public bool ShowUnlockedItemWarnings { get; set; } = true; + public bool RevertManualChangesOnZoneChange { get; set; } = false; + public bool ShowQuickBarInTabs { get; set; } = true; + public bool OpenWindowAtStart { get; set; } = false; + public bool ShowWindowWhenUiHidden { get; set; } = false; + public bool UseAdvancedParameters { get; set; } = true; + public bool UseAdvancedDyes { get; set; } = true; + public bool KeepAdvancedDyesAttached { get; set; } = true; + public bool ShowPalettePlusImport { get; set; } = true; + public bool UseFloatForColors { get; set; } = true; + public bool UseRgbForColors { get; set; } = true; + public bool ShowColorConfig { get; set; } = true; + public bool ChangeEntireItem { get; set; } = false; + public bool AlwaysApplyAssociatedMods { get; set; } = false; + public ModifiableHotkey ToggleQuickDesignBar { get; set; } = new(VirtualKey.NO_KEY); + public DoubleModifier DeleteDesignModifier { get; set; } = new(ModifierHotkey.Control, ModifierHotkey.Shift); + public ChangeLogDisplayType ChangeLogDisplayType { get; set; } = ChangeLogDisplayType.New; + + public QdbButtons QdbButtons { get; set; } = + QdbButtons.ApplyDesign | QdbButtons.RevertAll | QdbButtons.RevertAutomation | QdbButtons.RevertAdvanced; [JsonConverter(typeof(SortModeConverter))] [JsonProperty(Order = int.MaxValue)] @@ -78,15 +81,8 @@ public class Configuration : IPluginConfiguration, ISavable public void Save() => _saveService.DelaySave(this); - public void Load(ConfigMigrationService migrator) + private void Load(ConfigMigrationService migrator) { - static void HandleDeserializationError(object? sender, ErrorEventArgs errorArgs) - { - Glamourer.Log.Error( - $"Error parsing Configuration at {errorArgs.ErrorContext.Path}, using default or migrating:\n{errorArgs.ErrorContext.Error}"); - errorArgs.ErrorContext.Handled = true; - } - if (!File.Exists(_saveService.FileNames.ConfigFile)) return; @@ -107,6 +103,14 @@ public class Configuration : IPluginConfiguration, ISavable } migrator.Migrate(this); + return; + + static void HandleDeserializationError(object? sender, ErrorEventArgs errorArgs) + { + Glamourer.Log.Error( + $"Error parsing Configuration at {errorArgs.ErrorContext.Path}, using default or migrating:\n{errorArgs.ErrorContext.Error}"); + errorArgs.ErrorContext.Handled = true; + } } public string ToFilename(FilenameService fileNames) @@ -114,14 +118,15 @@ public class Configuration : IPluginConfiguration, ISavable public void Save(StreamWriter writer) { - using var jWriter = new JsonTextWriter(writer) { Formatting = Formatting.Indented }; - var serializer = new JsonSerializer { Formatting = Formatting.Indented }; + using var jWriter = new JsonTextWriter(writer); + jWriter.Formatting = Formatting.Indented; + var serializer = new JsonSerializer { Formatting = Formatting.Indented }; serializer.Serialize(jWriter, this); } public static class Constants { - public const int CurrentVersion = 5; + public const int CurrentVersion = 6; public static readonly ISortMode[] ValidSortModes = { diff --git a/Glamourer/Gui/DesignQuickBar.cs b/Glamourer/Gui/DesignQuickBar.cs index b602ee8..35f23bb 100644 --- a/Glamourer/Gui/DesignQuickBar.cs +++ b/Glamourer/Gui/DesignQuickBar.cs @@ -16,6 +16,17 @@ using Penumbra.GameData.Actors; namespace Glamourer.Gui; +[Flags] +public enum QdbButtons +{ + ApplyDesign = 0x01, + RevertAll = 0x02, + RevertAutomation = 0x04, + RevertAdvanced = 0x08, + RevertEquip = 0x10, + RevertCustomize = 0x20, +} + public sealed class DesignQuickBar : Window, IDisposable { private ImGuiWindowFlags GetFlags @@ -55,7 +66,7 @@ public sealed class DesignQuickBar : Window, IDisposable public override void PreOpenCheck() { CheckHotkeys(); - IsOpen = _config.Ephemeral.ShowDesignQuickBar; + IsOpen = _config.Ephemeral.ShowDesignQuickBar && _config.QdbButtons != 0; } public override void PreDraw() @@ -93,15 +104,20 @@ public sealed class DesignQuickBar : Window, IDisposable var spacing = ImGui.GetStyle().ItemInnerSpacing; using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing); var buttonSize = new Vector2(ImGui.GetFrameHeight()); - var comboSize = width - _numButtons * (buttonSize.X + spacing.X); - _designCombo.Draw(comboSize); PrepareButtons(); - ImGui.SameLine(); - DrawApplyButton(buttonSize); - ImGui.SameLine(); + if (_config.QdbButtons.HasFlag(QdbButtons.ApplyDesign)) + { + var comboSize = width - _numButtons * (buttonSize.X + spacing.X); + _designCombo.Draw(comboSize); + ImGui.SameLine(); + DrawApplyButton(buttonSize); + } + DrawRevertButton(buttonSize); - DrawRevertAutomationButton(buttonSize); + DrawRevertEquipButton(buttonSize); + DrawRevertCustomizeButton(buttonSize); DrawRevertAdvancedCustomization(buttonSize); + DrawRevertAutomationButton(buttonSize); } private ActorIdentifier _playerIdentifier; @@ -152,12 +168,14 @@ public sealed class DesignQuickBar : Window, IDisposable var (clicked, id, data, state) = ResolveTarget(FontAwesomeIcon.PlayCircle, size, tooltip, available); + ImGui.SameLine(); if (!clicked) return; if (state == null && !_stateManager.GetOrCreate(id, data.Objects[0], out state)) { - Glamourer.Messager.NotificationMessage($"Could not apply {design!.ResolveName(true)} to {id.Incognito(null)}: Failed to create state."); + Glamourer.Messager.NotificationMessage( + $"Could not apply {design!.ResolveName(true)} to {id.Incognito(null)}: Failed to create state."); return; } @@ -166,8 +184,11 @@ public sealed class DesignQuickBar : Window, IDisposable _stateManager.ApplyDesign(state, design, ApplySettings.ManualWithLinks); } - public void DrawRevertButton(Vector2 buttonSize) + private void DrawRevertButton(Vector2 buttonSize) { + if (!_config.QdbButtons.HasFlag(QdbButtons.RevertAll)) + return; + var available = 0; var tooltip = string.Empty; if (_playerIdentifier.IsValid && _playerState is { IsLocked: false }) @@ -188,15 +209,19 @@ public sealed class DesignQuickBar : Window, IDisposable tooltip = "Neither player character nor target are available, have state modified by Glamourer, or their state is locked."; var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.UndoAlt, buttonSize, tooltip, available); + ImGui.SameLine(); if (clicked) _stateManager.ResetState(state!, StateSource.Manual); } - public void DrawRevertAutomationButton(Vector2 buttonSize) + private void DrawRevertAutomationButton(Vector2 buttonSize) { if (!_config.EnableAutoDesigns) return; + if (!_config.QdbButtons.HasFlag(QdbButtons.RevertAutomation)) + return; + var available = 0; var tooltip = string.Empty; @@ -217,8 +242,8 @@ public sealed class DesignQuickBar : Window, IDisposable if (available == 0) tooltip = "Neither player character nor target are available, have state modified by Glamourer, or their state is locked."; - ImGui.SameLine(); var (clicked, id, data, state) = ResolveTarget(FontAwesomeIcon.SyncAlt, buttonSize, tooltip, available); + ImGui.SameLine(); if (!clicked) return; @@ -229,9 +254,12 @@ public sealed class DesignQuickBar : Window, IDisposable } } - public void DrawRevertAdvancedCustomization(Vector2 buttonSize) + private void DrawRevertAdvancedCustomization(Vector2 buttonSize) { - if (!_config.ShowRevertAdvancedParametersButton || !_config.UseAdvancedParameters) + if (!_config.UseAdvancedParameters) + return; + + if (!_config.QdbButtons.HasFlag(QdbButtons.RevertAdvanced)) return; var available = 0; @@ -254,12 +282,74 @@ public sealed class DesignQuickBar : Window, IDisposable if (available == 0) tooltip = "Neither player character nor target are available or their state is locked."; - ImGui.SameLine(); var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.Palette, buttonSize, tooltip, available); + ImGui.SameLine(); if (clicked) _stateManager.ResetAdvancedState(state!, StateSource.Manual); } + private void DrawRevertCustomizeButton(Vector2 buttonSize) + { + if (!_config.QdbButtons.HasFlag(QdbButtons.RevertCustomize)) + return; + + var available = 0; + var tooltip = string.Empty; + + if (_playerIdentifier.IsValid && _playerState is { IsLocked: false } && _playerData.Valid) + { + available |= 1; + tooltip = "Left-Click: Revert the customizations of the player character to their game state."; + } + + if (_targetIdentifier.IsValid && _targetState is { IsLocked: false } && _targetData.Valid) + { + if (available != 0) + tooltip += '\n'; + available |= 2; + tooltip += $"Right-Click: Revert the customizations of {_targetIdentifier} to their game state."; + } + + if (available == 0) + tooltip = "Neither player character nor target are available or their state is locked."; + + var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.User, buttonSize, tooltip, available); + ImGui.SameLine(); + if (clicked) + _stateManager.ResetCustomize(state!, StateSource.Manual); + } + + private void DrawRevertEquipButton(Vector2 buttonSize) + { + if (!_config.QdbButtons.HasFlag(QdbButtons.RevertEquip)) + return; + + var available = 0; + var tooltip = string.Empty; + + if (_playerIdentifier.IsValid && _playerState is { IsLocked: false } && _playerData.Valid) + { + available |= 1; + tooltip = "Left-Click: Revert the equipment of the player character to its game state."; + } + + if (_targetIdentifier.IsValid && _targetState is { IsLocked: false } && _targetData.Valid) + { + if (available != 0) + tooltip += '\n'; + available |= 2; + tooltip += $"Right-Click: Revert the equipment of {_targetIdentifier} to its game state."; + } + + if (available == 0) + tooltip = "Neither player character nor target are available or their state is locked."; + + var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.Vest, buttonSize, tooltip, available); + ImGui.SameLine(); + if (clicked) + _stateManager.ResetEquip(state!, StateSource.Manual); + } + private (bool, ActorIdentifier, ActorData, ActorState?) ResolveTarget(FontAwesomeIcon icon, Vector2 buttonSize, string tooltip, int available) { @@ -292,15 +382,32 @@ public sealed class DesignQuickBar : Window, IDisposable private float UpdateWidth() { - _numButtons = (_config.EnableAutoDesigns, _config is { ShowRevertAdvancedParametersButton: true, UseAdvancedParameters: true }) switch + _numButtons = 0; + if (_config.QdbButtons.HasFlag(QdbButtons.RevertAll)) + ++_numButtons; + if (_config.EnableAutoDesigns && _config.QdbButtons.HasFlag(QdbButtons.RevertAutomation)) + ++_numButtons; + if ((_config.UseAdvancedParameters || _config.UseAdvancedDyes) && _config.QdbButtons.HasFlag(QdbButtons.RevertAdvanced)) + ++_numButtons; + if (_config.QdbButtons.HasFlag(QdbButtons.RevertCustomize)) + ++_numButtons; + if (_config.QdbButtons.HasFlag(QdbButtons.RevertEquip)) + ++_numButtons; + if (_config.QdbButtons.HasFlag(QdbButtons.ApplyDesign)) { - (true, true) => 4, - (false, true) => 3, - (true, false) => 3, - (false, false) => 2, - }; - Size = new Vector2((7 + _numButtons) * ImGui.GetFrameHeight() + _numButtons * ImGui.GetStyle().ItemInnerSpacing.X, - ImGui.GetFrameHeight()); + ++_numButtons; + Size = new Vector2((7 + _numButtons) * ImGui.GetFrameHeight() + _numButtons * ImGui.GetStyle().ItemInnerSpacing.X, + ImGui.GetFrameHeight()); + } + else + { + Size = new Vector2( + _numButtons * ImGui.GetFrameHeight() + + (_numButtons - 1) * ImGui.GetStyle().ItemInnerSpacing.X + + ImGui.GetStyle().WindowPadding.X * 2, + ImGui.GetFrameHeight()); + } + return Size.Value.X; } } diff --git a/Glamourer/Gui/GlamourerWindowSystem.cs b/Glamourer/Gui/GlamourerWindowSystem.cs index 59b237c..39f3c6d 100644 --- a/Glamourer/Gui/GlamourerWindowSystem.cs +++ b/Glamourer/Gui/GlamourerWindowSystem.cs @@ -25,6 +25,7 @@ public class GlamourerWindowSystem : IDisposable _uiBuilder.Draw += _windowSystem.Draw; _uiBuilder.OpenConfigUi += _ui.Toggle; _uiBuilder.DisableCutsceneUiHide = !config.HideWindowInCutscene; + _uiBuilder.DisableUserUiHide = config.ShowWindowWhenUiHidden; } public void Dispose() diff --git a/Glamourer/Gui/MainWindow.cs b/Glamourer/Gui/MainWindow.cs index d9a6e1f..71d3822 100644 --- a/Glamourer/Gui/MainWindow.cs +++ b/Glamourer/Gui/MainWindow.cs @@ -159,10 +159,6 @@ public class MainWindow : Window, IDisposable { var width = ImGui.CalcTextSize("Join Discord for Support").X + ImGui.GetStyle().FramePadding.X * 2; var xPos = ImGui.GetWindowWidth() - width; - // Respect the scroll bar width. - if (ImGui.GetScrollMaxY() > 0) - xPos -= ImGui.GetStyle().ScrollbarSize + ImGui.GetStyle().FramePadding.X; - ImGui.SetCursorPos(new Vector2(xPos, 0)); CustomGui.DrawDiscordButton(Glamourer.Messager, width); diff --git a/Glamourer/Gui/Tabs/SettingsTab/SettingsTab.cs b/Glamourer/Gui/Tabs/SettingsTab/SettingsTab.cs index fab2085..88f7b58 100644 --- a/Glamourer/Gui/Tabs/SettingsTab/SettingsTab.cs +++ b/Glamourer/Gui/Tabs/SettingsTab/SettingsTab.cs @@ -120,6 +120,7 @@ public class SettingsTab( Checkbox("Show Quick Design Bar in Main Window", "Show the quick design bar in the tab selection part of the main window, too.", config.ShowQuickBarInTabs, v => config.ShowQuickBarInTabs = v); + DrawQuickDesignBoxes(); ImGui.Dummy(Vector2.Zero); ImGui.Separator(); @@ -134,6 +135,12 @@ public class SettingsTab( else contextMenuService.Disable(); }); + Checkbox("Show Window when UI is Hidden", "Whether to show Glamourer windows even when the games UI is hidden.", + config.ShowWindowWhenUiHidden, v => + { + config.ShowWindowWhenUiHidden = v; + uiBuilder.DisableUserUiHide = v; + }); Checkbox("Hide Window in Cutscenes", "Whether the main Glamourer window should automatically be hidden when entering cutscenes or not.", config.HideWindowInCutscene, v => @@ -176,9 +183,9 @@ public class SettingsTab( config.ShowUnlockedItemWarnings, v => config.ShowUnlockedItemWarnings = v); if (config.UseAdvancedParameters) { - Checkbox("Show Revert Advanced Customizations Button in Quick Design Bar", - "Show a button to revert only advanced customizations on your character or a target in the quick design bar.", - config.ShowRevertAdvancedParametersButton, v => config.ShowRevertAdvancedParametersButton = v); + //Checkbox("Show Revert Advanced Customizations Button in Quick Design Bar", + // "Show a button to revert only advanced customizations on your character or a target in the quick design bar.", + // config.ShowRevertAdvancedParametersButton, v => config.ShowRevertAdvancedParametersButton = v); Checkbox("Show Color Display Config", "Show the Color Display configuration options in the Advanced Customization panels.", config.ShowColorConfig, v => config.ShowColorConfig = v); Checkbox("Show Palette+ Import Button", @@ -198,6 +205,52 @@ public class SettingsTab( ImGui.NewLine(); } + private void DrawQuickDesignBoxes() + { + var showAuto = config.EnableAutoDesigns; + var showAdvanced = config.UseAdvancedParameters || config.UseAdvancedDyes; + var numColumns = 6 - (showAuto ? 0 : 1) - (showAdvanced ? 0 : 1); + ImGui.NewLine(); + ImGui.TextUnformatted("Show the Following Buttons in the Quick Design Bar:"); + ImGui.Dummy(Vector2.Zero); + using var table = ImRaii.Table("##tableQdb", numColumns, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders | ImGuiTableFlags.NoHostExtendX); + if (!table) + return; + + var columns = new[] + { + (" Apply Design ", true, QdbButtons.ApplyDesign), + (" Revert All ", true, QdbButtons.RevertAll), + (" Revert to Auto ", showAuto, QdbButtons.RevertAutomation), + (" Revert Equip ", true, QdbButtons.RevertEquip), + (" Revert Customization ", true, QdbButtons.RevertCustomize), + (" Revert Advanced ", showAdvanced, QdbButtons.RevertAdvanced), + }; + + foreach (var (label, _, _) in columns.Where(t => t.Item2)) + { + ImGui.TableNextColumn(); + ImGui.TableHeader(label); + } + + foreach (var (_, _, flag) in columns.Where(t => t.Item2)) + { + using var id = ImRaii.PushId((int)flag); + ImGui.TableNextColumn(); + var offset = (ImGui.GetContentRegionAvail().X - ImGui.GetFrameHeight()) / 2; + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + offset); + var value = config.QdbButtons.HasFlag(flag); + if (!ImGui.Checkbox(string.Empty, ref value)) + continue; + + var buttons = value ? config.QdbButtons | flag : config.QdbButtons & ~flag; + if (buttons == config.QdbButtons) + continue; + + config.QdbButtons = buttons; + config.Save(); + } + } private void PaletteImportButton() { diff --git a/Glamourer/Services/ConfigMigrationService.cs b/Glamourer/Services/ConfigMigrationService.cs index 55b0664..88eaf69 100644 --- a/Glamourer/Services/ConfigMigrationService.cs +++ b/Glamourer/Services/ConfigMigrationService.cs @@ -4,38 +4,38 @@ using Newtonsoft.Json.Linq; namespace Glamourer.Services; -public class ConfigMigrationService +public class ConfigMigrationService(SaveService saveService, FixedDesignMigrator fixedDesignMigrator, BackupService backupService) { - private readonly SaveService _saveService; - private readonly FixedDesignMigrator _fixedDesignMigrator; - private readonly BackupService _backupService; - private Configuration _config = null!; private JObject _data = null!; - public ConfigMigrationService(SaveService saveService, FixedDesignMigrator fixedDesignMigrator, BackupService backupService) - { - _saveService = saveService; - _fixedDesignMigrator = fixedDesignMigrator; - _backupService = backupService; - } - public void Migrate(Configuration config) { _config = config; - if (config.Version >= Configuration.Constants.CurrentVersion || !File.Exists(_saveService.FileNames.ConfigFile)) + if (config.Version >= Configuration.Constants.CurrentVersion || !File.Exists(saveService.FileNames.ConfigFile)) { AddColors(config, false); return; } - _data = JObject.Parse(File.ReadAllText(_saveService.FileNames.ConfigFile)); + _data = JObject.Parse(File.ReadAllText(saveService.FileNames.ConfigFile)); MigrateV1To2(); MigrateV2To4(); MigrateV4To5(); + MigrateV5To6(); AddColors(config, true); } + private void MigrateV5To6() + { + if (_config.Version > 5) + return; + + if (_data["ShowRevertAdvancedParametersButton"]?.ToObject() ?? true) + _config.QdbButtons |= QdbButtons.RevertAdvanced; + _config.Version = 6; + } + // Ephemeral Config. private void MigrateV4To5() { @@ -59,8 +59,8 @@ public class ConfigMigrationService if (_config.Version > 1) return; - _backupService.CreateMigrationBackup("pre_v1_to_v2_migration"); - _fixedDesignMigrator.Migrate(_data["FixedDesigns"]); + backupService.CreateMigrationBackup("pre_v1_to_v2_migration"); + fixedDesignMigrator.Migrate(_data["FixedDesigns"]); _config.Version = 2; var customizationColor = _data["CustomizationColor"]?.ToObject() ?? ColorId.CustomizationDesign.Data().DefaultColor; _config.Colors[ColorId.CustomizationDesign] = customizationColor; diff --git a/Glamourer/State/StateManager.cs b/Glamourer/State/StateManager.cs index 3637729..1b190b9 100644 --- a/Glamourer/State/StateManager.cs +++ b/Glamourer/State/StateManager.cs @@ -29,7 +29,8 @@ public sealed class StateManager( DesignMerger merger, ModSettingApplier modApplier, GPoseService gPose) - : StateEditor(editor, applier, @event, jobChange, config, items, merger, modApplier, gPose), IReadOnlyDictionary + : StateEditor(editor, applier, @event, jobChange, config, items, merger, modApplier, gPose), + IReadOnlyDictionary { private readonly Dictionary _states = []; @@ -225,7 +226,7 @@ public sealed class StateManager( || !state.ModelData.IsHuman || CustomizeArray.Compare(state.ModelData.Customize, state.BaseData.Customize).RequiresRedraw(); - state.ModelData = state.BaseData; + state.ModelData = state.BaseData; state.ModelData.SetIsWet(false); foreach (var index in Enum.GetValues()) state.Sources[index] = StateSource.Game; @@ -281,6 +282,55 @@ public sealed class StateManager( StateChanged.Invoke(StateChanged.Type.Reset, source, state, actors, null); } + public void ResetCustomize(ActorState state, StateSource source, uint key = 0) + { + if (!state.Unlock(key) || !state.ModelData.IsHuman) + return; + + foreach (var flag in CustomizationExtensions.All) + state.Sources[flag] = StateSource.Game; + + state.ModelData = state.BaseData; + var actors = ActorData.Invalid; + if (source is not StateSource.Game) + actors = Applier.ChangeCustomize(state, true); + Glamourer.Log.Verbose( + $"Reset customization state of {state.Identifier.Incognito(null)} to game base. [Affecting {actors.ToLazyString("nothing")}.]"); + } + + public void ResetEquip(ActorState state, StateSource source, uint key = 0) + { + if (!state.Unlock(key)) + return; + + foreach (var slot in EquipSlotExtensions.FullSlots) + { + state.Sources[slot, true] = StateSource.Game; + state.Sources[slot, false] = StateSource.Game; + if (source is not StateSource.Game) + { + state.ModelData.SetItem(slot, state.BaseData.Item(slot)); + state.ModelData.SetStain(slot, state.BaseData.Stain(slot)); + } + } + + var actors = ActorData.Invalid; + if (source is not StateSource.Game) + { + actors = Applier.ChangeArmor(state, EquipSlotExtensions.EqdpSlots[0], true); + foreach (var slot in EquipSlotExtensions.EqdpSlots.Skip(1)) + Applier.ChangeArmor(actors, slot, state.ModelData.Armor(slot), !state.Sources[slot, false].IsIpc(), + state.ModelData.IsHatVisible()); + + var mainhandActors = state.ModelData.MainhandType != state.BaseData.MainhandType ? actors.OnlyGPose() : actors; + Applier.ChangeMainhand(mainhandActors, state.ModelData.Item(EquipSlot.MainHand), state.ModelData.Stain(EquipSlot.MainHand)); + var offhandActors = state.ModelData.OffhandType != state.BaseData.OffhandType ? actors.OnlyGPose() : actors; + Applier.ChangeOffhand(offhandActors, state.ModelData.Item(EquipSlot.OffHand), state.ModelData.Stain(EquipSlot.OffHand)); + } + + Glamourer.Log.Verbose($"Reset equipment state of {state.Identifier.Incognito(null)} to game base. [Affecting {actors.ToLazyString("nothing")}.]"); + } + public void ResetStateFixed(ActorState state, bool respectManualPalettes, uint key = 0) { if (!state.Unlock(key))