From 1ad70541d3c7c7dd11f71ffcf5b10fb73ab99bba Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Tue, 23 Jan 2024 18:02:53 +0100 Subject: [PATCH] Reworked all of the meta, made StateIndex its own thing. --- Glamourer/Api/GlamourerIpc.Apply.cs | 3 +- Glamourer/Api/GlamourerIpc.Events.cs | 2 +- Glamourer/Api/GlamourerIpc.Revert.cs | 3 +- Glamourer/Api/GlamourerIpc.Set.cs | 5 +- Glamourer/Automation/ApplicationType.cs | 20 +- Glamourer/Automation/AutoDesign.cs | 3 +- Glamourer/Automation/AutoDesignApplier.cs | 89 +++---- Glamourer/Designs/DesignBase64Migration.cs | 9 +- Glamourer/Designs/DesignConverter.cs | 18 +- Glamourer/Designs/DesignManager.cs | 20 +- Glamourer/Designs/Links/DesignMerger.cs | 86 +++---- Glamourer/Designs/Links/MergedDesign.cs | 36 +-- Glamourer/Designs/MetaIndex.cs | 36 ++- Glamourer/Events/StateChanged.cs | 91 +++---- .../CustomizeParameterDrawData.cs | 2 +- Glamourer/Gui/DesignQuickBar.cs | 6 +- Glamourer/Gui/Equipment/EquipDrawData.cs | 4 +- Glamourer/Gui/PenumbraChangedItemTooltip.cs | 12 +- Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs | 18 +- Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs | 2 +- .../Gui/Tabs/DebugTab/ActiveStatePanel.cs | 24 +- .../Gui/Tabs/DebugTab/DesignManagerPanel.cs | 27 +- .../Gui/Tabs/DebugTab/DesignTesterPanel.cs | 6 +- .../Gui/Tabs/DebugTab/NpcAppearancePanel.cs | 6 +- Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs | 41 ++- Glamourer/Gui/Tabs/NpcTab/NpcPanel.cs | 4 +- Glamourer/Gui/ToggleDrawData.cs | 69 ++--- Glamourer/Interop/ContextMenuService.cs | 12 +- Glamourer/Services/CommandService.cs | 6 +- Glamourer/State/ActorState.cs | 4 +- Glamourer/State/StateApplier.cs | 92 +++---- Glamourer/State/StateEditor.cs | 73 +++--- Glamourer/State/StateIndex.cs | 235 ++++++++++++++++++ Glamourer/State/StateListener.cs | 72 +++--- Glamourer/State/StateManager.cs | 176 ++++++------- Glamourer/State/StateSource.cs | 92 ++++--- 36 files changed, 747 insertions(+), 657 deletions(-) create mode 100644 Glamourer/State/StateIndex.cs diff --git a/Glamourer/Api/GlamourerIpc.Apply.cs b/Glamourer/Api/GlamourerIpc.Apply.cs index 47c655e..08ccff4 100644 --- a/Glamourer/Api/GlamourerIpc.Apply.cs +++ b/Glamourer/Api/GlamourerIpc.Apply.cs @@ -3,6 +3,7 @@ using Dalamud.Plugin; using Glamourer.Designs; using Glamourer.Events; using Glamourer.Interop.Structs; +using Glamourer.State; using Penumbra.Api.Helpers; using Penumbra.GameData.Actors; @@ -130,7 +131,7 @@ public partial class GlamourerIpc if ((hasModelId || state.ModelData.ModelId == 0) && state.CanUnlock(lockCode)) { - _stateManager.ApplyDesign(design, state, StateChanged.Source.Ipc, lockCode); + _stateManager.ApplyDesign(design, state, StateSource.Ipc, lockCode); state.Lock(lockCode); } } diff --git a/Glamourer/Api/GlamourerIpc.Events.cs b/Glamourer/Api/GlamourerIpc.Events.cs index 44f0775..8caa495 100644 --- a/Glamourer/Api/GlamourerIpc.Events.cs +++ b/Glamourer/Api/GlamourerIpc.Events.cs @@ -15,7 +15,7 @@ public partial class GlamourerIpc private readonly EventProvider> _stateChangedProvider; private readonly EventProvider _gPoseChangedProvider; - private void OnStateChanged(StateChanged.Type type, StateChanged.Source source, ActorState state, ActorData actors, object? data = null) + private void OnStateChanged(StateChanged.Type type, StateSource source, ActorState state, ActorData actors, object? data = null) { foreach (var actor in actors.Objects) _stateChangedProvider.Invoke(type, actor.Address, new Lazy(() => _designConverter.ShareBase64(state))); diff --git a/Glamourer/Api/GlamourerIpc.Revert.cs b/Glamourer/Api/GlamourerIpc.Revert.cs index 8bf47cc..44a03aa 100644 --- a/Glamourer/Api/GlamourerIpc.Revert.cs +++ b/Glamourer/Api/GlamourerIpc.Revert.cs @@ -1,6 +1,7 @@ using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Plugin; using Glamourer.Events; +using Glamourer.State; using Penumbra.Api.Helpers; using Penumbra.GameData.Actors; @@ -82,7 +83,7 @@ public partial class GlamourerIpc foreach (var id in actors) { if (_stateManager.TryGetValue(id, out var state)) - _stateManager.ResetState(state, StateChanged.Source.Ipc, lockCode); + _stateManager.ResetState(state, StateSource.Ipc, lockCode); } } diff --git a/Glamourer/Api/GlamourerIpc.Set.cs b/Glamourer/Api/GlamourerIpc.Set.cs index 1a39bea..983fd71 100644 --- a/Glamourer/Api/GlamourerIpc.Set.cs +++ b/Glamourer/Api/GlamourerIpc.Set.cs @@ -2,6 +2,7 @@ using Dalamud.Plugin; using Glamourer.Events; using Glamourer.Services; +using Glamourer.State; using Penumbra.Api.Helpers; using Penumbra.GameData.Enums; using Penumbra.GameData.Structs; @@ -55,7 +56,7 @@ public partial class GlamourerIpc if (!state.ModelData.IsHuman) return GlamourerErrorCode.ActorNotHuman; - _stateManager.ChangeEquip(state, slot, item, stainId, StateChanged.Source.Ipc, key); + _stateManager.ChangeEquip(state, slot, item, stainId, StateSource.Ipc, key); return GlamourerErrorCode.Success; } @@ -82,7 +83,7 @@ public partial class GlamourerIpc if (!state.ModelData.IsHuman) return GlamourerErrorCode.ActorNotHuman; - _stateManager.ChangeEquip(state, slot, item, stainId, StateChanged.Source.Ipc, key); + _stateManager.ChangeEquip(state, slot, item, stainId, StateSource.Ipc, key); found = true; } diff --git a/Glamourer/Automation/ApplicationType.cs b/Glamourer/Automation/ApplicationType.cs index e4866de..e99d948 100644 --- a/Glamourer/Automation/ApplicationType.cs +++ b/Glamourer/Automation/ApplicationType.cs @@ -18,9 +18,8 @@ public enum ApplicationType : byte public static class ApplicationTypeExtensions { - public static (EquipFlag Equip, CustomizeFlag Customize, CrestFlag Crest, CustomizeParameterFlag Parameters, bool ApplyHat, bool ApplyVisor, - bool - ApplyWeapon, bool ApplyWet) ApplyWhat(this ApplicationType type, DesignBase? design) + public static (EquipFlag Equip, CustomizeFlag Customize, CrestFlag Crest, CustomizeParameterFlag Parameters, MetaFlag Meta) ApplyWhat( + this ApplicationType type, DesignBase? design) { var equipFlags = (type.HasFlag(ApplicationType.Weapons) ? WeaponFlags : 0) | (type.HasFlag(ApplicationType.Armor) ? ArmorFlags : 0) @@ -29,18 +28,15 @@ public static class ApplicationTypeExtensions var customizeFlags = type.HasFlag(ApplicationType.Customizations) ? CustomizeFlagExtensions.All : 0; var parameterFlags = type.HasFlag(ApplicationType.Customizations) ? CustomizeParameterExtensions.All : 0; var crestFlag = type.HasFlag(ApplicationType.GearCustomization) ? CrestExtensions.AllRelevant : 0; + var metaFlag = (type.HasFlag(ApplicationType.Armor) ? MetaFlag.HatState | MetaFlag.VisorState : 0) + | (type.HasFlag(ApplicationType.Weapons) ? MetaFlag.WeaponState : 0) + | (type.HasFlag(ApplicationType.Customizations) ? MetaFlag.Wetness : 0); if (design == null) - return (equipFlags, customizeFlags, crestFlag, parameterFlags, type.HasFlag(ApplicationType.Armor), - type.HasFlag(ApplicationType.Armor), - type.HasFlag(ApplicationType.Weapons), type.HasFlag(ApplicationType.Customizations)); + return (equipFlags, customizeFlags, crestFlag, parameterFlags, metaFlag); return (equipFlags & design!.ApplyEquip, customizeFlags & design.ApplyCustomize, crestFlag & design.ApplyCrest, - parameterFlags & design.ApplyParameters, - type.HasFlag(ApplicationType.Armor) && design.DoApplyHatVisible(), - type.HasFlag(ApplicationType.Armor) && design.DoApplyVisorToggle(), - type.HasFlag(ApplicationType.Weapons) && design.DoApplyWeaponVisible(), - type.HasFlag(ApplicationType.Customizations) && design.DoApplyWetness()); + parameterFlags & design.ApplyParameters, metaFlag & design.ApplyMeta); } public const EquipFlag WeaponFlags = EquipFlag.Mainhand | EquipFlag.Offhand; @@ -59,4 +55,4 @@ public static class ApplicationTypeExtensions | EquipFlag.WristStain | EquipFlag.RFingerStain | EquipFlag.LFingerStain; -} \ No newline at end of file +} diff --git a/Glamourer/Automation/AutoDesign.cs b/Glamourer/Automation/AutoDesign.cs index 9d709ab..50704f4 100644 --- a/Glamourer/Automation/AutoDesign.cs +++ b/Glamourer/Automation/AutoDesign.cs @@ -68,7 +68,6 @@ public class AutoDesign return ret; } - public (EquipFlag Equip, CustomizeFlag Customize, CrestFlag Crest, CustomizeParameterFlag Parameters, bool ApplyHat, bool ApplyVisor, bool - ApplyWeapon, bool ApplyWet) ApplyWhat() + public (EquipFlag Equip, CustomizeFlag Customize, CrestFlag Crest, CustomizeParameterFlag Parameters, MetaFlag Meta) ApplyWhat() => Type.ApplyWhat(Design); } diff --git a/Glamourer/Automation/AutoDesignApplier.cs b/Glamourer/Automation/AutoDesignApplier.cs index 54664f1..db4058f 100644 --- a/Glamourer/Automation/AutoDesignApplier.cs +++ b/Glamourer/Automation/AutoDesignApplier.cs @@ -35,7 +35,7 @@ public sealed class AutoDesignApplier : IDisposable private readonly IClientState _clientState; private ActorState? _jobChangeState; - private readonly Dictionary _jobChange = []; + private readonly Dictionary _jobChange = []; private void ResetJobChange() { @@ -183,7 +183,7 @@ public sealed class AutoDesignApplier : IDisposable } else if (_state.TryGetValue(id, out var state)) { - state.Source.RemoveFixedDesignSources(); + state.Sources.RemoveFixedDesignSources(); } } } @@ -197,9 +197,9 @@ public sealed class AutoDesignApplier : IDisposable { if (id.Type is IdentifierType.Player && id.HomeWorld == WorldId.AnyWorld) foreach (var state in _state.Where(kvp => kvp.Key.PlayerName == id.PlayerName).Select(kvp => kvp.Value)) - state.Source.RemoveFixedDesignSources(); + state.Sources.RemoveFixedDesignSources(); else if (_state.TryGetValue(id, out var state)) - state.Source.RemoveFixedDesignSources(); + state.Sources.RemoveFixedDesignSources(); } } } @@ -256,13 +256,13 @@ public sealed class AutoDesignApplier : IDisposable else if (!GetPlayerSet(identifier, out set!)) { if (state.UpdateTerritory(_clientState.TerritoryType) && _config.RevertManualChangesOnZoneChange) - _state.ResetState(state, StateChanged.Source.Game); + _state.ResetState(state, StateSource.Game); return true; } var respectManual = !state.UpdateTerritory(_clientState.TerritoryType) || !_config.RevertManualChangesOnZoneChange; if (!respectManual) - _state.ResetState(state, StateChanged.Source.Game); + _state.ResetState(state, StateSource.Game); Reduce(actor, state, set, respectManual, false); return true; } @@ -272,13 +272,13 @@ public sealed class AutoDesignApplier : IDisposable if (set.BaseState == AutoDesignSet.Base.Game) _state.ResetStateFixed(state, respectManual); else if (!respectManual) - state.Source.RemoveFixedDesignSources(); + state.Sources.RemoveFixedDesignSources(); if (!_humans.IsHuman((uint)actor.AsCharacter->CharacterData.ModelCharaId)) return; - var mergedDesign = _designMerger.Merge(set.Designs.Where(d => d.IsActive(actor)).Select(d => ((DesignBase?) d.Design, d.Type)), state.ModelData, true); - ApplyToState(state, mergedDesign, respectManual, fromJobChange, StateChanged.Source.Fixed); + var mergedDesign = _designMerger.Merge(set.Designs.Where(d => d.IsActive(actor)).Select(d => ((DesignBase?) d.Design, d.Type)), state.ModelData, true, false); + ApplyToState(state, mergedDesign, respectManual, fromJobChange, StateSource.Fixed); } /// Get world-specific first and all-world afterward. @@ -304,27 +304,27 @@ public sealed class AutoDesignApplier : IDisposable } } - private void ApplyToState(ActorState state, MergedDesign mergedDesign, bool respectManual, bool fromJobChange, StateChanged.Source source) + private void ApplyToState(ActorState state, MergedDesign mergedDesign, bool respectManual, bool fromJobChange, StateSource source) { foreach (var slot in CrestExtensions.AllRelevantSet.Where(mergedDesign.Design.DoApplyCrest)) - if (!respectManual || state.Source[slot] is not StateChanged.Source.Manual) + if (!respectManual || state.Sources[slot] is not StateSource.Manual) _state.ChangeCrest(state, slot, mergedDesign.Design.DesignData.Crest(slot), mergedDesign.GetSource(slot, source)); foreach (var parameter in mergedDesign.Design.ApplyParameters.Iterate()) - if (!respectManual || state.Source[parameter] is not StateChanged.Source.Manual and not StateChanged.Source.Pending) + if (!respectManual || state.Sources[parameter] is not StateSource.Manual and not StateSource.Pending) _state.ChangeCustomizeParameter(state, parameter, mergedDesign.Design.DesignData.Parameters[parameter], mergedDesign.GetSource(parameter, source)); foreach (var slot in EquipSlotExtensions.EqdpSlots) { if (mergedDesign.Design.DoApplyEquip(slot)) { - if (!respectManual || state.Source[slot, false] is not StateChanged.Source.Manual) + if (!respectManual || state.Sources[slot, false] is not StateSource.Manual) _state.ChangeItem(state, slot, mergedDesign.Design.DesignData.Item(slot), mergedDesign.GetSource(slot, false, source)); } if (mergedDesign.Design.DoApplyStain(slot)) { - if (!respectManual || state.Source[slot, true] is not StateChanged.Source.Manual) + if (!respectManual || state.Sources[slot, true] is not StateSource.Manual) _state.ChangeStain(state, slot, mergedDesign.Design.DesignData.Stain(slot), mergedDesign.GetSource(slot, true, source)); } } @@ -333,14 +333,14 @@ public sealed class AutoDesignApplier : IDisposable { if (mergedDesign.Design.DoApplyStain(weaponSlot)) { - if (!respectManual || state.Source[weaponSlot, true] is not StateChanged.Source.Manual) + if (!respectManual || state.Sources[weaponSlot, true] is not StateSource.Manual) _state.ChangeStain(state, weaponSlot, mergedDesign.Design.DesignData.Stain(weaponSlot), mergedDesign.GetSource(weaponSlot, true, source)); } if (!mergedDesign.Design.DoApplyEquip(weaponSlot)) continue; - if (respectManual && state.Source[weaponSlot, false] is StateChanged.Source.Manual) + if (respectManual && state.Sources[weaponSlot, false] is StateSource.Manual) continue; var currentType = state.ModelData.Item(weaponSlot).Type; @@ -359,7 +359,7 @@ public sealed class AutoDesignApplier : IDisposable } private void ReduceEquip(ActorState state, in DesignData design, EquipFlag equipFlags, ref EquipFlag totalEquipFlags, bool respectManual, - StateChanged.Source source, bool fromJobChange) + StateSource source, bool fromJobChange) { equipFlags &= ~totalEquipFlags; if (equipFlags == 0) @@ -373,7 +373,7 @@ public sealed class AutoDesignApplier : IDisposable var item = design.Item(slot); if (!_config.UnlockedItemMode || _itemUnlocks.IsUnlocked(item.Id, out _)) { - if (!respectManual || state.Source[slot, false] is not StateChanged.Source.Manual) + if (!respectManual || state.Sources[slot, false] is not StateSource.Manual) _state.ChangeItem(state, slot, item, source); totalEquipFlags |= flag; } @@ -382,7 +382,7 @@ public sealed class AutoDesignApplier : IDisposable var stainFlag = slot.ToStainFlag(); if (equipFlags.HasFlag(stainFlag)) { - if (!respectManual || state.Source[slot, true] is not StateChanged.Source.Manual) + if (!respectManual || state.Sources[slot, true] is not StateSource.Manual) _state.ChangeStain(state, slot, design.Stain(slot), source); totalEquipFlags |= stainFlag; } @@ -392,7 +392,7 @@ public sealed class AutoDesignApplier : IDisposable { var item = design.Item(EquipSlot.MainHand); var checkUnlock = !_config.UnlockedItemMode || _itemUnlocks.IsUnlocked(item.Id, out _); - var checkState = !respectManual || state.Source[EquipSlot.MainHand, false] is not StateChanged.Source.Manual; + var checkState = !respectManual || state.Sources[EquipSlot.MainHand, false] is not StateSource.Manual; if (checkUnlock && checkState) { if (fromJobChange) @@ -412,7 +412,7 @@ public sealed class AutoDesignApplier : IDisposable { var item = design.Item(EquipSlot.OffHand); var checkUnlock = !_config.UnlockedItemMode || _itemUnlocks.IsUnlocked(item.Id, out _); - var checkState = !respectManual || state.Source[EquipSlot.OffHand, false] is not StateChanged.Source.Manual; + var checkState = !respectManual || state.Sources[EquipSlot.OffHand, false] is not StateSource.Manual; if (checkUnlock && checkState) { if (fromJobChange) @@ -430,21 +430,21 @@ public sealed class AutoDesignApplier : IDisposable if (equipFlags.HasFlag(EquipFlag.MainhandStain)) { - if (!respectManual || state.Source[EquipSlot.MainHand, true] is not StateChanged.Source.Manual) + if (!respectManual || state.Sources[EquipSlot.MainHand, true] is not StateSource.Manual) _state.ChangeStain(state, EquipSlot.MainHand, design.Stain(EquipSlot.MainHand), source); totalEquipFlags |= EquipFlag.MainhandStain; } if (equipFlags.HasFlag(EquipFlag.OffhandStain)) { - if (!respectManual || state.Source[EquipSlot.OffHand, true] is not StateChanged.Source.Manual) + if (!respectManual || state.Sources[EquipSlot.OffHand, true] is not StateSource.Manual) _state.ChangeStain(state, EquipSlot.OffHand, design.Stain(EquipSlot.OffHand), source); totalEquipFlags |= EquipFlag.OffhandStain; } } private void ReduceCustomize(ActorState state, in DesignData design, CustomizeFlag customizeFlags, ref CustomizeFlag totalCustomizeFlags, - bool respectManual, StateChanged.Source source) + bool respectManual, StateSource source) { customizeFlags &= ~totalCustomizeFlags; if (customizeFlags == 0) @@ -459,7 +459,7 @@ public sealed class AutoDesignApplier : IDisposable if (customizeFlags.HasFlag(CustomizeFlag.Clan)) { - if (!respectManual || state.Source[CustomizeIndex.Clan] is not StateChanged.Source.Manual) + if (!respectManual || state.Sources[CustomizeIndex.Clan] is not StateSource.Manual) fixFlags |= _customizations.ChangeClan(ref customize, design.Customize.Clan); customizeFlags &= ~(CustomizeFlag.Clan | CustomizeFlag.Race); totalCustomizeFlags |= CustomizeFlag.Clan | CustomizeFlag.Race; @@ -467,7 +467,7 @@ public sealed class AutoDesignApplier : IDisposable if (customizeFlags.HasFlag(CustomizeFlag.Gender)) { - if (!respectManual || state.Source[CustomizeIndex.Gender] is not StateChanged.Source.Manual) + if (!respectManual || state.Sources[CustomizeIndex.Gender] is not StateSource.Manual) fixFlags |= _customizations.ChangeGender(ref customize, design.Customize.Gender); customizeFlags &= ~CustomizeFlag.Gender; totalCustomizeFlags |= CustomizeFlag.Gender; @@ -478,7 +478,7 @@ public sealed class AutoDesignApplier : IDisposable if (customizeFlags.HasFlag(CustomizeFlag.Face)) { - if (!respectManual || state.Source[CustomizeIndex.Face] is not StateChanged.Source.Manual) + if (!respectManual || state.Sources[CustomizeIndex.Face] is not StateSource.Manual) _state.ChangeCustomize(state, CustomizeIndex.Face, design.Customize.Face, source); customizeFlags &= ~CustomizeFlag.Face; totalCustomizeFlags |= CustomizeFlag.Face; @@ -498,42 +498,21 @@ public sealed class AutoDesignApplier : IDisposable if (data.HasValue && _config.UnlockedItemMode && !_customizeUnlocks.IsUnlocked(data.Value, out _)) continue; - if (!respectManual || state.Source[index] is not StateChanged.Source.Manual) + if (!respectManual || state.Sources[index] is not StateSource.Manual) _state.ChangeCustomize(state, index, value, source); totalCustomizeFlags |= flag; } } } - private void ReduceMeta(ActorState state, in DesignData design, bool applyHat, bool applyVisor, bool applyWeapon, bool applyWet, - ref byte totalMetaFlags, bool respectManual, StateChanged.Source source) + private void ReduceMeta(ActorState state, in DesignData design, MetaFlag apply, ref MetaFlag totalMetaFlags, bool respectManual, StateSource source) { - if (applyHat && (totalMetaFlags & 0x01) == 0) + apply &= ~totalMetaFlags; + foreach (var index in MetaExtensions.AllRelevant) { - if (!respectManual || state.Source[MetaIndex.HatState] is not StateChanged.Source.Manual) - _state.ChangeHatState(state, design.IsHatVisible(), source); - totalMetaFlags |= 0x01; - } - - if (applyVisor && (totalMetaFlags & 0x02) == 0) - { - if (!respectManual || state.Source[MetaIndex.VisorState] is not StateChanged.Source.Manual) - _state.ChangeVisorState(state, design.IsVisorToggled(), source); - totalMetaFlags |= 0x02; - } - - if (applyWeapon && (totalMetaFlags & 0x04) == 0) - { - if (!respectManual || state.Source[MetaIndex.WeaponState] is not StateChanged.Source.Manual) - _state.ChangeWeaponState(state, design.IsWeaponVisible(), source); - totalMetaFlags |= 0x04; - } - - if (applyWet && (totalMetaFlags & 0x08) == 0) - { - if (!respectManual || state.Source[MetaIndex.Wetness] is not StateChanged.Source.Manual) - _state.ChangeWetness(state, design.IsWet(), source); - totalMetaFlags |= 0x08; + if (!respectManual || state.Sources[index] is not StateSource.Manual) + _state.ChangeMeta(state, index, design.GetMeta(index), source); + totalMetaFlags |= index.ToFlag(); } } diff --git a/Glamourer/Designs/DesignBase64Migration.cs b/Glamourer/Designs/DesignBase64Migration.cs index ec4beb1..a8b2f7b 100644 --- a/Glamourer/Designs/DesignBase64Migration.cs +++ b/Glamourer/Designs/DesignBase64Migration.cs @@ -163,16 +163,15 @@ public class DesignBase64Migration } } - public static unsafe string CreateOldBase64(in DesignData save, EquipFlag equipFlags, CustomizeFlag customizeFlags, - bool setHat, bool setVisor, bool setWeapon, bool writeProtected, float alpha = 1.0f) + public static unsafe string CreateOldBase64(in DesignData save, EquipFlag equipFlags, CustomizeFlag customizeFlags, MetaFlag meta, bool writeProtected, float alpha = 1.0f) { var data = stackalloc byte[Base64SizeV4]; data[0] = 5; data[1] = (byte)((customizeFlags == CustomizeFlagExtensions.All ? 0x01 : 0) | (save.IsWet() ? 0x02 : 0) - | (setHat ? 0x04 : 0) - | (setWeapon ? 0x08 : 0) - | (setVisor ? 0x10 : 0) + | (meta.HasFlag(MetaFlag.HatState) ? 0x04 : 0) + | (meta.HasFlag(MetaFlag.WeaponState) ? 0x08 : 0) + | (meta.HasFlag(MetaFlag.VisorState) ? 0x10 : 0) | (writeProtected ? 0x20 : 0)); data[2] = (byte)((equipFlags.HasFlag(EquipFlag.Mainhand) ? 0x01 : 0) | (equipFlags.HasFlag(EquipFlag.Offhand) ? 0x02 : 0) diff --git a/Glamourer/Designs/DesignConverter.cs b/Glamourer/Designs/DesignConverter.cs index 596fbc3..14c85f6 100644 --- a/Glamourer/Designs/DesignConverter.cs +++ b/Glamourer/Designs/DesignConverter.cs @@ -55,10 +55,10 @@ public class DesignConverter(ItemManager _items, DesignManager _designs, Customi design.ApplyCustomize = customizeFlags & CustomizeFlagExtensions.AllRelevant; design.ApplyCrest = crestFlags & CrestExtensions.All; design.ApplyParameters = parameterFlags & CustomizeParameterExtensions.All; - design.SetApplyHatVisible(design.DoApplyEquip(EquipSlot.Head)); - design.SetApplyVisorToggle(design.DoApplyEquip(EquipSlot.Head)); - design.SetApplyWeaponVisible(design.DoApplyEquip(EquipSlot.MainHand) || design.DoApplyEquip(EquipSlot.OffHand)); - design.SetApplyWetness(true); + design.SetApplyMeta(MetaIndex.HatState, design.DoApplyEquip(EquipSlot.Head)); + design.SetApplyMeta(MetaIndex.VisorState, design.DoApplyEquip(EquipSlot.Head)); + design.SetApplyMeta(MetaIndex.WeaponState, design.DoApplyEquip(EquipSlot.MainHand) || design.DoApplyEquip(EquipSlot.OffHand)); + design.SetApplyMeta(MetaIndex.Wetness, true); design.SetDesignData(_customize, data); return design; } @@ -126,16 +126,14 @@ public class DesignConverter(ItemManager _items, DesignManager _designs, Customi return null; } - ret.SetApplyWetness(customize); + ret.SetApplyMeta(MetaIndex.Wetness, customize); ret.ApplyCustomize = customize ? CustomizeFlagExtensions.AllRelevant : 0; if (!equip) { - ret.ApplyEquip = 0; - ret.ApplyCrest = 0; - ret.SetApplyHatVisible(false); - ret.SetApplyWeaponVisible(false); - ret.SetApplyVisorToggle(false); + ret.ApplyEquip = 0; + ret.ApplyCrest = 0; + ret.ApplyMeta &= ~(MetaFlag.HatState | MetaFlag.WeaponState | MetaFlag.VisorState); } return ret; diff --git a/Glamourer/Designs/DesignManager.cs b/Glamourer/Designs/DesignManager.cs index 2df7d8d..ee4bd13 100644 --- a/Glamourer/Designs/DesignManager.cs +++ b/Glamourer/Designs/DesignManager.cs @@ -523,15 +523,7 @@ public class DesignManager /// Change the application value of one of the meta flags. public void ChangeApplyMeta(Design design, MetaIndex metaIndex, bool value) { - var change = metaIndex switch - { - MetaIndex.Wetness => design.SetApplyWetness(value), - MetaIndex.HatState => design.SetApplyHatVisible(value), - MetaIndex.VisorState => design.SetApplyVisorToggle(value), - MetaIndex.WeaponState => design.SetApplyWeaponVisible(value), - _ => throw new ArgumentOutOfRangeException(nameof(metaIndex), metaIndex, null), - }; - if (!change) + if (!design.SetApplyMeta(metaIndex, value)) return; design.LastEdit = DateTimeOffset.UtcNow; @@ -556,14 +548,8 @@ public class DesignManager public void ApplyDesign(Design design, DesignBase other) { _undoStore[design.Identifier] = design.DesignData; - if (other.DoApplyWetness()) - design.GetDesignDataRef().SetIsWet(other.DesignData.IsWet()); - if (other.DoApplyHatVisible()) - design.GetDesignDataRef().SetHatVisible(other.DesignData.IsHatVisible()); - if (other.DoApplyVisorToggle()) - design.GetDesignDataRef().SetVisor(other.DesignData.IsVisorToggled()); - if (other.DoApplyWeaponVisible()) - design.GetDesignDataRef().SetWeaponVisible(other.DesignData.IsWeaponVisible()); + foreach (var index in MetaExtensions.AllRelevant.Where(other.DoApplyMeta)) + design.GetDesignDataRef().SetMeta(index, other.DesignData.GetMeta(index)); if (design.DesignData.IsHuman) { diff --git a/Glamourer/Designs/Links/DesignMerger.cs b/Glamourer/Designs/Links/DesignMerger.cs index 2aef9bc..ef77226 100644 --- a/Glamourer/Designs/Links/DesignMerger.cs +++ b/Glamourer/Designs/Links/DesignMerger.cs @@ -1,5 +1,4 @@ using Glamourer.Automation; -using Glamourer.Events; using Glamourer.GameData; using Glamourer.Services; using Glamourer.State; @@ -28,13 +27,13 @@ public class DesignMerger( continue; ref readonly var data = ref design == null ? ref baseRef : ref design.GetDesignDataRef(); - var source = design == null ? StateChanged.Source.Game : StateChanged.Source.Manual; + var source = design == null ? StateSource.Game : StateSource.Manual; if (!data.IsHuman) continue; - var (equipFlags, customizeFlags, crestFlags, parameterFlags, applyHat, applyVisor, applyWeapon, applyWet) = type.ApplyWhat(design); - ReduceMeta(data, applyHat, applyVisor, applyWeapon, applyWet, ret, source); + var (equipFlags, customizeFlags, crestFlags, parameterFlags, applyMeta) = type.ApplyWhat(design); + ReduceMeta(data, applyMeta, ret, source); ReduceCustomize(data, customizeFlags, ref fixFlags, ret, source, respectOwnership); ReduceEquip(data, equipFlags, ret, source, respectOwnership); ReduceMainhands(data, equipFlags, ret, source, respectOwnership); @@ -58,39 +57,22 @@ public class DesignMerger( ret.AssociatedMods.TryAdd(mod, settings); } - private static void ReduceMeta(in DesignData design, bool applyHat, bool applyVisor, bool applyWeapon, bool applyWet, MergedDesign ret, - StateChanged.Source source) + private static void ReduceMeta(in DesignData design, MetaFlag applyMeta, MergedDesign ret, StateSource source) { - if (applyHat && !ret.Design.DoApplyHatVisible()) - { - ret.Design.SetApplyHatVisible(true); - ret.Design.GetDesignDataRef().SetHatVisible(design.IsHatVisible()); - ret.Source[MetaIndex.HatState] = source; - } + applyMeta &= ~ret.Design.ApplyMeta; - if (applyVisor && !ret.Design.DoApplyVisorToggle()) + foreach (var index in MetaExtensions.AllRelevant) { - ret.Design.SetApplyVisorToggle(true); - ret.Design.GetDesignDataRef().SetVisor(design.IsVisorToggled()); - ret.Source[MetaIndex.VisorState] = source; - } + if (!applyMeta.HasFlag(index.ToFlag())) + continue; - if (applyWeapon && !ret.Design.DoApplyWeaponVisible()) - { - ret.Design.SetApplyWeaponVisible(true); - ret.Design.GetDesignDataRef().SetWeaponVisible(design.IsWeaponVisible()); - ret.Source[MetaIndex.WeaponState] = source; - } - - if (applyWet && !ret.Design.DoApplyWetness()) - { - ret.Design.SetApplyWetness(true); - ret.Design.GetDesignDataRef().SetIsWet(design.IsWet()); - ret.Source[MetaIndex.Wetness] = source; + ret.Design.SetApplyMeta(index, true); + ret.Design.GetDesignDataRef().SetMeta(index, design.GetMeta(index)); + ret.Sources[index] = source; } } - private static void ReduceCrests(in DesignData design, CrestFlag crestFlags, MergedDesign ret, StateChanged.Source source) + private static void ReduceCrests(in DesignData design, CrestFlag crestFlags, MergedDesign ret, StateSource source) { crestFlags &= ~ret.Design.ApplyCrest; if (crestFlags == 0) @@ -103,12 +85,12 @@ public class DesignMerger( ret.Design.GetDesignDataRef().SetCrest(slot, design.Crest(slot)); ret.Design.SetApplyCrest(slot, true); - ret.Source[slot] = source; + ret.Sources[slot] = source; } } private static void ReduceParameters(in DesignData design, CustomizeParameterFlag parameterFlags, MergedDesign ret, - StateChanged.Source source) + StateSource source) { parameterFlags &= ~ret.Design.ApplyParameters; if (parameterFlags == 0) @@ -121,11 +103,11 @@ public class DesignMerger( ret.Design.GetDesignDataRef().Parameters.Set(flag, design.Parameters[flag]); ret.Design.SetApplyParameter(flag, true); - ret.Source[flag] = source; + ret.Sources[flag] = source; } } - private void ReduceEquip(in DesignData design, EquipFlag equipFlags, MergedDesign ret, StateChanged.Source source, + private void ReduceEquip(in DesignData design, EquipFlag equipFlags, MergedDesign ret, StateSource source, bool respectOwnership) { equipFlags &= ~ret.Design.ApplyEquip; @@ -142,7 +124,7 @@ public class DesignMerger( if (!respectOwnership || _itemUnlocks.IsUnlocked(item.Id, out _)) ret.Design.GetDesignDataRef().SetItem(slot, item); ret.Design.SetApplyEquip(slot, true); - ret.Source[slot, false] = source; + ret.Sources[slot, false] = source; } var stainFlag = slot.ToStainFlag(); @@ -150,7 +132,7 @@ public class DesignMerger( { ret.Design.GetDesignDataRef().SetStain(slot, design.Stain(slot)); ret.Design.SetApplyStain(slot, true); - ret.Source[slot, true] = source; + ret.Sources[slot, true] = source; } } @@ -161,12 +143,12 @@ public class DesignMerger( { ret.Design.GetDesignDataRef().SetStain(slot, design.Stain(slot)); ret.Design.SetApplyStain(slot, true); - ret.Source[slot, true] = source; + ret.Sources[slot, true] = source; } } } - private void ReduceMainhands(in DesignData design, EquipFlag equipFlags, MergedDesign ret, StateChanged.Source source, + private void ReduceMainhands(in DesignData design, EquipFlag equipFlags, MergedDesign ret, StateSource source, bool respectOwnership) { if (!equipFlags.HasFlag(EquipFlag.Mainhand)) @@ -185,7 +167,7 @@ public class DesignMerger( ret.Weapons.TryAdd(weapon.Type, (weapon, source)); } - private void ReduceOffhands(in DesignData design, EquipFlag equipFlags, MergedDesign ret, StateChanged.Source source, bool respectOwnership) + private void ReduceOffhands(in DesignData design, EquipFlag equipFlags, MergedDesign ret, StateSource source, bool respectOwnership) { if (!equipFlags.HasFlag(EquipFlag.Offhand)) return; @@ -205,7 +187,7 @@ public class DesignMerger( } private void ReduceCustomize(in DesignData design, CustomizeFlag customizeFlags, ref CustomizeFlag fixFlags, MergedDesign ret, - StateChanged.Source source, bool respectOwnership) + StateSource source, bool respectOwnership) { customizeFlags &= ~ret.Design.ApplyCustomizeRaw; if (customizeFlags == 0) @@ -221,25 +203,25 @@ public class DesignMerger( fixFlags |= _customize.ChangeClan(ref customize, design.Customize.Clan); ret.Design.SetApplyCustomize(CustomizeIndex.Clan, true); ret.Design.SetApplyCustomize(CustomizeIndex.Race, true); - customizeFlags &= ~(CustomizeFlag.Clan | CustomizeFlag.Race); - ret.Source[CustomizeIndex.Clan] = source; - ret.Source[CustomizeIndex.Race] = source; + customizeFlags &= ~(CustomizeFlag.Clan | CustomizeFlag.Race); + ret.Sources[CustomizeIndex.Clan] = source; + ret.Sources[CustomizeIndex.Race] = source; } if (customizeFlags.HasFlag(CustomizeFlag.Gender)) { fixFlags |= _customize.ChangeGender(ref customize, design.Customize.Gender); ret.Design.SetApplyCustomize(CustomizeIndex.Gender, true); - customizeFlags &= ~CustomizeFlag.Gender; - ret.Source[CustomizeIndex.Gender] = source; + customizeFlags &= ~CustomizeFlag.Gender; + ret.Sources[CustomizeIndex.Gender] = source; } if (customizeFlags.HasFlag(CustomizeFlag.Face)) { customize[CustomizeIndex.Face] = design.Customize.Face; ret.Design.SetApplyCustomize(CustomizeIndex.Face, true); - customizeFlags &= ~CustomizeFlag.Face; - ret.Source[CustomizeIndex.Face] = source; + customizeFlags &= ~CustomizeFlag.Face; + ret.Sources[CustomizeIndex.Face] = source; } var set = ret.Design.CustomizeSet; @@ -259,8 +241,8 @@ public class DesignMerger( customize[index] = data?.Value ?? value; ret.Design.SetApplyCustomize(index, true); - ret.Source[index] = source; - fixFlags &= ~flag; + ret.Sources[index] = source; + fixFlags &= ~flag; } ret.Design.SetCustomize(_customize, customize); @@ -272,15 +254,15 @@ public class DesignMerger( return; var source = ret.Design.DoApplyCustomize(CustomizeIndex.Clan) - ? ret.Source[CustomizeIndex.Clan] - : ret.Source[CustomizeIndex.Gender]; + ? ret.Sources[CustomizeIndex.Clan] + : ret.Sources[CustomizeIndex.Gender]; foreach (var index in Enum.GetValues()) { var flag = index.ToFlag(); if (!fixFlags.HasFlag(flag)) continue; - ret.Source[index] = source; + ret.Sources[index] = source; ret.Design.SetApplyCustomize(index, true); } } diff --git a/Glamourer/Designs/Links/MergedDesign.cs b/Glamourer/Designs/Links/MergedDesign.cs index d4b3cab..74e65ca 100644 --- a/Glamourer/Designs/Links/MergedDesign.cs +++ b/Glamourer/Designs/Links/MergedDesign.cs @@ -26,14 +26,14 @@ public sealed class MergedDesign { var weapon = design.DesignData.Item(EquipSlot.MainHand); if (weapon.Valid) - Weapons.TryAdd(weapon.Type, (weapon, StateChanged.Source.Manual)); + Weapons.TryAdd(weapon.Type, (weapon, StateSource.Manual)); } if (design.DoApplyEquip(EquipSlot.OffHand)) { var weapon = design.DesignData.Item(EquipSlot.OffHand); if (weapon.Valid) - Weapons.TryAdd(weapon.Type, (weapon, StateChanged.Source.Manual)); + Weapons.TryAdd(weapon.Type, (weapon, StateSource.Manual)); } } @@ -44,26 +44,26 @@ public sealed class MergedDesign AssociatedMods[mod] = settings; } - public readonly DesignBase Design; - public readonly Dictionary Weapons = new(4); - public readonly StateSource Source = new(); - public readonly SortedList AssociatedMods = []; + public readonly DesignBase Design; + public readonly Dictionary Weapons = new(4); + public readonly SortedList AssociatedMods = []; + public StateSources Sources = new(); - public StateChanged.Source GetSource(EquipSlot slot, bool stain, StateChanged.Source actualSource) - => GetSource(Source[slot, stain], actualSource); + public StateSource GetSource(EquipSlot slot, bool stain, StateSource actualSource) + => GetSource(Sources[slot, stain], actualSource); - public StateChanged.Source GetSource(CrestFlag slot, StateChanged.Source actualSource) - => GetSource(Source[slot], actualSource); + public StateSource GetSource(CrestFlag slot, StateSource actualSource) + => GetSource(Sources[slot], actualSource); - public StateChanged.Source GetSource(CustomizeIndex type, StateChanged.Source actualSource) - => GetSource(Source[type], actualSource); + public StateSource GetSource(CustomizeIndex type, StateSource actualSource) + => GetSource(Sources[type], actualSource); - public StateChanged.Source GetSource(MetaIndex index, StateChanged.Source actualSource) - => GetSource(Source[index], actualSource); + public StateSource GetSource(MetaIndex index, StateSource actualSource) + => GetSource(Sources[index], actualSource); - public StateChanged.Source GetSource(CustomizeParameterFlag flag, StateChanged.Source actualSource) - => GetSource(Source[flag], actualSource); + public StateSource GetSource(CustomizeParameterFlag flag, StateSource actualSource) + => GetSource(Sources[flag], actualSource); - public static StateChanged.Source GetSource(StateChanged.Source given, StateChanged.Source actualSource) - => given is StateChanged.Source.Game ? StateChanged.Source.Game : actualSource; + public static StateSource GetSource(StateSource given, StateSource actualSource) + => given is StateSource.Game ? StateSource.Game : actualSource; } diff --git a/Glamourer/Designs/MetaIndex.cs b/Glamourer/Designs/MetaIndex.cs index 4fac98d..2dd77cd 100644 --- a/Glamourer/Designs/MetaIndex.cs +++ b/Glamourer/Designs/MetaIndex.cs @@ -1,14 +1,14 @@ -using Penumbra.GameData.Enums; +using Glamourer.State; -namespace Glamourer.State; +namespace Glamourer.Designs; public enum MetaIndex { - Wetness = EquipFlagExtensions.NumEquipFlags + CustomizationExtensions.NumIndices, - HatState, - VisorState, - WeaponState, - ModelId, + Wetness = StateIndex.MetaWetness, + HatState = StateIndex.MetaHatState, + VisorState = StateIndex.MetaVisorState, + WeaponState = StateIndex.MetaWeaponState, + ModelId = StateIndex.MetaModelId, } [Flags] @@ -34,6 +34,26 @@ public static class MetaExtensions MetaIndex.HatState => MetaFlag.HatState, MetaIndex.VisorState => MetaFlag.VisorState, MetaIndex.WeaponState => MetaFlag.WeaponState, - _ => (MetaFlag) byte.MaxValue, + _ => (MetaFlag)byte.MaxValue, + }; + + public static string ToName(this MetaIndex index) + => index switch + { + MetaIndex.HatState => "Hat Visible", + MetaIndex.VisorState => "Visor Toggled", + MetaIndex.WeaponState => "Weapon Visible", + MetaIndex.Wetness => "Force Wetness", + _ => "Unknown Meta", + }; + + public static string ToTooltip(this MetaIndex index) + => index switch + { + MetaIndex.HatState => "Hide or show the characters head gear.", + MetaIndex.VisorState => "Toggle the visor state of the characters head gear.", + MetaIndex.WeaponState => "Hide or show the characters weapons when not drawn.", + MetaIndex.Wetness => "Force the character to be wet or not.", + _ => string.Empty, }; } diff --git a/Glamourer/Events/StateChanged.cs b/Glamourer/Events/StateChanged.cs index 01e2758..47b5d20 100644 --- a/Glamourer/Events/StateChanged.cs +++ b/Glamourer/Events/StateChanged.cs @@ -2,68 +2,59 @@ using Glamourer.Interop.Structs; using Glamourer.State; using OtterGui.Classes; -namespace Glamourer.Events; - -/// -/// Triggered when a Design is edited in any way. -/// -/// Parameter is the type of the change -/// Parameter is the changed saved state. -/// Parameter is the existing actors using this saved state. -/// Parameter is any additional data depending on the type of change. -/// -/// -public sealed class StateChanged() - : EventWrapper(nameof(StateChanged)) +namespace Glamourer.Events { - public enum Type + /// + /// Triggered when a Design is edited in any way. + /// + /// Parameter is the type of the change + /// Parameter is the changed saved state. + /// Parameter is the existing actors using this saved state. + /// Parameter is any additional data depending on the type of change. + /// + /// + public sealed class StateChanged() + : EventWrapper(nameof(StateChanged)) { - /// A characters saved state had the model id changed. This means everything may have changed. Data is the old model id and the new model id. [(uint, uint)] - Model, + public enum Type + { + /// A characters saved state had the model id changed. This means everything may have changed. Data is the old model id and the new model id. [(uint, uint)] + Model, - /// A characters saved state had multiple customization values changed. TData is the old customize array and the applied changes. [(Customize, CustomizeFlag)] - EntireCustomize, + /// A characters saved state had multiple customization values changed. TData is the old customize array and the applied changes. [(Customize, CustomizeFlag)] + EntireCustomize, - /// A characters saved state had a customization value changed. Data is the old value, the new value and the type. [(CustomizeValue, CustomizeValue, CustomizeIndex)]. - Customize, + /// A characters saved state had a customization value changed. Data is the old value, the new value and the type. [(CustomizeValue, CustomizeValue, CustomizeIndex)]. + Customize, - /// A characters saved state had an equipment piece changed. Data is the old value, the new value and the slot [(EquipItem, EquipItem, EquipSlot)]. - Equip, + /// A characters saved state had an equipment piece changed. Data is the old value, the new value and the slot [(EquipItem, EquipItem, EquipSlot)]. + Equip, - /// A characters saved state had its weapons changed. Data is the old mainhand, the old offhand, the new mainhand and the new offhand [(EquipItem, EquipItem, EquipItem, EquipItem)]. - Weapon, + /// A characters saved state had its weapons changed. Data is the old mainhand, the old offhand, the new mainhand and the new offhand [(EquipItem, EquipItem, EquipItem, EquipItem)]. + Weapon, - /// A characters saved state had a stain changed. Data is the old stain id, the new stain id and the slot [(StainId, StainId, EquipSlot)]. - Stain, + /// A characters saved state had a stain changed. Data is the old stain id, the new stain id and the slot [(StainId, StainId, EquipSlot)]. + Stain, - /// A characters saved state had a crest visibility changed. Data is the old crest visibility, the new crest visibility and the slot [(bool, bool, EquipSlot)]. - Crest, + /// A characters saved state had a crest visibility changed. Data is the old crest visibility, the new crest visibility and the slot [(bool, bool, EquipSlot)]. + Crest, - /// A characters saved state had its customize parameter changed. Data is the old value, the new value and the type [(CustomizeParameterValue, CustomizeParameterValue, CustomizeParameterFlag)]. - Parameter, + /// A characters saved state had its customize parameter changed. Data is the old value, the new value and the type [(CustomizeParameterValue, CustomizeParameterValue, CustomizeParameterFlag)]. + Parameter, - /// A characters saved state had a design applied. This means everything may have changed. Data is the applied design. [DesignBase] - Design, + /// A characters saved state had a design applied. This means everything may have changed. Data is the applied design. [DesignBase] + Design, - /// A characters saved state had its state reset to its game values. This means everything may have changed. Data is null. - Reset, + /// A characters saved state had its state reset to its game values. This means everything may have changed. Data is null. + Reset, - /// A characters saved state had a meta toggle changed. Data is the old stain id, the new stain id and the slot [(StainId, StainId, EquipSlot)]. - Other, - } + /// A characters saved state had a meta toggle changed. Data is the old stain id, the new stain id and the slot [(StainId, StainId, EquipSlot)]. + Other, + } - public enum Source : byte - { - Game, - Manual, - Fixed, - Ipc, - // Only used for CustomizeParameters. - Pending, - } - - public enum Priority - { - GlamourerIpc = int.MinValue, + public enum Priority + { + GlamourerIpc = int.MinValue, + } } } diff --git a/Glamourer/Gui/Customization/CustomizeParameterDrawData.cs b/Glamourer/Gui/Customization/CustomizeParameterDrawData.cs index 0bae022..07f3486 100644 --- a/Glamourer/Gui/Customization/CustomizeParameterDrawData.cs +++ b/Glamourer/Gui/Customization/CustomizeParameterDrawData.cs @@ -33,7 +33,7 @@ public ref struct CustomizeParameterDrawData(CustomizeParameterFlag flag, in Des { Locked = state.IsLocked, DisplayApplication = false, - ValueSetter = v => manager.ChangeCustomizeParameter(state, flag, v, StateChanged.Source.Manual), + ValueSetter = v => manager.ChangeCustomizeParameter(state, flag, v, StateSource.Manual), GameValue = state.BaseData.Parameters[flag], AllowRevert = true, }; diff --git a/Glamourer/Gui/DesignQuickBar.cs b/Glamourer/Gui/DesignQuickBar.cs index f6e73f9..37c37e7 100644 --- a/Glamourer/Gui/DesignQuickBar.cs +++ b/Glamourer/Gui/DesignQuickBar.cs @@ -163,7 +163,7 @@ public sealed class DesignQuickBar : Window, IDisposable var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags(); using var _ = design!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest, applyParameters); - _stateManager.ApplyDesign(design, state, StateChanged.Source.Manual); + _stateManager.ApplyDesign(design, state, StateSource.Manual); } public void DrawRevertButton(Vector2 buttonSize) @@ -189,7 +189,7 @@ public sealed class DesignQuickBar : Window, IDisposable var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.UndoAlt, buttonSize, tooltip, available); if (clicked) - _stateManager.ResetState(state!, StateChanged.Source.Manual); + _stateManager.ResetState(state!, StateSource.Manual); } public void DrawRevertAutomationButton(Vector2 buttonSize) @@ -257,7 +257,7 @@ public sealed class DesignQuickBar : Window, IDisposable ImGui.SameLine(); var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.Palette, buttonSize, tooltip, available); if (clicked) - _stateManager.ResetAdvancedState(state!, StateChanged.Source.Manual); + _stateManager.ResetAdvancedState(state!, StateSource.Manual); } private (bool, ActorIdentifier, ActorData, ActorState?) ResolveTarget(FontAwesomeIcon icon, Vector2 buttonSize, string tooltip, diff --git a/Glamourer/Gui/Equipment/EquipDrawData.cs b/Glamourer/Gui/Equipment/EquipDrawData.cs index 57da890..1450fb5 100644 --- a/Glamourer/Gui/Equipment/EquipDrawData.cs +++ b/Glamourer/Gui/Equipment/EquipDrawData.cs @@ -46,8 +46,8 @@ public ref struct EquipDrawData(EquipSlot slot, in DesignData designData) public static EquipDrawData FromState(StateManager manager, ActorState state, EquipSlot slot) => new(slot, state.ModelData) { - ItemSetter = i => manager.ChangeItem(state, slot, i, StateChanged.Source.Manual), - StainSetter = i => manager.ChangeStain(state, slot, i, StateChanged.Source.Manual), + ItemSetter = i => manager.ChangeItem(state, slot, i, StateSource.Manual), + StainSetter = i => manager.ChangeStain(state, slot, i, StateSource.Manual), Locked = state.IsLocked, DisplayApplication = false, GameItem = state.BaseData.Item(slot), diff --git a/Glamourer/Gui/PenumbraChangedItemTooltip.cs b/Glamourer/Gui/PenumbraChangedItemTooltip.cs index d030abb..ecea9ad 100644 --- a/Glamourer/Gui/PenumbraChangedItemTooltip.cs +++ b/Glamourer/Gui/PenumbraChangedItemTooltip.cs @@ -113,22 +113,22 @@ public class PenumbraChangedItemTooltip : IDisposable case (false, false): Glamourer.Log.Information($"Applying {item.Name} to Right Finger."); SetLastItem(EquipSlot.RFinger, item, state); - _stateManager.ChangeItem(state, EquipSlot.RFinger, item, StateChanged.Source.Manual); + _stateManager.ChangeItem(state, EquipSlot.RFinger, item, StateSource.Manual); break; case (false, true): Glamourer.Log.Information($"Applying {item.Name} to Left Finger."); SetLastItem(EquipSlot.LFinger, item, state); - _stateManager.ChangeItem(state, EquipSlot.LFinger, item, StateChanged.Source.Manual); + _stateManager.ChangeItem(state, EquipSlot.LFinger, item, StateSource.Manual); break; case (true, false) when last.Valid: Glamourer.Log.Information($"Re-Applying {last.Name} to Right Finger."); SetLastItem(EquipSlot.RFinger, default, state); - _stateManager.ChangeItem(state, EquipSlot.RFinger, last, StateChanged.Source.Manual); + _stateManager.ChangeItem(state, EquipSlot.RFinger, last, StateSource.Manual); break; case (true, true) when _lastItems[EquipSlot.LFinger.ToIndex()].Valid: Glamourer.Log.Information($"Re-Applying {last.Name} to Left Finger."); SetLastItem(EquipSlot.LFinger, default, state); - _stateManager.ChangeItem(state, EquipSlot.LFinger, last, StateChanged.Source.Manual); + _stateManager.ChangeItem(state, EquipSlot.LFinger, last, StateSource.Manual); break; } @@ -138,13 +138,13 @@ public class PenumbraChangedItemTooltip : IDisposable { Glamourer.Log.Information($"Re-Applying {last.Name} to {slot.ToName()}."); SetLastItem(slot, default, state); - _stateManager.ChangeItem(state, slot, last, StateChanged.Source.Manual); + _stateManager.ChangeItem(state, slot, last, StateSource.Manual); } else { Glamourer.Log.Information($"Applying {item.Name} to {slot.ToName()}."); SetLastItem(slot, item, state); - _stateManager.ChangeItem(state, slot, item, StateChanged.Source.Manual); + _stateManager.ChangeItem(state, slot, item, StateSource.Manual); } return; diff --git a/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs b/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs index e85057d..e1d0eef 100644 --- a/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs +++ b/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs @@ -61,13 +61,13 @@ public class ActorPanel( if (_importService.CreateDatTarget(out var dat)) { - _stateManager.ChangeCustomize(_state!, dat.Customize, CustomizeApplicationFlags, StateChanged.Source.Manual); + _stateManager.ChangeCustomize(_state!, dat.Customize, CustomizeApplicationFlags, StateSource.Manual); Glamourer.Messager.NotificationMessage($"Applied games .dat file {dat.Description} customizations to {_state.Identifier}.", NotificationType.Success, false); } else if (_importService.CreateCharaTarget(out var designBase, out var name)) { - _stateManager.ApplyDesign(designBase, _state!, StateChanged.Source.Manual); + _stateManager.ApplyDesign(designBase, _state!, StateSource.Manual); Glamourer.Messager.NotificationMessage($"Applied Anamnesis .chara file {name} to {_state.Identifier}.", NotificationType.Success, false); } @@ -139,7 +139,7 @@ public class ActorPanel( return; if (_customizationDrawer.Draw(_state!.ModelData.Customize, _state.IsLocked, _lockedRedraw)) - _stateManager.ChangeCustomize(_state, _customizationDrawer.Customize, _customizationDrawer.Changed, StateChanged.Source.Manual); + _stateManager.ChangeCustomize(_state, _customizationDrawer.Customize, _customizationDrawer.Changed, StateSource.Manual); EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(MetaIndex.Wetness, _stateManager, _state)); ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2)); @@ -159,7 +159,7 @@ public class ActorPanel( var data = EquipDrawData.FromState(_stateManager, _state!, slot); _equipmentDrawer.DrawEquip(data); if (usedAllStain) - _stateManager.ChangeStain(_state, slot, newAllStain, StateChanged.Source.Manual); + _stateManager.ChangeStain(_state, slot, newAllStain, StateSource.Manual); } var mainhand = EquipDrawData.FromState(_stateManager, _state, EquipSlot.MainHand); @@ -264,7 +264,7 @@ public class ActorPanel( } if (turnHuman) - _stateManager.TurnHuman(_state, StateChanged.Source.Manual); + _stateManager.TurnHuman(_state, StateSource.Manual); } private HeaderDrawer.Button SetFromClipboardButton() @@ -340,7 +340,7 @@ public class ActorPanel( var text = ImGui.GetClipboardText(); var design = _converter.FromBase64(text, applyCustomize, applyGear, out _) ?? throw new Exception("The clipboard did not contain valid data."); - _stateManager.ApplyDesign(design, _state!, StateChanged.Source.Manual); + _stateManager.ApplyDesign(design, _state!, StateSource.Manual); } catch (Exception ex) { @@ -368,7 +368,7 @@ public class ActorPanel( { if (ImGuiUtil.DrawDisabledButton("Revert to Game", Vector2.Zero, "Revert the character to its actual state in the game.", _state!.IsLocked)) - _stateManager.ResetState(_state!, StateChanged.Source.Manual); + _stateManager.ResetState(_state!, StateSource.Manual); ImGui.SameLine(); if (ImGuiUtil.DrawDisabledButton("Reapply State", Vector2.Zero, "Try to reapply the configured state if something went wrong.", @@ -396,7 +396,7 @@ public class ActorPanel( var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags(); if (_stateManager.GetOrCreate(id, data.Objects[0], out var state)) _stateManager.ApplyDesign(_converter.Convert(_state!, applyGear, applyCustomize, applyCrest, applyParameters), state, - StateChanged.Source.Manual); + StateSource.Manual); } private void DrawApplyToTarget() @@ -414,6 +414,6 @@ public class ActorPanel( var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags(); if (_stateManager.GetOrCreate(id, data.Objects[0], out var state)) _stateManager.ApplyDesign(_converter.Convert(_state!, applyGear, applyCustomize, applyCrest, applyParameters), state, - StateChanged.Source.Manual); + StateSource.Manual); } } diff --git a/Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs b/Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs index bb9e135..2cb1ede 100644 --- a/Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs +++ b/Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs @@ -264,7 +264,7 @@ public class SetPanel( var size = new Vector2(ImGui.GetFrameHeight()); size.X += ImGuiHelpers.GlobalScale; - var (equipFlags, customizeFlags, _, _, _, _, _, _) = design.ApplyWhat(); + var (equipFlags, customizeFlags, _, _, _) = design.ApplyWhat(); var sb = new StringBuilder(); foreach (var slot in EquipSlotExtensions.EqdpSlots.Append(EquipSlot.MainHand).Append(EquipSlot.OffHand)) { diff --git a/Glamourer/Gui/Tabs/DebugTab/ActiveStatePanel.cs b/Glamourer/Gui/Tabs/DebugTab/ActiveStatePanel.cs index 6eac9ad..7b3f594 100644 --- a/Glamourer/Gui/Tabs/DebugTab/ActiveStatePanel.cs +++ b/Glamourer/Gui/Tabs/DebugTab/ActiveStatePanel.cs @@ -52,11 +52,11 @@ public class ActiveStatePanel(StateManager _stateManager, ObjectManager _objectM ImGuiUtil.DrawTableColumn(state.Identifier.ToString()); ImGui.TableNextColumn(); if (ImGui.Button("Reset")) - stateManager.ResetState(state, StateChanged.Source.Manual); + stateManager.ResetState(state, StateSource.Manual); ImGui.TableNextRow(); - static void PrintRow(string label, T actor, T model, StateChanged.Source source) where T : notnull + static void PrintRow(string label, T actor, T model, StateSource source) where T : notnull { ImGuiUtil.DrawTableColumn(label); ImGuiUtil.DrawTableColumn(actor.ToString()!); @@ -70,44 +70,44 @@ public class ActiveStatePanel(StateManager _stateManager, ObjectManager _objectM return $"{item.Name} ({item.PrimaryId.Id}{(item.SecondaryId != 0 ? $"-{item.SecondaryId.Id}" : string.Empty)}-{item.Variant})"; } - PrintRow("Model ID", state.BaseData.ModelId, state.ModelData.ModelId, state.Source[MetaIndex.ModelId]); + PrintRow("Model ID", state.BaseData.ModelId, state.ModelData.ModelId, state.Sources[MetaIndex.ModelId]); ImGui.TableNextRow(); - PrintRow("Wetness", state.BaseData.IsWet(), state.ModelData.IsWet(), state.Source[MetaIndex.Wetness]); + PrintRow("Wetness", state.BaseData.IsWet(), state.ModelData.IsWet(), state.Sources[MetaIndex.Wetness]); ImGui.TableNextRow(); if (state.BaseData.IsHuman && state.ModelData.IsHuman) { - PrintRow("Hat Visible", state.BaseData.IsHatVisible(), state.ModelData.IsHatVisible(), state.Source[MetaIndex.HatState]); + PrintRow("Hat Visible", state.BaseData.IsHatVisible(), state.ModelData.IsHatVisible(), state.Sources[MetaIndex.HatState]); ImGui.TableNextRow(); PrintRow("Visor Toggled", state.BaseData.IsVisorToggled(), state.ModelData.IsVisorToggled(), - state.Source[MetaIndex.VisorState]); + state.Sources[MetaIndex.VisorState]); ImGui.TableNextRow(); PrintRow("Weapon Visible", state.BaseData.IsWeaponVisible(), state.ModelData.IsWeaponVisible(), - state.Source[MetaIndex.WeaponState]); + state.Sources[MetaIndex.WeaponState]); ImGui.TableNextRow(); foreach (var slot in EquipSlotExtensions.EqdpSlots.Prepend(EquipSlot.OffHand).Prepend(EquipSlot.MainHand)) { - PrintRow(slot.ToName(), ItemString(state.BaseData, slot), ItemString(state.ModelData, slot), state.Source[slot, false]); + PrintRow(slot.ToName(), ItemString(state.BaseData, slot), ItemString(state.ModelData, slot), state.Sources[slot, false]); ImGuiUtil.DrawTableColumn(state.BaseData.Stain(slot).Id.ToString()); ImGuiUtil.DrawTableColumn(state.ModelData.Stain(slot).Id.ToString()); - ImGuiUtil.DrawTableColumn(state.Source[slot, true].ToString()); + ImGuiUtil.DrawTableColumn(state.Sources[slot, true].ToString()); } foreach (var type in Enum.GetValues()) { - PrintRow(type.ToDefaultName(), state.BaseData.Customize[type].Value, state.ModelData.Customize[type].Value, state.Source[type]); + PrintRow(type.ToDefaultName(), state.BaseData.Customize[type].Value, state.ModelData.Customize[type].Value, state.Sources[type]); ImGui.TableNextRow(); } foreach (var crest in CrestExtensions.AllRelevantSet) { - PrintRow(crest.ToLabel(), state.BaseData.Crest(crest), state.ModelData.Crest(crest), state.Source[crest]); + PrintRow(crest.ToLabel(), state.BaseData.Crest(crest), state.ModelData.Crest(crest), state.Sources[crest]); ImGui.TableNextRow(); } foreach (var flag in CustomizeParameterExtensions.AllFlags) { - PrintRow(flag.ToString(), state.BaseData.Parameters[flag], state.ModelData.Parameters[flag], state.Source[flag]); + PrintRow(flag.ToString(), state.BaseData.Parameters[flag], state.ModelData.Parameters[flag], state.Sources[flag]); ImGui.TableNextRow(); } } diff --git a/Glamourer/Gui/Tabs/DebugTab/DesignManagerPanel.cs b/Glamourer/Gui/Tabs/DebugTab/DesignManagerPanel.cs index d4070ef..85b4010 100644 --- a/Glamourer/Gui/Tabs/DebugTab/DesignManagerPanel.cs +++ b/Glamourer/Gui/Tabs/DebugTab/DesignManagerPanel.cs @@ -25,9 +25,8 @@ public class DesignManagerPanel(DesignManager _designManager, DesignFileSystem _ continue; DrawDesign(design, _designFileSystem); - var base64 = DesignBase64Migration.CreateOldBase64(design.DesignData, design.ApplyEquip, design.ApplyCustomizeRaw, - design.DoApplyHatVisible(), - design.DoApplyVisorToggle(), design.DoApplyWeaponVisible(), design.WriteProtected()); + var base64 = DesignBase64Migration.CreateOldBase64(design.DesignData, design.ApplyEquip, design.ApplyCustomizeRaw, design.ApplyMeta, + design.WriteProtected()); using var font = ImRaii.PushFont(UiBuilder.MonoFont); ImGuiUtil.TextWrapped(base64); if (ImGui.IsItemClicked()) @@ -85,18 +84,12 @@ public class DesignManagerPanel(DesignManager _designManager, DesignFileSystem _ ImGuiUtil.DrawTableColumn(applyCrest ? "Apply" : "Keep"); } - ImGuiUtil.DrawTableColumn("Hat Visible"); - ImGuiUtil.DrawTableColumn(design.DesignData.IsHatVisible().ToString()); - ImGuiUtil.DrawTableColumn(design.DoApplyHatVisible() ? "Apply" : "Keep"); - ImGui.TableNextRow(); - ImGuiUtil.DrawTableColumn("Visor Toggled"); - ImGuiUtil.DrawTableColumn(design.DesignData.IsVisorToggled().ToString()); - ImGuiUtil.DrawTableColumn(design.DoApplyVisorToggle() ? "Apply" : "Keep"); - ImGui.TableNextRow(); - ImGuiUtil.DrawTableColumn("Weapon Visible"); - ImGuiUtil.DrawTableColumn(design.DesignData.IsWeaponVisible().ToString()); - ImGuiUtil.DrawTableColumn(design.DoApplyWeaponVisible() ? "Apply" : "Keep"); - ImGui.TableNextRow(); + foreach (var index in MetaExtensions.AllRelevant) + { + ImGuiUtil.DrawTableColumn(index.ToName()); + ImGuiUtil.DrawTableColumn(design.DesignData.GetMeta(index).ToString()); + ImGuiUtil.DrawTableColumn(design.DoApplyMeta(index) ? "Apply" : "Keep"); + } ImGuiUtil.DrawTableColumn("Model ID"); ImGuiUtil.DrawTableColumn(design.DesignData.ModelId.ToString()); @@ -111,9 +104,5 @@ public class DesignManagerPanel(DesignManager _designManager, DesignFileSystem _ ImGuiUtil.DrawTableColumn(apply ? "Apply" : "Keep"); ImGui.TableNextRow(); } - - ImGuiUtil.DrawTableColumn("Is Wet"); - ImGuiUtil.DrawTableColumn(design.DesignData.IsWet().ToString()); - ImGui.TableNextRow(); } } diff --git a/Glamourer/Gui/Tabs/DebugTab/DesignTesterPanel.cs b/Glamourer/Gui/Tabs/DebugTab/DesignTesterPanel.cs index 7bc83f9..c893f4c 100644 --- a/Glamourer/Gui/Tabs/DebugTab/DesignTesterPanel.cs +++ b/Glamourer/Gui/Tabs/DebugTab/DesignTesterPanel.cs @@ -55,10 +55,8 @@ public class DesignTesterPanel(ItemManager _items, HumanModelList _humans) : IGa try { - _parse64 = DesignBase64Migration.MigrateBase64(_items, _humans, _base64, out var ef, out var cf, out var wp, out var ah, - out var av, - out var aw); - _restore = DesignBase64Migration.CreateOldBase64(in _parse64, ef, cf, ah, av, aw, wp); + _parse64 = DesignBase64Migration.MigrateBase64(_items, _humans, _base64, out var ef, out var cf, out var wp, out var meta); + _restore = DesignBase64Migration.CreateOldBase64(in _parse64, ef, cf, meta, wp); _restoreBytes = Convert.FromBase64String(_restore); } catch (Exception ex) diff --git a/Glamourer/Gui/Tabs/DebugTab/NpcAppearancePanel.cs b/Glamourer/Gui/Tabs/DebugTab/NpcAppearancePanel.cs index 505ed62..90302b8 100644 --- a/Glamourer/Gui/Tabs/DebugTab/NpcAppearancePanel.cs +++ b/Glamourer/Gui/Tabs/DebugTab/NpcAppearancePanel.cs @@ -67,9 +67,9 @@ public class NpcAppearancePanel(NpcCombo _npcCombo, StateManager _state, ObjectM if (ImGuiUtil.DrawDisabledButton("Apply", Vector2.Zero, string.Empty, disabled)) { foreach (var (slot, item, stain) in _designConverter.FromDrawData(data.Equip.ToArray(), data.Mainhand, data.Offhand, true)) - _state.ChangeEquip(state!, slot, item, stain, StateChanged.Source.Manual); - _state.ChangeVisorState(state!, data.VisorToggled, StateChanged.Source.Manual); - _state.ChangeCustomize(state!, data.Customize, CustomizeFlagExtensions.All, StateChanged.Source.Manual); + _state.ChangeEquip(state!, slot, item, stain, StateSource.Manual); + _state.ChangeMeta(state!, MetaIndex.VisorState, data.VisorToggled, StateSource.Manual); + _state.ChangeCustomize(state!, data.Customize, CustomizeFlagExtensions.All, StateSource.Manual); } ImGui.TableNextColumn(); diff --git a/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs b/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs index f942439..803a226 100644 --- a/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs +++ b/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs @@ -287,28 +287,25 @@ public class DesignPanel( private void DrawMetaApplication() { - using var id = ImRaii.PushId("Meta"); - const uint all = 0x0Fu; - var flags = (_selector.Selected!.DoApplyHatVisible() ? 0x01u : 0x00) - | (_selector.Selected!.DoApplyVisorToggle() ? 0x02u : 0x00) - | (_selector.Selected!.DoApplyWeaponVisible() ? 0x04u : 0x00) - | (_selector.Selected!.DoApplyWetness() ? 0x08u : 0x00); - var bigChange = ImGui.CheckboxFlags("Apply All Meta Changes", ref flags, all); - var apply = bigChange ? (flags & 0x01) == 0x01 : _selector.Selected!.DoApplyHatVisible(); - if (ImGui.Checkbox("Apply Hat Visibility", ref apply) || bigChange) - _manager.ChangeApplyMeta(_selector.Selected!, MetaIndex.HatState, apply); + using var id = ImRaii.PushId("Meta"); + const uint all = (uint)MetaExtensions.All; + var flags = (uint)_selector.Selected!.ApplyMeta; + var bigChange = ImGui.CheckboxFlags("Apply All Meta Changes", ref flags, all); - apply = bigChange ? (flags & 0x02) == 0x02 : _selector.Selected!.DoApplyVisorToggle(); - if (ImGui.Checkbox("Apply Visor State", ref apply) || bigChange) - _manager.ChangeApplyMeta(_selector.Selected!, MetaIndex.VisorState, apply); + var labels = new[] + { + "Apply Hat Visibility", + "Apply Visor State", + "Apply Weapon Visibility", + "Apply Wetness", + }; - apply = bigChange ? (flags & 0x04) == 0x04 : _selector.Selected!.DoApplyWeaponVisible(); - if (ImGui.Checkbox("Apply Weapon Visibility", ref apply) || bigChange) - _manager.ChangeApplyMeta(_selector.Selected!, MetaIndex.WeaponState, apply); - - apply = bigChange ? (flags & 0x08) == 0x08 : _selector.Selected!.DoApplyWetness(); - if (ImGui.Checkbox("Apply Wetness", ref apply) || bigChange) - _manager.ChangeApplyMeta(_selector.Selected!, MetaIndex.Wetness, apply); + foreach (var (index, label) in MetaExtensions.AllRelevant.Zip(labels)) + { + var apply = bigChange ? ((MetaFlag)flags).HasFlag(index.ToFlag()) : _selector.Selected!.DoApplyMeta(index); + if (ImGui.Checkbox(label, ref apply) || bigChange) + _manager.ChangeApplyMeta(_selector.Selected!, MetaIndex.HatState, apply); + } } private void DrawParameterApplication() @@ -442,7 +439,7 @@ public class DesignPanel( { var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags(); using var _ = _selector.Selected!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest, applyParameters); - _state.ApplyDesign(_selector.Selected!, state, StateChanged.Source.Manual); + _state.ApplyDesign(_selector.Selected!, state, StateSource.Manual); } } @@ -461,7 +458,7 @@ public class DesignPanel( { var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags(); using var _ = _selector.Selected!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest, applyParameters); - _state.ApplyDesign(_selector.Selected!, state, StateChanged.Source.Manual); + _state.ApplyDesign(_selector.Selected!, state, StateSource.Manual); } } diff --git a/Glamourer/Gui/Tabs/NpcTab/NpcPanel.cs b/Glamourer/Gui/Tabs/NpcTab/NpcPanel.cs index 24382d5..829a681 100644 --- a/Glamourer/Gui/Tabs/NpcTab/NpcPanel.cs +++ b/Glamourer/Gui/Tabs/NpcTab/NpcPanel.cs @@ -202,7 +202,7 @@ public class NpcPanel( { var (applyGear, applyCustomize, _, _) = UiHelpers.ConvertKeysToFlags(); var design = _converter.Convert(ToDesignData(), applyGear, applyCustomize, 0, 0); - _state.ApplyDesign(design, state, StateChanged.Source.Manual); + _state.ApplyDesign(design, state, StateSource.Manual); } } @@ -221,7 +221,7 @@ public class NpcPanel( { var (applyGear, applyCustomize, _, _) = UiHelpers.ConvertKeysToFlags(); var design = _converter.Convert(ToDesignData(), applyGear, applyCustomize, 0, 0); - _state.ApplyDesign(design, state, StateChanged.Source.Manual); + _state.ApplyDesign(design, state, StateSource.Manual); } } diff --git a/Glamourer/Gui/ToggleDrawData.cs b/Glamourer/Gui/ToggleDrawData.cs index bb834a4..5758229 100644 --- a/Glamourer/Gui/ToggleDrawData.cs +++ b/Glamourer/Gui/ToggleDrawData.cs @@ -1,5 +1,4 @@ using Glamourer.Designs; -using Glamourer.Events; using Glamourer.State; using Penumbra.GameData.Enums; @@ -23,32 +22,17 @@ public ref struct ToggleDrawData { } public static ToggleDrawData FromDesign(MetaIndex index, DesignManager manager, Design design) - { - var (label, value, apply, setValue, setApply) = index switch + => new() { - MetaIndex.HatState => ("Hat Visible", design.DesignData.IsHatVisible(), design.DoApplyHatVisible(), - (Action)(b => manager.ChangeMeta(design, index, b)), (Action)(b => manager.ChangeApplyMeta(design, index, b))), - MetaIndex.VisorState => ("Visor Toggled", design.DesignData.IsVisorToggled(), design.DoApplyVisorToggle(), - b => manager.ChangeMeta(design, index, b), b => manager.ChangeApplyMeta(design, index, b)), - MetaIndex.WeaponState => ("Weapon Visible", design.DesignData.IsWeaponVisible(), design.DoApplyWeaponVisible(), - b => manager.ChangeMeta(design, index, b), b => manager.ChangeApplyMeta(design, index, b)), - MetaIndex.Wetness => ("Force Wetness", design.DesignData.IsWet(), design.DoApplyWetness(), - b => manager.ChangeMeta(design, index, b), b => manager.ChangeApplyMeta(design, index, b)), - _ => throw new Exception("Unsupported meta index."), - }; - - return new ToggleDrawData - { - Label = label, + Label = index.ToName(), Tooltip = string.Empty, Locked = design.WriteProtected(), DisplayApplication = true, - CurrentValue = value, - CurrentApply = apply, - SetValue = setValue, - SetApply = setApply, + CurrentValue = design.DesignData.GetMeta(index), + CurrentApply = design.DoApplyMeta(index), + SetValue = b => manager.ChangeMeta(design, index, b), + SetApply = b => manager.ChangeApplyMeta(design, index, b), }; - } public static ToggleDrawData CrestFromDesign(CrestFlag slot, DesignManager manager, Design design) => new() @@ -70,52 +54,27 @@ public ref struct ToggleDrawData Tooltip = "Hide or show your free company crest on this piece of gear.", Locked = state.IsLocked, CurrentValue = state.ModelData.Crest(slot), - SetValue = v => manager.ChangeCrest(state, slot, v, StateChanged.Source.Manual), + SetValue = v => manager.ChangeCrest(state, slot, v, StateSource.Manual), }; public static ToggleDrawData FromState(MetaIndex index, StateManager manager, ActorState state) { - var (label, tooltip, value, setValue) = index switch - { - MetaIndex.HatState => ("Hat Visible", "Hide or show the characters head gear.", state.ModelData.IsHatVisible(), - (Action)(b => manager.ChangeHatState(state, b, StateChanged.Source.Manual))), - MetaIndex.VisorState => ("Visor Toggled", "Toggle the visor state of the characters head gear.", - state.ModelData.IsVisorToggled(), - b => manager.ChangeVisorState(state, b, StateChanged.Source.Manual)), - MetaIndex.WeaponState => ("Weapon Visible", "Hide or show the characters weapons when not drawn.", - state.ModelData.IsWeaponVisible(), - b => manager.ChangeWeaponState(state, b, StateChanged.Source.Manual)), - MetaIndex.Wetness => ("Force Wetness", "Force the character to be wet or not.", state.ModelData.IsWet(), - b => manager.ChangeWetness(state, b, StateChanged.Source.Manual)), - _ => throw new Exception("Unsupported meta index."), - }; - return new ToggleDrawData { - Label = label, - Tooltip = tooltip, + Label = index.ToName(), + Tooltip = index.ToTooltip(), Locked = state.IsLocked, - CurrentValue = value, - SetValue = setValue, + CurrentValue = state.ModelData.GetMeta(index), + SetValue = b => manager.ChangeMeta(state, index, b, StateSource.Manual), }; } public static ToggleDrawData FromValue(MetaIndex index, bool value) - { - var (label, tooltip) = index switch + => new() { - MetaIndex.HatState => ("Hat Visible", "Hide or show the characters head gear."), - MetaIndex.VisorState => ("Visor Toggled", "Toggle the visor state of the characters head gear."), - MetaIndex.WeaponState => ("Weapon Visible", "Hide or show the characters weapons when not drawn."), - MetaIndex.Wetness => ("Force Wetness", "Force the character to be wet or not."), - _ => throw new Exception("Unsupported meta index."), - }; - return new ToggleDrawData - { - Label = label, - Tooltip = tooltip, + Label = index.ToName(), + Tooltip = index.ToTooltip(), Locked = true, CurrentValue = value, }; - } } diff --git a/Glamourer/Interop/ContextMenuService.cs b/Glamourer/Interop/ContextMenuService.cs index 228eda7..6bdac74 100644 --- a/Glamourer/Interop/ContextMenuService.cs +++ b/Glamourer/Interop/ContextMenuService.cs @@ -118,14 +118,14 @@ public class ContextMenuService : IDisposable return; var slot = item.Type.ToSlot(); - _state.ChangeEquip(state, slot, item, 0, StateChanged.Source.Manual); + _state.ChangeEquip(state, slot, item, 0, StateSource.Manual); if (item.Type.ValidOffhand().IsOffhandType()) { if (item.PrimaryId.Id is > 1600 and < 1651 && _items.ItemData.TryGetValue(item.ItemId, EquipSlot.Hands, out var gauntlets)) - _state.ChangeEquip(state, EquipSlot.Hands, gauntlets, 0, StateChanged.Source.Manual); + _state.ChangeEquip(state, EquipSlot.Hands, gauntlets, 0, StateSource.Manual); if (_items.ItemData.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand)) - _state.ChangeEquip(state, EquipSlot.OffHand, offhand, 0, StateChanged.Source.Manual); + _state.ChangeEquip(state, EquipSlot.OffHand, offhand, 0, StateSource.Manual); } }; } @@ -142,14 +142,14 @@ public class ContextMenuService : IDisposable return; var slot = item.Type.ToSlot(); - _state.ChangeEquip(state, slot, item, 0, StateChanged.Source.Manual); + _state.ChangeEquip(state, slot, item, 0, StateSource.Manual); if (item.Type.ValidOffhand().IsOffhandType()) { if (item.PrimaryId.Id is > 1600 and < 1651 && _items.ItemData.TryGetValue(item.ItemId, EquipSlot.Hands, out var gauntlets)) - _state.ChangeEquip(state, EquipSlot.Hands, gauntlets, 0, StateChanged.Source.Manual); + _state.ChangeEquip(state, EquipSlot.Hands, gauntlets, 0, StateSource.Manual); if (_items.ItemData.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand)) - _state.ChangeEquip(state, EquipSlot.OffHand, offhand, 0, StateChanged.Source.Manual); + _state.ChangeEquip(state, EquipSlot.OffHand, offhand, 0, StateSource.Manual); } }; } diff --git a/Glamourer/Services/CommandService.cs b/Glamourer/Services/CommandService.cs index f659847..41a2052 100644 --- a/Glamourer/Services/CommandService.cs +++ b/Glamourer/Services/CommandService.cs @@ -333,7 +333,7 @@ public class CommandService : IDisposable foreach (var identifier in identifiers) { if (_stateManager.TryGetValue(identifier, out var state)) - _stateManager.ResetState(state, StateChanged.Source.Manual); + _stateManager.ResetState(state, StateSource.Manual); } @@ -419,7 +419,7 @@ public class CommandService : IDisposable if (!_objects.TryGetValue(identifier, out var actors)) { if (_stateManager.TryGetValue(identifier, out var state)) - _stateManager.ApplyDesign(design, state, StateChanged.Source.Manual); + _stateManager.ApplyDesign(design, state, StateSource.Manual); } else { @@ -428,7 +428,7 @@ public class CommandService : IDisposable if (_stateManager.GetOrCreate(actor.GetIdentifier(_actors), actor, out var state)) { ApplyModSettings(design, actor, applyMods); - _stateManager.ApplyDesign(design, state, StateChanged.Source.Manual); + _stateManager.ApplyDesign(design, state, StateSource.Manual); } } } diff --git a/Glamourer/State/ActorState.cs b/Glamourer/State/ActorState.cs index 83b22ac..0b3204f 100644 --- a/Glamourer/State/ActorState.cs +++ b/Glamourer/State/ActorState.cs @@ -68,13 +68,13 @@ public class ActorState => Unlock(1337); /// This contains whether a change to the base data was made by the game, the user via manual input or through automatic application. - public readonly StateSource Source = new(); + public StateSources Sources = new(); internal ActorState(ActorIdentifier identifier) => Identifier = identifier.CreatePermanent(); public CustomizeParameterFlag OnlyChangedParameters() - => CustomizeParameterExtensions.AllFlags.Where(f => Source[f] is not StateChanged.Source.Game) + => CustomizeParameterExtensions.AllFlags.Where(f => Sources[f] is not StateSource.Game) .Aggregate((CustomizeParameterFlag)0, (a, b) => a | b); public bool UpdateTerritory(ushort territory) diff --git a/Glamourer/State/StateApplier.cs b/Glamourer/State/StateApplier.cs index d497006..906beb6 100644 --- a/Glamourer/State/StateApplier.cs +++ b/Glamourer/State/StateApplier.cs @@ -1,4 +1,5 @@ -using Glamourer.Events; +using Glamourer.Designs; +using Glamourer.Events; using Glamourer.GameData; using Glamourer.Interop; using Glamourer.Interop.Penumbra; @@ -118,7 +119,7 @@ public class StateApplier( // If the source is not IPC we do not want to apply restrictions. var data = GetData(state); if (apply) - ChangeArmor(data, slot, state.ModelData.Armor(slot), state.Source[slot, false] is not StateChanged.Source.Ipc, + ChangeArmor(data, slot, state.ModelData.Armor(slot), state.Sources[slot, false] is not StateSource.Ipc, state.ModelData.IsHatVisible()); return data; @@ -200,67 +201,44 @@ public class StateApplier( _weapon.LoadWeapon(actor, EquipSlot.OffHand, weapon.Weapon().With(stain)); } - /// Change the visor state of actors only on the draw object. - public void ChangeVisor(ActorData data, bool value) + /// Change a meta state. + public unsafe void ChangeMetaState(ActorData data, MetaIndex index, bool value) { - foreach (var actor in data.Objects.Where(a => a.Model.IsHuman)) - _visor.SetVisorState(actor.Model, value); + switch (index) + { + case MetaIndex.Wetness: + { + foreach (var actor in data.Objects.Where(a => a.IsCharacter)) + actor.AsCharacter->IsGPoseWet = value; + return; + } + case MetaIndex.HatState: + { + foreach (var actor in data.Objects.Where(a => a.IsCharacter)) + _metaService.SetHatState(actor, value); + return; + } + case MetaIndex.WeaponState: + { + foreach (var actor in data.Objects.Where(a => a.IsCharacter)) + _metaService.SetWeaponState(actor, value); + return; + } + case MetaIndex.VisorState: + { + foreach (var actor in data.Objects.Where(a => a.Model.IsHuman)) + _visor.SetVisorState(actor.Model, value); + return; + } + } } - /// - public ActorData ChangeVisor(ActorState state, bool apply) + /// + public ActorData ChangeMetaState(ActorState state, MetaIndex index, bool apply) { var data = GetData(state); if (apply) - ChangeVisor(data, state.ModelData.IsVisorToggled()); - return data; - } - - /// Change the forced wetness state on actors. - public unsafe void ChangeWetness(ActorData data, bool value) - { - foreach (var actor in data.Objects.Where(a => a.IsCharacter)) - actor.AsCharacter->IsGPoseWet = value; - } - - /// - public ActorData ChangeWetness(ActorState state, bool apply) - { - var data = GetData(state); - if (apply) - ChangeWetness(data, state.ModelData.IsWet()); - return data; - } - - /// Change the hat-visibility state on actors. - public void ChangeHatState(ActorData data, bool value) - { - foreach (var actor in data.Objects.Where(a => a.IsCharacter)) - _metaService.SetHatState(actor, value); - } - - /// - public ActorData ChangeHatState(ActorState state, bool apply) - { - var data = GetData(state); - if (apply) - ChangeHatState(data, state.ModelData.IsHatVisible()); - return data; - } - - /// Change the weapon-visibility state on actors. - public void ChangeWeaponState(ActorData data, bool value) - { - foreach (var actor in data.Objects.Where(a => a.IsCharacter)) - _metaService.SetWeaponState(actor, value); - } - - /// - public ActorData ChangeWeaponState(ActorState state, bool apply) - { - var data = GetData(state); - if (apply) - ChangeWeaponState(data, state.ModelData.IsWeaponVisible()); + ChangeMetaState(data, index, state.ModelData.GetMeta(index)); return data; } diff --git a/Glamourer/State/StateEditor.cs b/Glamourer/State/StateEditor.cs index abb3716..403c106 100644 --- a/Glamourer/State/StateEditor.cs +++ b/Glamourer/State/StateEditor.cs @@ -13,7 +13,7 @@ public class StateEditor(CustomizeService customizations, HumanModelList humans, { /// Change the model id. If the actor is changed from a human to another human, customize and equipData are unused. /// We currently only allow changing things to humans, not humans to monsters. - public bool ChangeModelId(ActorState state, uint modelId, in CustomizeArray customize, nint equipData, StateChanged.Source source, + public bool ChangeModelId(ActorState state, uint modelId, in CustomizeArray customize, nint equipData, StateSource source, out uint oldModelId, uint key = 0) { oldModelId = state.ModelData.ModelId; @@ -45,21 +45,21 @@ public class StateEditor(CustomizeService customizations, HumanModelList humans, state.ModelData.SetHatVisible(true); state.ModelData.SetWeaponVisible(true); state.ModelData.SetVisor(false); - state.Source[MetaIndex.ModelId] = source; - state.Source[MetaIndex.HatState] = source; - state.Source[MetaIndex.WeaponState] = source; - state.Source[MetaIndex.VisorState] = source; + state.Sources[MetaIndex.ModelId] = source; + state.Sources[MetaIndex.HatState] = source; + state.Sources[MetaIndex.WeaponState] = source; + state.Sources[MetaIndex.VisorState] = source; foreach (var slot in EquipSlotExtensions.FullSlots) { - state.Source[slot, true] = source; - state.Source[slot, false] = source; + state.Sources[slot, true] = source; + state.Sources[slot, false] = source; } - state.Source[CustomizeIndex.Clan] = source; - state.Source[CustomizeIndex.Gender] = source; + state.Sources[CustomizeIndex.Clan] = source; + state.Sources[CustomizeIndex.Gender] = source; var set = customizations.Manager.GetSet(state.ModelData.Customize.Clan, state.ModelData.Customize.Gender); foreach (var index in Enum.GetValues().Where(set.IsAvailable)) - state.Source[index] = source; + state.Sources[index] = source; } else { @@ -67,14 +67,14 @@ public class StateEditor(CustomizeService customizations, HumanModelList humans, return false; state.ModelData.LoadNonHuman(modelId, customize, equipData); - state.Source[MetaIndex.ModelId] = source; + state.Sources[MetaIndex.ModelId] = source; } return true; } /// Change a customization value. - public bool ChangeCustomize(ActorState state, CustomizeIndex idx, CustomizeValue value, StateChanged.Source source, + public bool ChangeCustomize(ActorState state, CustomizeIndex idx, CustomizeValue value, StateSource source, out CustomizeValue old, uint key = 0) { old = state.ModelData.Customize[idx]; @@ -82,12 +82,12 @@ public class StateEditor(CustomizeService customizations, HumanModelList humans, return false; state.ModelData.Customize[idx] = value; - state.Source[idx] = source; + state.Sources[idx] = source; return true; } /// Change an entire customization array according to flags. - public bool ChangeHumanCustomize(ActorState state, in CustomizeArray customizeInput, CustomizeFlag applyWhich, StateChanged.Source source, + public bool ChangeHumanCustomize(ActorState state, in CustomizeArray customizeInput, CustomizeFlag applyWhich, StateSource source, out CustomizeArray old, out CustomizeFlag changed, uint key = 0) { old = state.ModelData.Customize; @@ -104,14 +104,14 @@ public class StateEditor(CustomizeService customizations, HumanModelList humans, foreach (var type in Enum.GetValues()) { if (applied.HasFlag(type.ToFlag())) - state.Source[type] = source; + state.Sources[type] = source; } return true; } /// Change a single piece of equipment without stain. - public bool ChangeItem(ActorState state, EquipSlot slot, EquipItem item, StateChanged.Source source, out EquipItem oldItem, uint key = 0) + public bool ChangeItem(ActorState state, EquipSlot slot, EquipItem item, StateSource source, out EquipItem oldItem, uint key = 0) { oldItem = state.ModelData.Item(slot); if (!state.CanUnlock(key)) @@ -128,17 +128,17 @@ public class StateEditor(CustomizeService customizations, HumanModelList humans, gPose.AddActionOnLeave(() => { if (old.Type == state.BaseData.Item(slot).Type) - ChangeItem(state, slot, old, state.Source[slot, false], out _, key); + ChangeItem(state, slot, old, state.Sources[slot, false], out _, key); }); } state.ModelData.SetItem(slot, item); - state.Source[slot, false] = source; + state.Sources[slot, false] = source; return true; } /// Change a single piece of equipment including stain. - public bool ChangeEquip(ActorState state, EquipSlot slot, EquipItem item, StainId stain, StateChanged.Source source, out EquipItem oldItem, + public bool ChangeEquip(ActorState state, EquipSlot slot, EquipItem item, StainId stain, StateSource source, out EquipItem oldItem, out StainId oldStain, uint key = 0) { oldItem = state.ModelData.Item(slot); @@ -158,43 +158,43 @@ public class StateEditor(CustomizeService customizations, HumanModelList humans, gPose.AddActionOnLeave(() => { if (old.Type == state.BaseData.Item(slot).Type) - ChangeEquip(state, slot, old, oldS, state.Source[slot, false], out _, out _, key); + ChangeEquip(state, slot, old, oldS, state.Sources[slot, false], out _, out _, key); }); } state.ModelData.SetItem(slot, item); state.ModelData.SetStain(slot, stain); - state.Source[slot, false] = source; - state.Source[slot, true] = source; + state.Sources[slot, false] = source; + state.Sources[slot, true] = source; return true; } /// Change only the stain of an equipment piece. - public bool ChangeStain(ActorState state, EquipSlot slot, StainId stain, StateChanged.Source source, out StainId oldStain, uint key = 0) + public bool ChangeStain(ActorState state, EquipSlot slot, StainId stain, StateSource source, out StainId oldStain, uint key = 0) { oldStain = state.ModelData.Stain(slot); if (!state.CanUnlock(key)) return false; state.ModelData.SetStain(slot, stain); - state.Source[slot, true] = source; + state.Sources[slot, true] = source; return true; } /// Change the crest of an equipment piece. - public bool ChangeCrest(ActorState state, CrestFlag slot, bool crest, StateChanged.Source source, out bool oldCrest, uint key = 0) + public bool ChangeCrest(ActorState state, CrestFlag slot, bool crest, StateSource source, out bool oldCrest, uint key = 0) { oldCrest = state.ModelData.Crest(slot); if (!state.CanUnlock(key)) return false; state.ModelData.SetCrest(slot, crest); - state.Source[slot] = source; + state.Sources[slot] = source; return true; } /// Change the customize flags of a character. - public bool ChangeParameter(ActorState state, CustomizeParameterFlag flag, CustomizeParameterValue value, StateChanged.Source source, + public bool ChangeParameter(ActorState state, CustomizeParameterFlag flag, CustomizeParameterValue value, StateSource source, out CustomizeParameterValue oldValue, uint key = 0) { oldValue = state.ModelData.Parameters[flag]; @@ -202,29 +202,20 @@ public class StateEditor(CustomizeService customizations, HumanModelList humans, return false; state.ModelData.Parameters.Set(flag, value); - state.Source[flag] = source; + state.Sources[flag] = source; return true; } - public bool ChangeMetaState(ActorState state, MetaIndex index, bool value, StateChanged.Source source, out bool oldValue, + public bool ChangeMetaState(ActorState state, MetaIndex index, bool value, StateSource source, out bool oldValue, uint key = 0) { - (var setter, oldValue) = index switch - { - MetaIndex.Wetness => ((Func)(v => state.ModelData.SetIsWet(v)), state.ModelData.IsWet()), - MetaIndex.HatState => ((Func)(v => state.ModelData.SetHatVisible(v)), state.ModelData.IsHatVisible()), - MetaIndex.VisorState => ((Func)(v => state.ModelData.SetVisor(v)), state.ModelData.IsVisorToggled()), - MetaIndex.WeaponState => ((Func)(v => state.ModelData.SetWeaponVisible(v)), - state.ModelData.IsWeaponVisible()), - _ => throw new Exception("Invalid MetaIndex."), - }; - + oldValue = state.ModelData.GetMeta(index); if (!state.CanUnlock(key)) return false; - setter(value); - state.Source[index] = source; + state.ModelData.SetMeta(index, value); + state.Sources[index] = source; return true; } } diff --git a/Glamourer/State/StateIndex.cs b/Glamourer/State/StateIndex.cs new file mode 100644 index 0000000..906b003 --- /dev/null +++ b/Glamourer/State/StateIndex.cs @@ -0,0 +1,235 @@ +using Glamourer.Designs; +using Glamourer.GameData; +using Penumbra.GameData.Enums; + +namespace Glamourer.State; + +public readonly record struct StateIndex(int Value) : IEqualityOperators +{ + public static readonly StateIndex Invalid = new(-1); + + public static implicit operator StateIndex(EquipFlag flag) + => flag switch + { + EquipFlag.Head => new StateIndex(EquipHead), + EquipFlag.Body => new StateIndex(EquipBody), + EquipFlag.Hands => new StateIndex(EquipHands), + EquipFlag.Legs => new StateIndex(EquipLegs), + EquipFlag.Feet => new StateIndex(EquipFeet), + EquipFlag.Ears => new StateIndex(EquipEars), + EquipFlag.Neck => new StateIndex(EquipNeck), + EquipFlag.Wrist => new StateIndex(EquipWrist), + EquipFlag.RFinger => new StateIndex(EquipRFinger), + EquipFlag.LFinger => new StateIndex(EquipLFinger), + EquipFlag.Mainhand => new StateIndex(EquipMainhand), + EquipFlag.Offhand => new StateIndex(EquipOffhand), + EquipFlag.HeadStain => new StateIndex(StainHead), + EquipFlag.BodyStain => new StateIndex(StainBody), + EquipFlag.HandsStain => new StateIndex(StainHands), + EquipFlag.LegsStain => new StateIndex(StainLegs), + EquipFlag.FeetStain => new StateIndex(StainFeet), + EquipFlag.EarsStain => new StateIndex(StainEars), + EquipFlag.NeckStain => new StateIndex(StainNeck), + EquipFlag.WristStain => new StateIndex(StainWrist), + EquipFlag.RFingerStain => new StateIndex(StainRFinger), + EquipFlag.LFingerStain => new StateIndex(StainLFinger), + EquipFlag.MainhandStain => new StateIndex(StainMainhand), + EquipFlag.OffhandStain => new StateIndex(StainOffhand), + _ => Invalid, + }; + + public static implicit operator StateIndex(CustomizeIndex index) + => index switch + { + CustomizeIndex.Race => new StateIndex(CustomizeRace), + CustomizeIndex.Gender => new StateIndex(CustomizeGender), + CustomizeIndex.BodyType => new StateIndex(CustomizeBodyType), + CustomizeIndex.Height => new StateIndex(CustomizeHeight), + CustomizeIndex.Clan => new StateIndex(CustomizeClan), + CustomizeIndex.Face => new StateIndex(CustomizeFace), + CustomizeIndex.Hairstyle => new StateIndex(CustomizeHairstyle), + CustomizeIndex.Highlights => new StateIndex(CustomizeHighlights), + CustomizeIndex.SkinColor => new StateIndex(CustomizeSkinColor), + CustomizeIndex.EyeColorRight => new StateIndex(CustomizeEyeColorRight), + CustomizeIndex.HairColor => new StateIndex(CustomizeHairColor), + CustomizeIndex.HighlightsColor => new StateIndex(CustomizeHighlightsColor), + CustomizeIndex.FacialFeature1 => new StateIndex(CustomizeFacialFeature1), + CustomizeIndex.FacialFeature2 => new StateIndex(CustomizeFacialFeature2), + CustomizeIndex.FacialFeature3 => new StateIndex(CustomizeFacialFeature3), + CustomizeIndex.FacialFeature4 => new StateIndex(CustomizeFacialFeature4), + CustomizeIndex.FacialFeature5 => new StateIndex(CustomizeFacialFeature5), + CustomizeIndex.FacialFeature6 => new StateIndex(CustomizeFacialFeature6), + CustomizeIndex.FacialFeature7 => new StateIndex(CustomizeFacialFeature7), + CustomizeIndex.LegacyTattoo => new StateIndex(CustomizeLegacyTattoo), + CustomizeIndex.TattooColor => new StateIndex(CustomizeTattooColor), + CustomizeIndex.Eyebrows => new StateIndex(CustomizeEyebrows), + CustomizeIndex.EyeColorLeft => new StateIndex(CustomizeEyeColorLeft), + CustomizeIndex.EyeShape => new StateIndex(CustomizeEyeShape), + CustomizeIndex.SmallIris => new StateIndex(CustomizeSmallIris), + CustomizeIndex.Nose => new StateIndex(CustomizeNose), + CustomizeIndex.Jaw => new StateIndex(CustomizeJaw), + CustomizeIndex.Mouth => new StateIndex(CustomizeMouth), + CustomizeIndex.Lipstick => new StateIndex(CustomizeLipstick), + CustomizeIndex.LipColor => new StateIndex(CustomizeLipColor), + CustomizeIndex.MuscleMass => new StateIndex(CustomizeMuscleMass), + CustomizeIndex.TailShape => new StateIndex(CustomizeTailShape), + CustomizeIndex.BustSize => new StateIndex(CustomizeBustSize), + CustomizeIndex.FacePaint => new StateIndex(CustomizeFacePaint), + CustomizeIndex.FacePaintReversed => new StateIndex(CustomizeFacePaintReversed), + CustomizeIndex.FacePaintColor => new StateIndex(CustomizeFacePaintColor), + _ => Invalid, + }; + + public static implicit operator StateIndex(MetaIndex meta) + => new((int)meta); + + public static implicit operator StateIndex(CrestFlag crest) + => crest switch + { + CrestFlag.OffHand => new StateIndex(CrestOffhand), + CrestFlag.Head => new StateIndex(CrestHead), + CrestFlag.Body => new StateIndex(CrestBody), + _ => Invalid, + }; + + public static implicit operator StateIndex(CustomizeParameterFlag param) + => param switch + { + CustomizeParameterFlag.SkinDiffuse => new StateIndex(ParamSkinDiffuse), + CustomizeParameterFlag.MuscleTone => new StateIndex(ParamMuscleTone), + CustomizeParameterFlag.SkinSpecular => new StateIndex(ParamSkinSpecular), + CustomizeParameterFlag.LipDiffuse => new StateIndex(ParamLipDiffuse), + CustomizeParameterFlag.HairDiffuse => new StateIndex(ParamHairDiffuse), + CustomizeParameterFlag.HairSpecular => new StateIndex(ParamHairSpecular), + CustomizeParameterFlag.HairHighlight => new StateIndex(ParamHairHighlight), + CustomizeParameterFlag.LeftEye => new StateIndex(ParamLeftEye), + CustomizeParameterFlag.RightEye => new StateIndex(ParamRightEye), + CustomizeParameterFlag.FeatureColor => new StateIndex(ParamFeatureColor), + CustomizeParameterFlag.FacePaintUvMultiplier => new StateIndex(ParamFacePaintUvMultiplier), + CustomizeParameterFlag.FacePaintUvOffset => new StateIndex(ParamFacePaintUvOffset), + CustomizeParameterFlag.DecalColor => new StateIndex(ParamDecalColor), + _ => Invalid, + }; + + public const int EquipHead = 0; + public const int EquipBody = 1; + public const int EquipHands = 2; + public const int EquipLegs = 3; + public const int EquipFeet = 4; + public const int EquipEars = 5; + public const int EquipNeck = 6; + public const int EquipWrist = 7; + public const int EquipRFinger = 8; + public const int EquipLFinger = 9; + public const int EquipMainhand = 10; + public const int EquipOffhand = 11; + + public const int StainHead = 12; + public const int StainBody = 13; + public const int StainHands = 14; + public const int StainLegs = 15; + public const int StainFeet = 16; + public const int StainEars = 17; + public const int StainNeck = 18; + public const int StainWrist = 19; + public const int StainRFinger = 20; + public const int StainLFinger = 21; + public const int StainMainhand = 22; + public const int StainOffhand = 23; + + public const int CustomizeRace = 24; + public const int CustomizeGender = 25; + public const int CustomizeBodyType = 26; + public const int CustomizeHeight = 27; + public const int CustomizeClan = 28; + public const int CustomizeFace = 29; + public const int CustomizeHairstyle = 30; + public const int CustomizeHighlights = 31; + public const int CustomizeSkinColor = 32; + public const int CustomizeEyeColorRight = 33; + public const int CustomizeHairColor = 34; + public const int CustomizeHighlightsColor = 35; + public const int CustomizeFacialFeature1 = 36; + public const int CustomizeFacialFeature2 = 37; + public const int CustomizeFacialFeature3 = 38; + public const int CustomizeFacialFeature4 = 39; + public const int CustomizeFacialFeature5 = 40; + public const int CustomizeFacialFeature6 = 41; + public const int CustomizeFacialFeature7 = 42; + public const int CustomizeLegacyTattoo = 43; + public const int CustomizeTattooColor = 44; + public const int CustomizeEyebrows = 45; + public const int CustomizeEyeColorLeft = 46; + public const int CustomizeEyeShape = 47; + public const int CustomizeSmallIris = 48; + public const int CustomizeNose = 49; + public const int CustomizeJaw = 50; + public const int CustomizeMouth = 51; + public const int CustomizeLipstick = 52; + public const int CustomizeLipColor = 53; + public const int CustomizeMuscleMass = 54; + public const int CustomizeTailShape = 55; + public const int CustomizeBustSize = 56; + public const int CustomizeFacePaint = 57; + public const int CustomizeFacePaintReversed = 58; + public const int CustomizeFacePaintColor = 59; + + public const int MetaWetness = 60; + public const int MetaHatState = 61; + public const int MetaVisorState = 62; + public const int MetaWeaponState = 63; + public const int MetaModelId = 64; + + public const int CrestHead = 65; + public const int CrestBody = 66; + public const int CrestOffhand = 67; + + public const int ParamSkinDiffuse = 68; + public const int ParamMuscleTone = 69; + public const int ParamSkinSpecular = 70; + public const int ParamLipDiffuse = 71; + public const int ParamHairDiffuse = 72; + public const int ParamHairSpecular = 73; + public const int ParamHairHighlight = 74; + public const int ParamLeftEye = 75; + public const int ParamRightEye = 76; + public const int ParamFeatureColor = 77; + public const int ParamFacePaintUvMultiplier = 78; + public const int ParamFacePaintUvOffset = 79; + public const int ParamDecalColor = 80; + + public const int Size = 81; +} + +public static class StateExtensions +{ + public static StateIndex ToState(this EquipSlot slot, bool stain = false) + => (slot, stain) switch + { + (EquipSlot.Head, true) => new StateIndex(StateIndex.EquipHead), + (EquipSlot.Body, true) => new StateIndex(StateIndex.EquipBody), + (EquipSlot.Hands, true) => new StateIndex(StateIndex.EquipHands), + (EquipSlot.Legs, true) => new StateIndex(StateIndex.EquipLegs), + (EquipSlot.Feet, true) => new StateIndex(StateIndex.EquipFeet), + (EquipSlot.Ears, true) => new StateIndex(StateIndex.EquipEars), + (EquipSlot.Neck, true) => new StateIndex(StateIndex.EquipNeck), + (EquipSlot.Wrists, true) => new StateIndex(StateIndex.EquipWrist), + (EquipSlot.RFinger, true) => new StateIndex(StateIndex.EquipRFinger), + (EquipSlot.LFinger, true) => new StateIndex(StateIndex.EquipLFinger), + (EquipSlot.MainHand, true) => new StateIndex(StateIndex.EquipMainhand), + (EquipSlot.OffHand, true) => new StateIndex(StateIndex.EquipOffhand), + (EquipSlot.Head, false) => new StateIndex(StateIndex.StainHead), + (EquipSlot.Body, false) => new StateIndex(StateIndex.StainBody), + (EquipSlot.Hands, false) => new StateIndex(StateIndex.StainHands), + (EquipSlot.Legs, false) => new StateIndex(StateIndex.StainLegs), + (EquipSlot.Feet, false) => new StateIndex(StateIndex.StainFeet), + (EquipSlot.Ears, false) => new StateIndex(StateIndex.StainEars), + (EquipSlot.Neck, false) => new StateIndex(StateIndex.StainNeck), + (EquipSlot.Wrists, false) => new StateIndex(StateIndex.StainWrist), + (EquipSlot.RFinger, false) => new StateIndex(StateIndex.StainRFinger), + (EquipSlot.LFinger, false) => new StateIndex(StateIndex.StainLFinger), + (EquipSlot.MainHand, false) => new StateIndex(StateIndex.StainMainhand), + (EquipSlot.OffHand, false) => new StateIndex(StateIndex.StainOffhand), + _ => StateIndex.Invalid, + }; +} diff --git a/Glamourer/State/StateListener.cs b/Glamourer/State/StateListener.cs index a8c8dd5..09c0673 100644 --- a/Glamourer/State/StateListener.cs +++ b/Glamourer/State/StateListener.cs @@ -164,21 +164,21 @@ public class StateListener : IDisposable var model = state.ModelData.Customize; if (customize.Gender != model.Gender || customize.Clan != model.Clan) { - _manager.ChangeCustomize(state, in customize, CustomizeFlagExtensions.AllRelevant, StateChanged.Source.Game); + _manager.ChangeCustomize(state, in customize, CustomizeFlagExtensions.AllRelevant, StateSource.Game); return; } var set = _customizations.Manager.GetSet(model.Clan, model.Gender); foreach (var index in CustomizationExtensions.AllBasic) { - if (state.Source[index] is not StateChanged.Source.Fixed) + if (state.Sources[index] is not StateSource.Fixed) { var newValue = customize[index]; var oldValue = model[index]; if (newValue != oldValue) { if (set.Validate(index, newValue, out _, model.Face)) - _manager.ChangeCustomize(state, index, newValue, StateChanged.Source.Game); + _manager.ChangeCustomize(state, index, newValue, StateSource.Game); else customize[index] = oldValue; } @@ -214,7 +214,7 @@ public class StateListener : IDisposable && _manager.TryGetValue(identifier, out var state)) { HandleEquipSlot(actor, state, slot, ref armor); - locked = state.Source[slot, false] is StateChanged.Source.Ipc; + locked = state.Sources[slot, false] is StateSource.Ipc; } _funModule.ApplyFunToSlot(actor, ref armor, slot); @@ -241,10 +241,10 @@ public class StateListener : IDisposable continue; var changed = changedItem.Weapon(stain); - if (current.Value == changed.Value && state.Source[slot, false] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc) + if (current.Value == changed.Value && state.Sources[slot, false] is not StateSource.Fixed and not StateSource.Ipc) { - _manager.ChangeItem(state, slot, currentItem, StateChanged.Source.Game); - _manager.ChangeStain(state, slot, current.Stain, StateChanged.Source.Game); + _manager.ChangeItem(state, slot, currentItem, StateSource.Game); + _manager.ChangeStain(state, slot, current.Stain, StateSource.Game); switch (slot) { case EquipSlot.MainHand: @@ -252,7 +252,7 @@ public class StateListener : IDisposable _applier.ChangeWeapon(objects, slot, currentItem, stain); break; default: - _applier.ChangeArmor(objects, slot, current.ToArmor(), state.Source[slot, false] is not StateChanged.Source.Ipc, + _applier.ChangeArmor(objects, slot, current.ToArmor(), state.Sources[slot, false] is not StateSource.Ipc, state.ModelData.IsHatVisible()); break; } @@ -286,13 +286,13 @@ public class StateListener : IDisposable // Do nothing. But this usually can not happen because the hooked function also writes to game objects later. case UpdateState.Transformed: break; case UpdateState.Change: - if (state.Source[slot, false] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc) - _manager.ChangeItem(state, slot, state.BaseData.Item(slot), StateChanged.Source.Game); + if (state.Sources[slot, false] is not StateSource.Fixed and not StateSource.Ipc) + _manager.ChangeItem(state, slot, state.BaseData.Item(slot), StateSource.Game); else apply = true; - if (state.Source[slot, true] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc) - _manager.ChangeStain(state, slot, state.BaseData.Stain(slot), StateChanged.Source.Game); + if (state.Sources[slot, true] is not StateSource.Fixed and not StateSource.Ipc) + _manager.ChangeStain(state, slot, state.BaseData.Stain(slot), StateSource.Game); else apply = true; break; @@ -385,13 +385,13 @@ public class StateListener : IDisposable // Update model state if not on fixed design. case UpdateState.Change: var apply = false; - if (state.Source[slot, false] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc) - _manager.ChangeItem(state, slot, state.BaseData.Item(slot), StateChanged.Source.Game); + if (state.Sources[slot, false] is not StateSource.Fixed and not StateSource.Ipc) + _manager.ChangeItem(state, slot, state.BaseData.Item(slot), StateSource.Game); else apply = true; - if (state.Source[slot, true] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc) - _manager.ChangeStain(state, slot, state.BaseData.Stain(slot), StateChanged.Source.Game); + if (state.Sources[slot, true] is not StateSource.Fixed and not StateSource.Ipc) + _manager.ChangeStain(state, slot, state.BaseData.Stain(slot), StateSource.Game); else apply = true; @@ -419,8 +419,8 @@ public class StateListener : IDisposable switch (UpdateBaseCrest(actor, state, slot, value)) { case UpdateState.Change: - if (state.Source[slot] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc) - _manager.ChangeCrest(state, slot, state.BaseData.Crest(slot), StateChanged.Source.Game); + if (state.Sources[slot] is not StateSource.Fixed and not StateSource.Ipc) + _manager.ChangeCrest(state, slot, state.BaseData.Crest(slot), StateSource.Game); else value = state.ModelData.Crest(slot); break; @@ -565,10 +565,10 @@ public class StateListener : IDisposable { // if base state changed, either overwrite the actual value if we have fixed values, // or overwrite the stored model state with the new one. - if (state.Source[MetaIndex.VisorState] is StateChanged.Source.Fixed or StateChanged.Source.Ipc) + if (state.Sources[MetaIndex.VisorState] is StateSource.Fixed or StateSource.Ipc) value = state.ModelData.IsVisorToggled(); else - _manager.ChangeVisorState(state, value, StateChanged.Source.Game); + _manager.ChangeMeta(state, MetaIndex.VisorState, value, StateSource.Game); } else { @@ -598,10 +598,10 @@ public class StateListener : IDisposable { // if base state changed, either overwrite the actual value if we have fixed values, // or overwrite the stored model state with the new one. - if (state.Source[MetaIndex.HatState] is StateChanged.Source.Fixed or StateChanged.Source.Ipc) + if (state.Sources[MetaIndex.HatState] is StateSource.Fixed or StateSource.Ipc) value = state.ModelData.IsHatVisible(); else - _manager.ChangeHatState(state, value, StateChanged.Source.Game); + _manager.ChangeMeta(state, MetaIndex.HatState, value, StateSource.Game); } else { @@ -631,10 +631,10 @@ public class StateListener : IDisposable { // if base state changed, either overwrite the actual value if we have fixed values, // or overwrite the stored model state with the new one. - if (state.Source[MetaIndex.WeaponState] is StateChanged.Source.Fixed or StateChanged.Source.Ipc) + if (state.Sources[MetaIndex.WeaponState] is StateSource.Fixed or StateSource.Ipc) value = state.ModelData.IsWeaponVisible(); else - _manager.ChangeWeaponState(state, value, StateChanged.Source.Game); + _manager.ChangeMeta(state, MetaIndex.WeaponState, value, StateSource.Game); } else { @@ -700,9 +700,9 @@ public class StateListener : IDisposable return; var data = new ActorData(gameObject, _creatingIdentifier.ToName()); - _applier.ChangeHatState(data, _creatingState.ModelData.IsHatVisible()); - _applier.ChangeWeaponState(data, _creatingState.ModelData.IsWeaponVisible()); - _applier.ChangeWetness(data, _creatingState.ModelData.IsWet()); + _applier.ChangeMetaState(data, MetaIndex.HatState, _creatingState.ModelData.IsHatVisible()); + _applier.ChangeMetaState(data, MetaIndex.Wetness, _creatingState.ModelData.IsWet()); + _applier.ChangeMetaState(data, MetaIndex.WeaponState, _creatingState.ModelData.IsWeaponVisible()); ApplyParameters(_creatingState, drawObject); } @@ -733,30 +733,30 @@ public class StateListener : IDisposable foreach (var flag in CustomizeParameterExtensions.AllFlags) { var newValue = data[flag]; - switch (state.Source[flag]) + switch (state.Sources[flag]) { - case StateChanged.Source.Game: + case StateSource.Game: if (state.BaseData.Parameters.Set(flag, newValue)) - _manager.ChangeCustomizeParameter(state, flag, newValue, StateChanged.Source.Game); + _manager.ChangeCustomizeParameter(state, flag, newValue, StateSource.Game); break; - case StateChanged.Source.Manual: + case StateSource.Manual: if (state.BaseData.Parameters.Set(flag, newValue)) - _manager.ChangeCustomizeParameter(state, flag, newValue, StateChanged.Source.Game); + _manager.ChangeCustomizeParameter(state, flag, newValue, StateSource.Game); else if (_config.UseAdvancedParameters) model.ApplySingleParameterData(flag, state.ModelData.Parameters); break; - case StateChanged.Source.Fixed: + case StateSource.Fixed: state.BaseData.Parameters.Set(flag, newValue); if (_config.UseAdvancedParameters) model.ApplySingleParameterData(flag, state.ModelData.Parameters); break; - case StateChanged.Source.Ipc: + case StateSource.Ipc: state.BaseData.Parameters.Set(flag, newValue); model.ApplySingleParameterData(flag, state.ModelData.Parameters); break; - case StateChanged.Source.Pending: + case StateSource.Pending: state.BaseData.Parameters.Set(flag, newValue); - state.Source[flag] = StateChanged.Source.Manual; + state.Sources[flag] = StateSource.Manual; if (_config.UseAdvancedParameters) model.ApplySingleParameterData(flag, state.ModelData.Parameters); break; diff --git a/Glamourer/State/StateManager.cs b/Glamourer/State/StateManager.cs index 89b8c24..4ccf42c 100644 --- a/Glamourer/State/StateManager.cs +++ b/Glamourer/State/StateManager.cs @@ -207,58 +207,58 @@ public class StateManager( #region Change Values /// Turn an actor human. - public void TurnHuman(ActorState state, StateChanged.Source source, uint key = 0) + public void TurnHuman(ActorState state, StateSource source, uint key = 0) => ChangeModelId(state, 0, CustomizeArray.Default, nint.Zero, source, key); /// Turn an actor to. - public void ChangeModelId(ActorState state, uint modelId, CustomizeArray customize, nint equipData, StateChanged.Source source, + public void ChangeModelId(ActorState state, uint modelId, CustomizeArray customize, nint equipData, StateSource source, uint key = 0) { if (!_editor.ChangeModelId(state, modelId, customize, equipData, source, out var old, key)) return; - var actors = _applier.ForceRedraw(state, source is StateChanged.Source.Manual or StateChanged.Source.Ipc); + var actors = _applier.ForceRedraw(state, source is StateSource.Manual or StateSource.Ipc); Glamourer.Log.Verbose( $"Set model id in state {state.Identifier.Incognito(null)} from {old} to {modelId}. [Affecting {actors.ToLazyString("nothing")}.]"); _event.Invoke(StateChanged.Type.Model, source, state, actors, (old, modelId)); } /// Change a customization value. - public void ChangeCustomize(ActorState state, CustomizeIndex idx, CustomizeValue value, StateChanged.Source source, uint key = 0) + public void ChangeCustomize(ActorState state, CustomizeIndex idx, CustomizeValue value, StateSource source, uint key = 0) { if (!_editor.ChangeCustomize(state, idx, value, source, out var old, key)) return; - var actors = _applier.ChangeCustomize(state, source is StateChanged.Source.Manual or StateChanged.Source.Ipc); + var actors = _applier.ChangeCustomize(state, source is StateSource.Manual or StateSource.Ipc); Glamourer.Log.Verbose( $"Set {idx.ToDefaultName()} customizations in state {state.Identifier.Incognito(null)} from {old.Value} to {value.Value}. [Affecting {actors.ToLazyString("nothing")}.]"); _event.Invoke(StateChanged.Type.Customize, source, state, actors, (old, value, idx)); } /// Change an entire customization array according to flags. - public void ChangeCustomize(ActorState state, in CustomizeArray customizeInput, CustomizeFlag apply, StateChanged.Source source, + public void ChangeCustomize(ActorState state, in CustomizeArray customizeInput, CustomizeFlag apply, StateSource source, uint key = 0) { if (!_editor.ChangeHumanCustomize(state, customizeInput, apply, source, out var old, out var applied, key)) return; - var actors = _applier.ChangeCustomize(state, source is StateChanged.Source.Manual or StateChanged.Source.Ipc); + var actors = _applier.ChangeCustomize(state, source is StateSource.Manual or StateSource.Ipc); Glamourer.Log.Verbose( $"Set {applied} customizations in state {state.Identifier.Incognito(null)} from {old} to {customizeInput}. [Affecting {actors.ToLazyString("nothing")}.]"); _event.Invoke(StateChanged.Type.EntireCustomize, source, state, actors, (old, applied)); } /// Change a single piece of equipment without stain. - /// Do not use this in the same frame as ChangeStain, use instead. - public void ChangeItem(ActorState state, EquipSlot slot, EquipItem item, StateChanged.Source source, uint key = 0) + /// Do not use this in the same frame as ChangeStain, use instead. + public void ChangeItem(ActorState state, EquipSlot slot, EquipItem item, StateSource source, uint key = 0) { if (!_editor.ChangeItem(state, slot, item, source, out var old, key)) return; var type = slot.ToIndex() < 10 ? StateChanged.Type.Equip : StateChanged.Type.Weapon; var actors = type is StateChanged.Type.Equip - ? _applier.ChangeArmor(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc) - : _applier.ChangeWeapon(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc, + ? _applier.ChangeArmor(state, slot, source is StateSource.Manual or StateSource.Ipc) + : _applier.ChangeWeapon(state, slot, source is StateSource.Manual or StateSource.Ipc, item.Type != (slot is EquipSlot.MainHand ? state.BaseData.MainhandType : state.BaseData.OffhandType)); Glamourer.Log.Verbose( $"Set {slot.ToName()} in state {state.Identifier.Incognito(null)} from {old.Name} ({old.ItemId}) to {item.Name} ({item.ItemId}). [Affecting {actors.ToLazyString("nothing")}.]"); @@ -266,15 +266,15 @@ public class StateManager( } /// Change a single piece of equipment including stain. - public void ChangeEquip(ActorState state, EquipSlot slot, EquipItem item, StainId stain, StateChanged.Source source, uint key = 0) + public void ChangeEquip(ActorState state, EquipSlot slot, EquipItem item, StainId stain, StateSource source, uint key = 0) { if (!_editor.ChangeEquip(state, slot, item, stain, source, out var old, out var oldStain, key)) return; var type = slot.ToIndex() < 10 ? StateChanged.Type.Equip : StateChanged.Type.Weapon; var actors = type is StateChanged.Type.Equip - ? _applier.ChangeArmor(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc) - : _applier.ChangeWeapon(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc, + ? _applier.ChangeArmor(state, slot, source is StateSource.Manual or StateSource.Ipc) + : _applier.ChangeWeapon(state, slot, source is StateSource.Manual or StateSource.Ipc, item.Type != (slot is EquipSlot.MainHand ? state.BaseData.MainhandType : state.BaseData.OffhandType)); Glamourer.Log.Verbose( $"Set {slot.ToName()} in state {state.Identifier.Incognito(null)} from {old.Name} ({old.ItemId}) to {item.Name} ({item.ItemId}) and its stain from {oldStain.Id} to {stain.Id}. [Affecting {actors.ToLazyString("nothing")}.]"); @@ -283,25 +283,25 @@ public class StateManager( } /// Change only the stain of an equipment piece. - /// Do not use this in the same frame as ChangeEquip, use instead. - public void ChangeStain(ActorState state, EquipSlot slot, StainId stain, StateChanged.Source source, uint key = 0) + /// Do not use this in the same frame as ChangeEquip, use instead. + public void ChangeStain(ActorState state, EquipSlot slot, StainId stain, StateSource source, uint key = 0) { if (!_editor.ChangeStain(state, slot, stain, source, out var old, key)) return; - var actors = _applier.ChangeStain(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc); + var actors = _applier.ChangeStain(state, slot, source is StateSource.Manual or StateSource.Ipc); Glamourer.Log.Verbose( $"Set {slot.ToName()} stain in state {state.Identifier.Incognito(null)} from {old.Id} to {stain.Id}. [Affecting {actors.ToLazyString("nothing")}.]"); _event.Invoke(StateChanged.Type.Stain, source, state, actors, (old, stain, slot)); } /// Change the crest of an equipment piece. - public void ChangeCrest(ActorState state, CrestFlag slot, bool crest, StateChanged.Source source, uint key = 0) + public void ChangeCrest(ActorState state, CrestFlag slot, bool crest, StateSource source, uint key = 0) { if (!_editor.ChangeCrest(state, slot, crest, source, out var old, key)) return; - var actors = _applier.ChangeCrests(state, source is StateChanged.Source.Manual or StateChanged.Source.Ipc); + var actors = _applier.ChangeCrests(state, source is StateSource.Manual or StateSource.Ipc); Glamourer.Log.Verbose( $"Set {slot.ToLabel()} crest in state {state.Identifier.Incognito(null)} from {old} to {crest}. [Affecting {actors.ToLazyString("nothing")}.]"); _event.Invoke(StateChanged.Type.Crest, source, state, actors, (old, crest, slot)); @@ -309,7 +309,7 @@ public class StateManager( /// Change the crest of an equipment piece. public void ChangeCustomizeParameter(ActorState state, CustomizeParameterFlag flag, CustomizeParameterValue value, - StateChanged.Source source, uint key = 0) + StateSource source, uint key = 0) { // Also apply main color to highlights when highlights is off. if (!state.ModelData.Customize.Highlights && flag is CustomizeParameterFlag.HairDiffuse) @@ -319,63 +319,27 @@ public class StateManager( return; var @new = state.ModelData.Parameters[flag]; - var actors = _applier.ChangeParameters(state, flag, source is StateChanged.Source.Manual or StateChanged.Source.Ipc); + var actors = _applier.ChangeParameters(state, flag, source is StateSource.Manual or StateSource.Ipc); Glamourer.Log.Verbose( $"Set {flag} crest in state {state.Identifier.Incognito(null)} from {old} to {@new}. [Affecting {actors.ToLazyString("nothing")}.]"); _event.Invoke(StateChanged.Type.Parameter, source, state, actors, (old, @new, flag)); } - /// Change hat visibility. - public void ChangeHatState(ActorState state, bool value, StateChanged.Source source, uint key = 0) + /// Change meta state. + public void ChangeMeta(ActorState state, MetaIndex meta, bool value, StateSource source, uint key = 0) { - if (!_editor.ChangeMetaState(state, MetaIndex.HatState, value, source, out var old, key)) + if (!_editor.ChangeMetaState(state, meta, value, source, out var old, key)) return; - var actors = _applier.ChangeHatState(state, source is StateChanged.Source.Manual or StateChanged.Source.Ipc); + var actors = _applier.ChangeMetaState(state, meta, source is StateSource.Manual or StateSource.Ipc); Glamourer.Log.Verbose( $"Set Head Gear Visibility in state {state.Identifier.Incognito(null)} from {old} to {value}. [Affecting {actors.ToLazyString("nothing")}.]"); _event.Invoke(StateChanged.Type.Other, source, state, actors, (old, value, MetaIndex.HatState)); } - /// Change weapon visibility. - public void ChangeWeaponState(ActorState state, bool value, StateChanged.Source source, uint key = 0) - { - if (!_editor.ChangeMetaState(state, MetaIndex.WeaponState, value, source, out var old, key)) - return; - - var actors = _applier.ChangeWeaponState(state, source is StateChanged.Source.Manual or StateChanged.Source.Ipc); - Glamourer.Log.Verbose( - $"Set Weapon Visibility in state {state.Identifier.Incognito(null)} from {old} to {value}. [Affecting {actors.ToLazyString("nothing")}.]"); - _event.Invoke(StateChanged.Type.Other, source, state, actors, (old, value, MetaIndex.WeaponState)); - } - - /// Change visor state. - public void ChangeVisorState(ActorState state, bool value, StateChanged.Source source, uint key = 0) - { - if (!_editor.ChangeMetaState(state, MetaIndex.VisorState, value, source, out var old, key)) - return; - - var actors = _applier.ChangeVisor(state, source is StateChanged.Source.Manual or StateChanged.Source.Ipc); - Glamourer.Log.Verbose( - $"Set Visor State in state {state.Identifier.Incognito(null)} from {old} to {value}. [Affecting {actors.ToLazyString("nothing")}.]"); - _event.Invoke(StateChanged.Type.Other, source, state, actors, (old, value, MetaIndex.VisorState)); - } - - /// Set GPose Wetness. - public void ChangeWetness(ActorState state, bool value, StateChanged.Source source, uint key = 0) - { - if (!_editor.ChangeMetaState(state, MetaIndex.Wetness, value, source, out var old, key)) - return; - - var actors = _applier.ChangeWetness(state, true); - Glamourer.Log.Verbose( - $"Set Wetness in state {state.Identifier.Incognito(null)} from {old} to {value}. [Affecting {actors.ToLazyString("nothing")}.]"); - _event.Invoke(StateChanged.Type.Other, state.Source[MetaIndex.Wetness], state, actors, (old, value, MetaIndex.Wetness)); - } - #endregion - public void ApplyDesign(DesignBase design, ActorState state, StateChanged.Source source, uint key = 0) + public void ApplyDesign(DesignBase design, ActorState state, StateSource source, uint key = 0) { if (!_editor.ChangeModelId(state, design.DesignData.ModelId, design.DesignData.Customize, design.GetDesignDataRef().GetEquipmentPtr(), source, @@ -383,16 +347,16 @@ public class StateManager( return; var redraw = oldModelId != design.DesignData.ModelId || !design.DesignData.IsHuman; - if (design.DoApplyWetness()) + if (design.DoApplyMeta(MetaIndex.Wetness)) _editor.ChangeMetaState(state, MetaIndex.Wetness, design.DesignData.IsWet(), source, out _, key); if (state.ModelData.IsHuman) { - if (design.DoApplyHatVisible()) + if (design.DoApplyMeta(MetaIndex.HatState)) _editor.ChangeMetaState(state, MetaIndex.HatState, design.DesignData.IsHatVisible(), source, out _, key); - if (design.DoApplyWeaponVisible()) + if (design.DoApplyMeta(MetaIndex.WeaponState)) _editor.ChangeMetaState(state, MetaIndex.WeaponState, design.DesignData.IsWeaponVisible(), source, out _, key); - if (design.DoApplyVisorToggle()) + if (design.DoApplyMeta(MetaIndex.VisorState)) _editor.ChangeMetaState(state, MetaIndex.VisorState, design.DesignData.IsVisorToggled(), source, out _, key); var flags = state.AllowsRedraw(_condition) @@ -407,8 +371,8 @@ public class StateManager( foreach (var slot in CrestExtensions.AllRelevantSet.Where(design.DoApplyCrest)) _editor.ChangeCrest(state, slot, design.DesignData.Crest(slot), source, out _, key); - var paramSource = source is StateChanged.Source.Manual - ? StateChanged.Source.Pending + var paramSource = source is StateSource.Manual + ? StateSource.Pending : source; foreach (var flag in CustomizeParameterExtensions.AllFlags.Where(design.DoApplyParameter)) @@ -418,13 +382,13 @@ public class StateManager( if (!state.ModelData.Customize.Highlights) _editor.ChangeParameter(state, CustomizeParameterFlag.HairHighlight, state.ModelData.Parameters[CustomizeParameterFlag.HairDiffuse], - state.Source[CustomizeParameterFlag.HairDiffuse], out _, key); + state.Sources[CustomizeParameterFlag.HairDiffuse], out _, key); } var actors = ApplyAll(state, redraw, false); Glamourer.Log.Verbose( $"Applied design to {state.Identifier.Incognito(null)}. [Affecting {actors.ToLazyString("nothing")}.]"); - _event.Invoke(StateChanged.Type.Design, state.Source[MetaIndex.Wetness], state, actors, design); + _event.Invoke(StateChanged.Type.Design, state.Sources[MetaIndex.Wetness], state, actors, design); return; void HandleEquip(EquipSlot slot, bool applyPiece, bool applyStain) @@ -442,7 +406,7 @@ public class StateManager( private ActorData ApplyAll(ActorState state, bool redraw, bool withLock) { - var actors = _applier.ChangeWetness(state, true); + var actors = _applier.ChangeMetaState(state, MetaIndex.Wetness, true); if (redraw) { if (withLock) @@ -454,7 +418,7 @@ public class StateManager( _applier.ChangeCustomize(actors, state.ModelData.Customize); foreach (var slot in EquipSlotExtensions.EqdpSlots) { - _applier.ChangeArmor(actors, slot, state.ModelData.Armor(slot), state.Source[slot, false] is not StateChanged.Source.Ipc, + _applier.ChangeArmor(actors, slot, state.ModelData.Armor(slot), state.Sources[slot, false] is not StateSource.Ipc, state.ModelData.IsHatVisible()); } @@ -466,9 +430,9 @@ public class StateManager( if (state.ModelData.IsHuman) { - _applier.ChangeHatState(actors, state.ModelData.IsHatVisible()); - _applier.ChangeWeaponState(actors, state.ModelData.IsWeaponVisible()); - _applier.ChangeVisor(actors, state.ModelData.IsVisorToggled()); + _applier.ChangeMetaState(actors, MetaIndex.HatState, state.ModelData.IsHatVisible()); + _applier.ChangeMetaState(actors, MetaIndex.WeaponState, state.ModelData.IsWeaponVisible()); + _applier.ChangeMetaState(actors, MetaIndex.VisorState, state.ModelData.IsVisorToggled()); _applier.ChangeCrests(actors, state.ModelData.CrestVisibility); _applier.ChangeParameters(actors, state.OnlyChangedParameters(), state.ModelData.Parameters, state.IsLocked); } @@ -476,7 +440,7 @@ public class StateManager( return actors; } - public void ResetState(ActorState state, StateChanged.Source source, uint key = 0) + public void ResetState(ActorState state, StateSource source, uint key = 0) { if (!state.Unlock(key)) return; @@ -488,25 +452,25 @@ public class StateManager( state.ModelData = state.BaseData; state.ModelData.SetIsWet(false); foreach (var index in Enum.GetValues()) - state.Source[index] = StateChanged.Source.Game; + state.Sources[index] = StateSource.Game; foreach (var slot in EquipSlotExtensions.FullSlots) { - state.Source[slot, true] = StateChanged.Source.Game; - state.Source[slot, false] = StateChanged.Source.Game; + state.Sources[slot, true] = StateSource.Game; + state.Sources[slot, false] = StateSource.Game; } foreach (var type in Enum.GetValues()) - state.Source[type] = StateChanged.Source.Game; + state.Sources[type] = StateSource.Game; foreach (var slot in CrestExtensions.AllRelevantSet) - state.Source[slot] = StateChanged.Source.Game; + state.Sources[slot] = StateSource.Game; foreach (var flag in CustomizeParameterExtensions.AllFlags) - state.Source[flag] = StateChanged.Source.Game; + state.Sources[flag] = StateSource.Game; var actors = ActorData.Invalid; - if (source is StateChanged.Source.Manual or StateChanged.Source.Ipc) + if (source is StateSource.Manual or StateSource.Ipc) actors = ApplyAll(state, redraw, true); Glamourer.Log.Verbose( @@ -514,7 +478,7 @@ public class StateManager( _event.Invoke(StateChanged.Type.Reset, source, state, actors, null); } - public void ResetAdvancedState(ActorState state, StateChanged.Source source, uint key = 0) + public void ResetAdvancedState(ActorState state, StateSource source, uint key = 0) { if (!state.Unlock(key) || !state.ModelData.IsHuman) return; @@ -522,10 +486,10 @@ public class StateManager( state.ModelData.Parameters = state.BaseData.Parameters; foreach (var flag in CustomizeParameterExtensions.AllFlags) - state.Source[flag] = StateChanged.Source.Game; + state.Sources[flag] = StateSource.Game; var actors = ActorData.Invalid; - if (source is StateChanged.Source.Manual or StateChanged.Source.Ipc) + if (source is StateSource.Manual or StateSource.Ipc) actors = _applier.ChangeParameters(state, CustomizeParameterExtensions.All, true); Glamourer.Log.Verbose( $"Reset advanced customization state of {state.Identifier.Incognito(null)} to game base. [Affecting {actors.ToLazyString("nothing")}.]"); @@ -537,69 +501,69 @@ public class StateManager( if (!state.Unlock(key)) return; - foreach (var index in Enum.GetValues().Where(i => state.Source[i] is StateChanged.Source.Fixed)) + foreach (var index in Enum.GetValues().Where(i => state.Sources[i] is StateSource.Fixed)) { - state.Source[index] = StateChanged.Source.Game; + state.Sources[index] = StateSource.Game; state.ModelData.Customize[index] = state.BaseData.Customize[index]; } foreach (var slot in EquipSlotExtensions.FullSlots) { - if (state.Source[slot, true] is StateChanged.Source.Fixed) + if (state.Sources[slot, true] is StateSource.Fixed) { - state.Source[slot, true] = StateChanged.Source.Game; + state.Sources[slot, true] = StateSource.Game; state.ModelData.SetStain(slot, state.BaseData.Stain(slot)); } - if (state.Source[slot, false] is StateChanged.Source.Fixed) + if (state.Sources[slot, false] is StateSource.Fixed) { - state.Source[slot, false] = StateChanged.Source.Game; + state.Sources[slot, false] = StateSource.Game; state.ModelData.SetItem(slot, state.BaseData.Item(slot)); } } foreach (var slot in CrestExtensions.AllRelevantSet) { - if (state.Source[slot] is StateChanged.Source.Fixed) + if (state.Sources[slot] is StateSource.Fixed) { - state.Source[slot] = StateChanged.Source.Game; + state.Sources[slot] = StateSource.Game; state.ModelData.SetCrest(slot, state.BaseData.Crest(slot)); } } foreach (var flag in CustomizeParameterExtensions.AllFlags) { - switch (state.Source[flag]) + switch (state.Sources[flag]) { - case StateChanged.Source.Fixed: - case StateChanged.Source.Manual when !respectManualPalettes: - state.Source[flag] = StateChanged.Source.Game; + case StateSource.Fixed: + case StateSource.Manual when !respectManualPalettes: + state.Sources[flag] = StateSource.Game; state.ModelData.Parameters[flag] = state.BaseData.Parameters[flag]; break; } } - if (state.Source[MetaIndex.HatState] is StateChanged.Source.Fixed) + if (state.Sources[MetaIndex.HatState] is StateSource.Fixed) { - state.Source[MetaIndex.HatState] = StateChanged.Source.Game; + state.Sources[MetaIndex.HatState] = StateSource.Game; state.ModelData.SetHatVisible(state.BaseData.IsHatVisible()); } - if (state.Source[MetaIndex.VisorState] is StateChanged.Source.Fixed) + if (state.Sources[MetaIndex.VisorState] is StateSource.Fixed) { - state.Source[MetaIndex.VisorState] = StateChanged.Source.Game; + state.Sources[MetaIndex.VisorState] = StateSource.Game; state.ModelData.SetVisor(state.BaseData.IsVisorToggled()); } - if (state.Source[MetaIndex.WeaponState] is StateChanged.Source.Fixed) + if (state.Sources[MetaIndex.WeaponState] is StateSource.Fixed) { - state.Source[MetaIndex.WeaponState] = StateChanged.Source.Game; + state.Sources[MetaIndex.WeaponState] = StateSource.Game; state.ModelData.SetWeaponVisible(state.BaseData.IsWeaponVisible()); } - if (state.Source[MetaIndex.Wetness] is StateChanged.Source.Fixed) + if (state.Sources[MetaIndex.Wetness] is StateSource.Fixed) { - state.Source[MetaIndex.Wetness] = StateChanged.Source.Game; + state.Sources[MetaIndex.Wetness] = StateSource.Game; state.ModelData.SetIsWet(state.BaseData.IsWet()); } } diff --git a/Glamourer/State/StateSource.cs b/Glamourer/State/StateSource.cs index 80899d2..1d66a46 100644 --- a/Glamourer/State/StateSource.cs +++ b/Glamourer/State/StateSource.cs @@ -1,49 +1,75 @@ -using Glamourer.GameData; -using Penumbra.GameData.Enums; -using static Glamourer.Events.StateChanged; +using Penumbra.GameData.Enums; namespace Glamourer.State; -public readonly struct StateSource +public enum StateSource : byte { - public static readonly int Size = EquipFlagExtensions.NumEquipFlags - + CustomizationExtensions.NumIndices - + 5 - + CrestExtensions.AllRelevantSet.Count - + CustomizeParameterExtensions.AllFlags.Count; + Game, + Manual, + Fixed, + Ipc, + + // Only used for CustomizeParameters. + Pending, +} + +public unsafe struct StateSources +{ + public const int Size = (StateIndex.Size + 1) / 2; + private fixed byte _data[Size]; - private readonly Source[] _data = Enumerable.Repeat(Source.Game, Size).ToArray(); - - public StateSource() + public StateSources() { } - public ref Source this[EquipSlot slot, bool stain] - => ref _data[slot.ToIndex() + (stain ? EquipFlagExtensions.NumEquipFlags / 2 : 0)]; + public StateSource this[StateIndex index] + { + get + { + var val = _data[index.Value / 2]; + return (StateSource)((index.Value & 1) == 1 ? val >> 4 : val & 0x0F); + } + set + { + var val = _data[index.Value / 2]; + if ((index.Value & 1) == 1) + val = (byte)((val & 0x0F) | ((byte)value << 4)); + else + val = (byte)((val & 0xF0) | (byte)value); + _data[index.Value / 2] = val; + } + } - public ref Source this[CrestFlag slot] - => ref _data[EquipFlagExtensions.NumEquipFlags + CustomizationExtensions.NumIndices + 5 + slot.ToInternalIndex()]; - - public ref Source this[CustomizeIndex type] - => ref _data[EquipFlagExtensions.NumEquipFlags + (int)type]; - - public ref Source this[MetaIndex index] - => ref _data[(int)index]; - - public ref Source this[CustomizeParameterFlag flag] - => ref _data[ - EquipFlagExtensions.NumEquipFlags - + CustomizationExtensions.NumIndices - + 5 - + CrestExtensions.AllRelevantSet.Count - + flag.ToInternalIndex()]; + public StateSource this[EquipSlot slot, bool stain] + { + get => this[slot.ToState(stain)]; + set => this[slot.ToState(stain)] = value; + } public void RemoveFixedDesignSources() { - for (var i = 0; i < _data.Length; ++i) + for (var i = 0; i < Size; ++i) { - if (_data[i] is Source.Fixed) - _data[i] = Source.Manual; + var value = _data[i]; + switch (value) + { + case (byte)StateSource.Fixed | ((byte)StateSource.Fixed << 4): + _data[i] = (byte)StateSource.Manual | ((byte)StateSource.Manual << 4); + break; + + case (byte)StateSource.Game | ((byte)StateSource.Fixed << 4): + case (byte)StateSource.Manual | ((byte)StateSource.Fixed << 4): + case (byte)StateSource.Ipc | ((byte)StateSource.Fixed << 4): + case (byte)StateSource.Pending | ((byte)StateSource.Fixed << 4): + _data[i] = (byte)((value & 0x0F) | ((byte)StateSource.Manual << 4)); + break; + case (byte)StateSource.Fixed: + case ((byte)StateSource.Manual << 4) | (byte)StateSource.Fixed: + case ((byte)StateSource.Ipc << 4) | (byte)StateSource.Fixed: + case ((byte)StateSource.Pending << 4) | (byte)StateSource.Fixed: + _data[i] = (byte)((value & 0xF0) | (byte)StateSource.Manual); + break; + } } } }