Improve QDB.

This commit is contained in:
Ottermandias 2024-03-01 14:29:36 +01:00
parent 436a975a44
commit ed6f32f757
7 changed files with 299 additions and 87 deletions

View file

@ -18,35 +18,38 @@ public class Configuration : IPluginConfiguration, ISavable
[JsonIgnore] [JsonIgnore]
public readonly EphemeralConfig Ephemeral; public readonly EphemeralConfig Ephemeral;
public bool UseRestrictedGearProtection { get; set; } = false; public bool UseRestrictedGearProtection { get; set; } = false;
public bool OpenFoldersByDefault { get; set; } = false; public bool OpenFoldersByDefault { get; set; } = false;
public bool AutoRedrawEquipOnChanges { get; set; } = false; public bool AutoRedrawEquipOnChanges { get; set; } = false;
public bool EnableAutoDesigns { get; set; } = true; public bool EnableAutoDesigns { get; set; } = true;
public bool HideApplyCheckmarks { get; set; } = false; public bool HideApplyCheckmarks { get; set; } = false;
public bool SmallEquip { get; set; } = false; public bool SmallEquip { get; set; } = false;
public bool UnlockedItemMode { get; set; } = false; public bool UnlockedItemMode { get; set; } = false;
public byte DisableFestivals { get; set; } = 1; public byte DisableFestivals { get; set; } = 1;
public bool EnableGameContextMenu { get; set; } = true; public bool EnableGameContextMenu { get; set; } = true;
public bool HideWindowInCutscene { get; set; } = false; public bool HideWindowInCutscene { get; set; } = false;
public bool ShowAutomationSetEditing { get; set; } = true; public bool ShowAutomationSetEditing { get; set; } = true;
public bool ShowAllAutomatedApplicationRules { get; set; } = true; public bool ShowAllAutomatedApplicationRules { get; set; } = true;
public bool ShowUnlockedItemWarnings { get; set; } = true; public bool ShowUnlockedItemWarnings { get; set; } = true;
public bool RevertManualChangesOnZoneChange { get; set; } = false; public bool RevertManualChangesOnZoneChange { get; set; } = false;
public bool ShowQuickBarInTabs { get; set; } = true; public bool ShowQuickBarInTabs { get; set; } = true;
public bool OpenWindowAtStart { get; set; } = false; public bool OpenWindowAtStart { get; set; } = false;
public bool UseAdvancedParameters { get; set; } = true; public bool ShowWindowWhenUiHidden { get; set; } = false;
public bool UseAdvancedDyes { get; set; } = true; public bool UseAdvancedParameters { get; set; } = true;
public bool KeepAdvancedDyesAttached { get; set; } = true; public bool UseAdvancedDyes { get; set; } = true;
public bool ShowRevertAdvancedParametersButton { get; set; } = true; public bool KeepAdvancedDyesAttached { get; set; } = true;
public bool ShowPalettePlusImport { get; set; } = true; public bool ShowPalettePlusImport { get; set; } = true;
public bool UseFloatForColors { get; set; } = true; public bool UseFloatForColors { get; set; } = true;
public bool UseRgbForColors { get; set; } = true; public bool UseRgbForColors { get; set; } = true;
public bool ShowColorConfig { get; set; } = true; public bool ShowColorConfig { get; set; } = true;
public bool ChangeEntireItem { get; set; } = false; public bool ChangeEntireItem { get; set; } = false;
public bool AlwaysApplyAssociatedMods { get; set; } = false; public bool AlwaysApplyAssociatedMods { get; set; } = false;
public ModifiableHotkey ToggleQuickDesignBar { get; set; } = new(VirtualKey.NO_KEY); public ModifiableHotkey ToggleQuickDesignBar { get; set; } = new(VirtualKey.NO_KEY);
public DoubleModifier DeleteDesignModifier { get; set; } = new(ModifierHotkey.Control, ModifierHotkey.Shift); public DoubleModifier DeleteDesignModifier { get; set; } = new(ModifierHotkey.Control, ModifierHotkey.Shift);
public ChangeLogDisplayType ChangeLogDisplayType { get; set; } = ChangeLogDisplayType.New; public ChangeLogDisplayType ChangeLogDisplayType { get; set; } = ChangeLogDisplayType.New;
public QdbButtons QdbButtons { get; set; } =
QdbButtons.ApplyDesign | QdbButtons.RevertAll | QdbButtons.RevertAutomation | QdbButtons.RevertAdvanced;
[JsonConverter(typeof(SortModeConverter))] [JsonConverter(typeof(SortModeConverter))]
[JsonProperty(Order = int.MaxValue)] [JsonProperty(Order = int.MaxValue)]
@ -78,15 +81,8 @@ public class Configuration : IPluginConfiguration, ISavable
public void Save() public void Save()
=> _saveService.DelaySave(this); => _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)) if (!File.Exists(_saveService.FileNames.ConfigFile))
return; return;
@ -107,6 +103,14 @@ public class Configuration : IPluginConfiguration, ISavable
} }
migrator.Migrate(this); 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) public string ToFilename(FilenameService fileNames)
@ -114,14 +118,15 @@ public class Configuration : IPluginConfiguration, ISavable
public void Save(StreamWriter writer) public void Save(StreamWriter writer)
{ {
using var jWriter = new JsonTextWriter(writer) { Formatting = Formatting.Indented }; using var jWriter = new JsonTextWriter(writer);
var serializer = new JsonSerializer { Formatting = Formatting.Indented }; jWriter.Formatting = Formatting.Indented;
var serializer = new JsonSerializer { Formatting = Formatting.Indented };
serializer.Serialize(jWriter, this); serializer.Serialize(jWriter, this);
} }
public static class Constants public static class Constants
{ {
public const int CurrentVersion = 5; public const int CurrentVersion = 6;
public static readonly ISortMode<Design>[] ValidSortModes = public static readonly ISortMode<Design>[] ValidSortModes =
{ {

View file

@ -16,6 +16,17 @@ using Penumbra.GameData.Actors;
namespace Glamourer.Gui; 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 public sealed class DesignQuickBar : Window, IDisposable
{ {
private ImGuiWindowFlags GetFlags private ImGuiWindowFlags GetFlags
@ -55,7 +66,7 @@ public sealed class DesignQuickBar : Window, IDisposable
public override void PreOpenCheck() public override void PreOpenCheck()
{ {
CheckHotkeys(); CheckHotkeys();
IsOpen = _config.Ephemeral.ShowDesignQuickBar; IsOpen = _config.Ephemeral.ShowDesignQuickBar && _config.QdbButtons != 0;
} }
public override void PreDraw() public override void PreDraw()
@ -93,15 +104,20 @@ public sealed class DesignQuickBar : Window, IDisposable
var spacing = ImGui.GetStyle().ItemInnerSpacing; var spacing = ImGui.GetStyle().ItemInnerSpacing;
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing); using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing);
var buttonSize = new Vector2(ImGui.GetFrameHeight()); var buttonSize = new Vector2(ImGui.GetFrameHeight());
var comboSize = width - _numButtons * (buttonSize.X + spacing.X);
_designCombo.Draw(comboSize);
PrepareButtons(); PrepareButtons();
ImGui.SameLine(); if (_config.QdbButtons.HasFlag(QdbButtons.ApplyDesign))
DrawApplyButton(buttonSize); {
ImGui.SameLine(); var comboSize = width - _numButtons * (buttonSize.X + spacing.X);
_designCombo.Draw(comboSize);
ImGui.SameLine();
DrawApplyButton(buttonSize);
}
DrawRevertButton(buttonSize); DrawRevertButton(buttonSize);
DrawRevertAutomationButton(buttonSize); DrawRevertEquipButton(buttonSize);
DrawRevertCustomizeButton(buttonSize);
DrawRevertAdvancedCustomization(buttonSize); DrawRevertAdvancedCustomization(buttonSize);
DrawRevertAutomationButton(buttonSize);
} }
private ActorIdentifier _playerIdentifier; private ActorIdentifier _playerIdentifier;
@ -152,12 +168,14 @@ public sealed class DesignQuickBar : Window, IDisposable
var (clicked, id, data, state) = ResolveTarget(FontAwesomeIcon.PlayCircle, size, tooltip, available); var (clicked, id, data, state) = ResolveTarget(FontAwesomeIcon.PlayCircle, size, tooltip, available);
ImGui.SameLine();
if (!clicked) if (!clicked)
return; return;
if (state == null && !_stateManager.GetOrCreate(id, data.Objects[0], out state)) 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; return;
} }
@ -166,8 +184,11 @@ public sealed class DesignQuickBar : Window, IDisposable
_stateManager.ApplyDesign(state, design, ApplySettings.ManualWithLinks); _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 available = 0;
var tooltip = string.Empty; var tooltip = string.Empty;
if (_playerIdentifier.IsValid && _playerState is { IsLocked: false }) 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."; 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); var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.UndoAlt, buttonSize, tooltip, available);
ImGui.SameLine();
if (clicked) if (clicked)
_stateManager.ResetState(state!, StateSource.Manual); _stateManager.ResetState(state!, StateSource.Manual);
} }
public void DrawRevertAutomationButton(Vector2 buttonSize) private void DrawRevertAutomationButton(Vector2 buttonSize)
{ {
if (!_config.EnableAutoDesigns) if (!_config.EnableAutoDesigns)
return; return;
if (!_config.QdbButtons.HasFlag(QdbButtons.RevertAutomation))
return;
var available = 0; var available = 0;
var tooltip = string.Empty; var tooltip = string.Empty;
@ -217,8 +242,8 @@ public sealed class DesignQuickBar : Window, IDisposable
if (available == 0) if (available == 0)
tooltip = "Neither player character nor target are available, have state modified by Glamourer, or their state is locked."; 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); var (clicked, id, data, state) = ResolveTarget(FontAwesomeIcon.SyncAlt, buttonSize, tooltip, available);
ImGui.SameLine();
if (!clicked) if (!clicked)
return; 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; return;
var available = 0; var available = 0;
@ -254,12 +282,74 @@ public sealed class DesignQuickBar : Window, IDisposable
if (available == 0) if (available == 0)
tooltip = "Neither player character nor target are available or their state is locked."; tooltip = "Neither player character nor target are available or their state is locked.";
ImGui.SameLine();
var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.Palette, buttonSize, tooltip, available); var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.Palette, buttonSize, tooltip, available);
ImGui.SameLine();
if (clicked) if (clicked)
_stateManager.ResetAdvancedState(state!, StateSource.Manual); _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, private (bool, ActorIdentifier, ActorData, ActorState?) ResolveTarget(FontAwesomeIcon icon, Vector2 buttonSize, string tooltip,
int available) int available)
{ {
@ -292,15 +382,32 @@ public sealed class DesignQuickBar : Window, IDisposable
private float UpdateWidth() 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, ++_numButtons;
(false, true) => 3, Size = new Vector2((7 + _numButtons) * ImGui.GetFrameHeight() + _numButtons * ImGui.GetStyle().ItemInnerSpacing.X,
(true, false) => 3, ImGui.GetFrameHeight());
(false, false) => 2, }
}; else
Size = new Vector2((7 + _numButtons) * ImGui.GetFrameHeight() + _numButtons * ImGui.GetStyle().ItemInnerSpacing.X, {
ImGui.GetFrameHeight()); Size = new Vector2(
_numButtons * ImGui.GetFrameHeight()
+ (_numButtons - 1) * ImGui.GetStyle().ItemInnerSpacing.X
+ ImGui.GetStyle().WindowPadding.X * 2,
ImGui.GetFrameHeight());
}
return Size.Value.X; return Size.Value.X;
} }
} }

View file

@ -25,6 +25,7 @@ public class GlamourerWindowSystem : IDisposable
_uiBuilder.Draw += _windowSystem.Draw; _uiBuilder.Draw += _windowSystem.Draw;
_uiBuilder.OpenConfigUi += _ui.Toggle; _uiBuilder.OpenConfigUi += _ui.Toggle;
_uiBuilder.DisableCutsceneUiHide = !config.HideWindowInCutscene; _uiBuilder.DisableCutsceneUiHide = !config.HideWindowInCutscene;
_uiBuilder.DisableUserUiHide = config.ShowWindowWhenUiHidden;
} }
public void Dispose() public void Dispose()

View file

@ -159,10 +159,6 @@ public class MainWindow : Window, IDisposable
{ {
var width = ImGui.CalcTextSize("Join Discord for Support").X + ImGui.GetStyle().FramePadding.X * 2; var width = ImGui.CalcTextSize("Join Discord for Support").X + ImGui.GetStyle().FramePadding.X * 2;
var xPos = ImGui.GetWindowWidth() - width; 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)); ImGui.SetCursorPos(new Vector2(xPos, 0));
CustomGui.DrawDiscordButton(Glamourer.Messager, width); CustomGui.DrawDiscordButton(Glamourer.Messager, width);

View file

@ -120,6 +120,7 @@ public class SettingsTab(
Checkbox("Show Quick Design Bar in Main Window", Checkbox("Show Quick Design Bar in Main Window",
"Show the quick design bar in the tab selection part of the main window, too.", "Show the quick design bar in the tab selection part of the main window, too.",
config.ShowQuickBarInTabs, v => config.ShowQuickBarInTabs = v); config.ShowQuickBarInTabs, v => config.ShowQuickBarInTabs = v);
DrawQuickDesignBoxes();
ImGui.Dummy(Vector2.Zero); ImGui.Dummy(Vector2.Zero);
ImGui.Separator(); ImGui.Separator();
@ -134,6 +135,12 @@ public class SettingsTab(
else else
contextMenuService.Disable(); 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.", Checkbox("Hide Window in Cutscenes", "Whether the main Glamourer window should automatically be hidden when entering cutscenes or not.",
config.HideWindowInCutscene, config.HideWindowInCutscene,
v => v =>
@ -176,9 +183,9 @@ public class SettingsTab(
config.ShowUnlockedItemWarnings, v => config.ShowUnlockedItemWarnings = v); config.ShowUnlockedItemWarnings, v => config.ShowUnlockedItemWarnings = v);
if (config.UseAdvancedParameters) if (config.UseAdvancedParameters)
{ {
Checkbox("Show Revert Advanced Customizations Button in Quick Design Bar", //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.", // "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); // config.ShowRevertAdvancedParametersButton, v => config.ShowRevertAdvancedParametersButton = v);
Checkbox("Show Color Display Config", "Show the Color Display configuration options in the Advanced Customization panels.", Checkbox("Show Color Display Config", "Show the Color Display configuration options in the Advanced Customization panels.",
config.ShowColorConfig, v => config.ShowColorConfig = v); config.ShowColorConfig, v => config.ShowColorConfig = v);
Checkbox("Show Palette+ Import Button", Checkbox("Show Palette+ Import Button",
@ -198,6 +205,52 @@ public class SettingsTab(
ImGui.NewLine(); 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() private void PaletteImportButton()
{ {

View file

@ -4,38 +4,38 @@ using Newtonsoft.Json.Linq;
namespace Glamourer.Services; 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 Configuration _config = null!;
private JObject _data = null!; private JObject _data = null!;
public ConfigMigrationService(SaveService saveService, FixedDesignMigrator fixedDesignMigrator, BackupService backupService)
{
_saveService = saveService;
_fixedDesignMigrator = fixedDesignMigrator;
_backupService = backupService;
}
public void Migrate(Configuration config) public void Migrate(Configuration config)
{ {
_config = 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); AddColors(config, false);
return; return;
} }
_data = JObject.Parse(File.ReadAllText(_saveService.FileNames.ConfigFile)); _data = JObject.Parse(File.ReadAllText(saveService.FileNames.ConfigFile));
MigrateV1To2(); MigrateV1To2();
MigrateV2To4(); MigrateV2To4();
MigrateV4To5(); MigrateV4To5();
MigrateV5To6();
AddColors(config, true); AddColors(config, true);
} }
private void MigrateV5To6()
{
if (_config.Version > 5)
return;
if (_data["ShowRevertAdvancedParametersButton"]?.ToObject<bool>() ?? true)
_config.QdbButtons |= QdbButtons.RevertAdvanced;
_config.Version = 6;
}
// Ephemeral Config. // Ephemeral Config.
private void MigrateV4To5() private void MigrateV4To5()
{ {
@ -59,8 +59,8 @@ public class ConfigMigrationService
if (_config.Version > 1) if (_config.Version > 1)
return; return;
_backupService.CreateMigrationBackup("pre_v1_to_v2_migration"); backupService.CreateMigrationBackup("pre_v1_to_v2_migration");
_fixedDesignMigrator.Migrate(_data["FixedDesigns"]); fixedDesignMigrator.Migrate(_data["FixedDesigns"]);
_config.Version = 2; _config.Version = 2;
var customizationColor = _data["CustomizationColor"]?.ToObject<uint>() ?? ColorId.CustomizationDesign.Data().DefaultColor; var customizationColor = _data["CustomizationColor"]?.ToObject<uint>() ?? ColorId.CustomizationDesign.Data().DefaultColor;
_config.Colors[ColorId.CustomizationDesign] = customizationColor; _config.Colors[ColorId.CustomizationDesign] = customizationColor;

View file

@ -29,7 +29,8 @@ public sealed class StateManager(
DesignMerger merger, DesignMerger merger,
ModSettingApplier modApplier, ModSettingApplier modApplier,
GPoseService gPose) GPoseService gPose)
: StateEditor(editor, applier, @event, jobChange, config, items, merger, modApplier, gPose), IReadOnlyDictionary<ActorIdentifier, ActorState> : StateEditor(editor, applier, @event, jobChange, config, items, merger, modApplier, gPose),
IReadOnlyDictionary<ActorIdentifier, ActorState>
{ {
private readonly Dictionary<ActorIdentifier, ActorState> _states = []; private readonly Dictionary<ActorIdentifier, ActorState> _states = [];
@ -225,7 +226,7 @@ public sealed class StateManager(
|| !state.ModelData.IsHuman || !state.ModelData.IsHuman
|| CustomizeArray.Compare(state.ModelData.Customize, state.BaseData.Customize).RequiresRedraw(); || CustomizeArray.Compare(state.ModelData.Customize, state.BaseData.Customize).RequiresRedraw();
state.ModelData = state.BaseData; state.ModelData = state.BaseData;
state.ModelData.SetIsWet(false); state.ModelData.SetIsWet(false);
foreach (var index in Enum.GetValues<CustomizeIndex>()) foreach (var index in Enum.GetValues<CustomizeIndex>())
state.Sources[index] = StateSource.Game; state.Sources[index] = StateSource.Game;
@ -281,6 +282,55 @@ public sealed class StateManager(
StateChanged.Invoke(StateChanged.Type.Reset, source, state, actors, null); 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) public void ResetStateFixed(ActorState state, bool respectManualPalettes, uint key = 0)
{ {
if (!state.Unlock(key)) if (!state.Unlock(key))