diff --git a/Glamourer/Configuration.cs b/Glamourer/Configuration.cs index 1d3689d..c9ff0e6 100644 --- a/Glamourer/Configuration.cs +++ b/Glamourer/Configuration.cs @@ -81,7 +81,7 @@ public class Configuration : IPluginConfiguration, ISavable public ChangeLogDisplayType ChangeLogDisplayType { get; set; } = ChangeLogDisplayType.New; public QdbButtons QdbButtons { get; set; } = - QdbButtons.ApplyDesign | QdbButtons.RevertAll | QdbButtons.RevertAutomation | QdbButtons.RevertAdvanced; + QdbButtons.ApplyDesign | QdbButtons.RevertAll | QdbButtons.RevertAutomation | QdbButtons.RevertAdvancedDyes; [JsonConverter(typeof(SortModeConverter))] [JsonProperty(Order = int.MaxValue)] @@ -158,7 +158,7 @@ public class Configuration : IPluginConfiguration, ISavable public static class Constants { - public const int CurrentVersion = 7; + public const int CurrentVersion = 8; public static readonly ISortMode[] ValidSortModes = [ diff --git a/Glamourer/Gui/DesignQuickBar.cs b/Glamourer/Gui/DesignQuickBar.cs index 5112d97..b64a5f2 100644 --- a/Glamourer/Gui/DesignQuickBar.cs +++ b/Glamourer/Gui/DesignQuickBar.cs @@ -19,14 +19,15 @@ namespace Glamourer.Gui; [Flags] public enum QdbButtons { - ApplyDesign = 0x01, - RevertAll = 0x02, - RevertAutomation = 0x04, - RevertAdvanced = 0x08, - RevertEquip = 0x10, - RevertCustomize = 0x20, - ReapplyAutomation = 0x40, - ResetSettings = 0x80, + ApplyDesign = 0x01, + RevertAll = 0x02, + RevertAutomation = 0x04, + RevertAdvancedDyes = 0x08, + RevertEquip = 0x10, + RevertCustomize = 0x20, + ReapplyAutomation = 0x40, + ResetSettings = 0x80, + RevertAdvancedCustomization = 0x100, } public sealed class DesignQuickBar : Window, IDisposable @@ -124,6 +125,7 @@ public sealed class DesignQuickBar : Window, IDisposable DrawRevertEquipButton(buttonSize); DrawRevertCustomizeButton(buttonSize); DrawRevertAdvancedCustomization(buttonSize); + DrawRevertAdvancedDyes(buttonSize); DrawRevertAutomationButton(buttonSize); DrawReapplyAutomationButton(buttonSize); DrawResetSettingsButton(buttonSize); @@ -318,7 +320,7 @@ public sealed class DesignQuickBar : Window, IDisposable private void DrawRevertAdvancedCustomization(Vector2 buttonSize) { - if (!_config.QdbButtons.HasFlag(QdbButtons.RevertAdvanced)) + if (!_config.QdbButtons.HasFlag(QdbButtons.RevertAdvancedCustomization)) return; var available = 0; @@ -327,7 +329,7 @@ public sealed class DesignQuickBar : Window, IDisposable if (_playerIdentifier.IsValid && _playerState is { IsLocked: false } && _playerData.Valid) { available |= 1; - _tooltipBuilder.Append("Left-Click: Revert the advanced customizations and dyes of the player character to their game state."); + _tooltipBuilder.Append("Left-Click: Revert the advanced customizations of the player character to their game state."); } if (_targetIdentifier.IsValid && _targetState is { IsLocked: false } && _targetData.Valid) @@ -335,7 +337,40 @@ public sealed class DesignQuickBar : Window, IDisposable if (available != 0) _tooltipBuilder.Append('\n'); available |= 2; - _tooltipBuilder.Append("Right-Click: Revert the advanced customizations and dyes of ") + _tooltipBuilder.Append("Right-Click: Revert the advanced customizations of ") + .Append(_targetIdentifier) + .Append(" to their game state."); + } + + if (available == 0) + _tooltipBuilder.Append("Neither player character nor target are available or their state is locked."); + + var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.PaintBrush, buttonSize, available); + ImGui.SameLine(); + if (clicked) + _stateManager.ResetAdvancedCustomizations(state!, StateSource.Manual); + } + + private void DrawRevertAdvancedDyes(Vector2 buttonSize) + { + if (!_config.QdbButtons.HasFlag(QdbButtons.RevertAdvancedDyes)) + return; + + var available = 0; + _tooltipBuilder.Clear(); + + if (_playerIdentifier.IsValid && _playerState is { IsLocked: false } && _playerData.Valid) + { + available |= 1; + _tooltipBuilder.Append("Left-Click: Revert the advanced dyes of the player character to their game state."); + } + + if (_targetIdentifier.IsValid && _targetState is { IsLocked: false } && _targetData.Valid) + { + if (available != 0) + _tooltipBuilder.Append('\n'); + available |= 2; + _tooltipBuilder.Append("Right-Click: Revert the advanced dyes of ") .Append(_targetIdentifier) .Append(" to their game state."); } @@ -346,7 +381,7 @@ public sealed class DesignQuickBar : Window, IDisposable var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.Palette, buttonSize, available); ImGui.SameLine(); if (clicked) - _stateManager.ResetAdvancedState(state!, StateSource.Manual); + _stateManager.ResetAdvancedDyes(state!, StateSource.Manual); } private void DrawRevertCustomizeButton(Vector2 buttonSize) @@ -501,7 +536,7 @@ public sealed class DesignQuickBar : Window, IDisposable ++_numButtons; } - if (_config.QdbButtons.HasFlag(QdbButtons.RevertAdvanced)) + if (_config.QdbButtons.HasFlag(QdbButtons.RevertAdvancedCustomization)) ++_numButtons; if (_config.QdbButtons.HasFlag(QdbButtons.RevertCustomize)) ++_numButtons; diff --git a/Glamourer/Gui/Tabs/SettingsTab/SettingsTab.cs b/Glamourer/Gui/Tabs/SettingsTab/SettingsTab.cs index 746bb47..cf57824 100644 --- a/Glamourer/Gui/Tabs/SettingsTab/SettingsTab.cs +++ b/Glamourer/Gui/Tabs/SettingsTab/SettingsTab.cs @@ -251,7 +251,7 @@ public class SettingsTab( private void DrawQuickDesignBoxes() { var showAuto = config.EnableAutoDesigns; - var numColumns = 8 - (showAuto ? 0 : 2) - (config.UseTemporarySettings ? 0 : 1); + var numColumns = 9 - (showAuto ? 0 : 2) - (config.UseTemporarySettings ? 0 : 1); ImGui.NewLine(); ImUtf8.Text("Show the Following Buttons in the Quick Design Bar:"u8); ImGui.Dummy(Vector2.Zero); @@ -268,7 +268,8 @@ public class SettingsTab( ("Reapply Auto", showAuto, QdbButtons.ReapplyAutomation), ("Revert Equip", true, QdbButtons.RevertEquip), ("Revert Customize", true, QdbButtons.RevertCustomize), - ("Revert Advanced", true, QdbButtons.RevertAdvanced), + ("Revert Advanced Customization", true, QdbButtons.RevertAdvancedCustomization), + ("Revert Advanced Dyes", true, QdbButtons.RevertAdvancedDyes), ("Reset Settings", config.UseTemporarySettings, QdbButtons.ResetSettings), ]; diff --git a/Glamourer/Services/ConfigMigrationService.cs b/Glamourer/Services/ConfigMigrationService.cs index 3f997c9..ef39f1a 100644 --- a/Glamourer/Services/ConfigMigrationService.cs +++ b/Glamourer/Services/ConfigMigrationService.cs @@ -24,9 +24,20 @@ public class ConfigMigrationService(SaveService saveService, FixedDesignMigrator MigrateV4To5(); MigrateV5To6(); MigrateV6To7(); + MigrateV7To8(); AddColors(config, true); } + private void MigrateV7To8() + { + if (_config.Version > 7) + return; + + if (_config.QdbButtons.HasFlag(QdbButtons.RevertAdvancedDyes)) + _config.QdbButtons |= QdbButtons.RevertAdvancedCustomization; + _config.Version = 8; + } + private void MigrateV6To7() { if (_config.Version > 6) @@ -43,7 +54,7 @@ public class ConfigMigrationService(SaveService saveService, FixedDesignMigrator return; if (_data["ShowRevertAdvancedParametersButton"]?.ToObject() ?? true) - _config.QdbButtons |= QdbButtons.RevertAdvanced; + _config.QdbButtons |= QdbButtons.RevertAdvancedCustomization; _config.Version = 6; } diff --git a/Glamourer/State/StateApplier.cs b/Glamourer/State/StateApplier.cs index 698151f..93a3450 100644 --- a/Glamourer/State/StateApplier.cs +++ b/Glamourer/State/StateApplier.cs @@ -411,6 +411,6 @@ public class StateApplier( return actors; } - private ActorData GetData(ActorState state) + public ActorData GetData(ActorState state) => _objects.TryGetValue(state.Identifier, out var data) ? data : ActorData.Invalid; } diff --git a/Glamourer/State/StateManager.cs b/Glamourer/State/StateManager.cs index 2dda310..98b12aa 100644 --- a/Glamourer/State/StateManager.cs +++ b/Glamourer/State/StateManager.cs @@ -270,16 +270,63 @@ public sealed class StateManager( state.Materials.Clear(); - var actors = ActorData.Invalid; + var objects = ActorData.Invalid; if (source is not StateSource.Game) - actors = Applier.ApplyAll(state, redraw, true); + objects = Applier.ApplyAll(state, redraw, true); Glamourer.Log.Verbose( - $"Reset entire state of {state.Identifier.Incognito(null)} to game base. [Affecting {actors.ToLazyString("nothing")}.]"); - StateChanged.Invoke(StateChangeType.Reset, source, state, actors, null); + $"Reset entire state of {state.Identifier.Incognito(null)} to game base. [Affecting {objects.ToLazyString("nothing")}.]"); + StateChanged.Invoke(StateChangeType.Reset, source, state, objects, null); // only invoke if we define this reset call as the final call in our state update. - if(isFinal) - StateFinalized.Invoke(StateFinalizationType.Revert, actors); + if (isFinal) + StateFinalized.Invoke(StateFinalizationType.Revert, objects); + } + + public void ResetAdvancedDyes(ActorState state, StateSource source, uint key = 0) + { + if (!state.Unlock(key) || !state.ModelData.IsHuman) + return; + + state.ModelData.Parameters = state.BaseData.Parameters; + + foreach (var flag in CustomizeParameterExtensions.AllFlags) + state.Sources[flag] = StateSource.Game; + + var objects = Applier.GetData(state); + if (source is not StateSource.Game) + foreach (var (idx, mat) in state.Materials.Values) + Applier.ChangeMaterialValue(state, objects, MaterialValueIndex.FromKey(idx), mat.Game); + + state.Materials.Clear(); + + Glamourer.Log.Verbose( + $"Reset advanced dye state of {state.Identifier.Incognito(null)} to game base. [Affecting {objects.ToLazyString("nothing")}.]"); + StateChanged.Invoke(StateChangeType.Reset, source, state, objects, null); + // Update that we have completed a full operation. (We can do this directly as nothing else is linked) + StateFinalized.Invoke(StateFinalizationType.RevertAdvanced, objects); + } + + public void ResetAdvancedCustomizations(ActorState state, StateSource source, uint key = 0) + { + if (!state.Unlock(key) || !state.ModelData.IsHuman) + return; + + state.ModelData.Parameters = state.BaseData.Parameters; + + foreach (var flag in CustomizeParameterExtensions.AllFlags) + state.Sources[flag] = StateSource.Game; + + var objects = ActorData.Invalid; + if (source is not StateSource.Game) + objects = Applier.ChangeParameters(state, CustomizeParameterExtensions.All, true); + + state.Materials.Clear(); + + Glamourer.Log.Verbose( + $"Reset advanced customization and dye state of {state.Identifier.Incognito(null)} to game base. [Affecting {objects.ToLazyString("nothing")}.]"); + StateChanged.Invoke(StateChangeType.Reset, source, state, objects, null); + // Update that we have completed a full operation. (We can do this directly as nothing else is linked) + StateFinalized.Invoke(StateFinalizationType.RevertAdvanced, objects); } public void ResetAdvancedState(ActorState state, StateSource source, uint key = 0) @@ -468,7 +515,7 @@ public sealed class StateManager( || !actor.Model.IsHuman || CustomizeArray.Compare(actor.Model.GetCustomize(), state.ModelData.Customize).RequiresRedraw(), false); StateChanged.Invoke(StateChangeType.Reapply, source, state, data, null); - if(isFinal) + if (isFinal) StateFinalized.Invoke(StateFinalizationType.Reapply, data); }