From 962c4e53ad3a114ce6adeb22142d405f3f5ddfed Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Tue, 30 Jan 2024 16:04:56 +0100 Subject: [PATCH] Better handling of application rules. --- Glamourer/Api/GlamourerIpc.Events.cs | 5 +- .../Api/GlamourerIpc.GetCustomization.cs | 3 +- Glamourer/Designs/ApplicationRules.cs | 84 +++++++++++++++++++ Glamourer/Designs/DesignBase.cs | 15 +++- Glamourer/Designs/DesignConverter.cs | 40 ++++----- Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs | 12 +-- Glamourer/Gui/Tabs/NpcTab/NpcPanel.cs | 15 ++-- Glamourer/Services/CommandService.cs | 7 +- 8 files changed, 130 insertions(+), 51 deletions(-) create mode 100644 Glamourer/Designs/ApplicationRules.cs diff --git a/Glamourer/Api/GlamourerIpc.Events.cs b/Glamourer/Api/GlamourerIpc.Events.cs index 8caa495..982e4a1 100644 --- a/Glamourer/Api/GlamourerIpc.Events.cs +++ b/Glamourer/Api/GlamourerIpc.Events.cs @@ -1,4 +1,5 @@ -using Glamourer.Events; +using Glamourer.Designs; +using Glamourer.Events; using Glamourer.Interop.Structs; using Glamourer.State; using Penumbra.Api.Helpers; @@ -18,7 +19,7 @@ public partial class GlamourerIpc 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))); + _stateChangedProvider.Invoke(type, actor.Address, new Lazy(() => _designConverter.ShareBase64(state, ApplicationRules.AllButParameters(state)))); } private void OnGPoseChanged(bool value) diff --git a/Glamourer/Api/GlamourerIpc.GetCustomization.cs b/Glamourer/Api/GlamourerIpc.GetCustomization.cs index bedf514..4f35a2f 100644 --- a/Glamourer/Api/GlamourerIpc.GetCustomization.cs +++ b/Glamourer/Api/GlamourerIpc.GetCustomization.cs @@ -1,5 +1,6 @@ using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Plugin; +using Glamourer.Designs; using Penumbra.Api.Helpers; using Penumbra.GameData.Actors; @@ -40,6 +41,6 @@ public partial class GlamourerIpc return null; } - return _designConverter.ShareBase64(state); + return _designConverter.ShareBase64(state, ApplicationRules.AllButParameters(state)); } } diff --git a/Glamourer/Designs/ApplicationRules.cs b/Glamourer/Designs/ApplicationRules.cs new file mode 100644 index 0000000..8fdd5d6 --- /dev/null +++ b/Glamourer/Designs/ApplicationRules.cs @@ -0,0 +1,84 @@ +using Glamourer.GameData; +using Glamourer.State; +using ImGuiNET; +using Penumbra.GameData.Enums; + +namespace Glamourer.Designs; + +public readonly struct ApplicationRules( + EquipFlag equip, + CustomizeFlag customize, + CrestFlag crest, + CustomizeParameterFlag parameters, + MetaFlag meta) +{ + public static readonly ApplicationRules All = new(EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant, + CrestExtensions.AllRelevant, CustomizeParameterExtensions.All, MetaExtensions.All); + + public static ApplicationRules FromModifiers(ActorState state) + => FromModifiers(state, ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift); + + public static ApplicationRules NpcFromModifiers() + => NpcFromModifiers(ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift); + + public static ApplicationRules AllButParameters(ActorState state) + => new(All.Equip, All.Customize, All.Crest, ComputeParameters(state.ModelData, state.BaseData, All.Parameters), All.Meta); + + public static ApplicationRules NpcFromModifiers(bool ctrl, bool shift) + => new(ctrl || !shift ? EquipFlagExtensions.All : 0, + !ctrl || shift ? CustomizeFlagExtensions.AllRelevant : 0, + 0, + 0, + ctrl || !shift ? MetaFlag.VisorState : 0); + + public static ApplicationRules FromModifiers(ActorState state, bool ctrl, bool shift) + { + var equip = ctrl || !shift ? EquipFlagExtensions.All : 0; + var customize = !ctrl || shift ? CustomizeFlagExtensions.AllRelevant : 0; + var crest = equip == 0 ? 0 : CrestExtensions.AllRelevant; + var parameters = customize == 0 ? 0 : CustomizeParameterExtensions.All; + var meta = state.ModelData.IsWet() ? MetaFlag.Wetness : 0; + if (equip != 0) + meta |= MetaFlag.HatState | MetaFlag.WeaponState | MetaFlag.VisorState; + + return new ApplicationRules(equip, customize, crest, ComputeParameters(state.ModelData, state.BaseData, parameters), meta); + } + + public void Apply(DesignBase design) + { + design.ApplyEquip = Equip; + design.ApplyCustomize = Customize; + design.ApplyCrest = Crest; + design.ApplyParameters = Parameters; + design.ApplyMeta = Meta; + } + + public EquipFlag Equip + => equip & EquipFlagExtensions.All; + + public CustomizeFlag Customize + => customize & CustomizeFlagExtensions.AllRelevant; + + public CrestFlag Crest + => crest & CrestExtensions.AllRelevant; + + public CustomizeParameterFlag Parameters + => parameters & CustomizeParameterExtensions.All; + + public MetaFlag Meta + => meta & MetaExtensions.All; + + public static CustomizeParameterFlag ComputeParameters(in DesignData model, in DesignData game, + CustomizeParameterFlag baseFlags = CustomizeParameterExtensions.All) + { + foreach (var flag in baseFlags.Iterate()) + { + var modelValue = model.Parameters[flag]; + var gameValue = game.Parameters[flag]; + if ((modelValue.InternalQuadruple - gameValue.InternalQuadruple).LengthSquared() > 1e-9f) + baseFlags &= ~flag; + } + + return baseFlags; + } +} diff --git a/Glamourer/Designs/DesignBase.cs b/Glamourer/Designs/DesignBase.cs index a533bc4..9699bc2 100644 --- a/Glamourer/Designs/DesignBase.cs +++ b/Glamourer/Designs/DesignBase.cs @@ -1,7 +1,7 @@ using Dalamud.Interface.Internal.Notifications; using Glamourer.GameData; +using Glamourer.Interop.Material; using Glamourer.Services; -using Glamourer.State; using Newtonsoft.Json.Linq; using OtterGui.Classes; using Penumbra.GameData.Enums; @@ -14,7 +14,16 @@ public class DesignBase { public const int FileVersion = 1; - private DesignData _designData = new(); + private DesignData _designData = new(); + private readonly DesignMaterialManager _materials = new(); + + /// For read-only information about custom material color changes. + public IReadOnlyList<(uint, MaterialValueDesign)> Materials + => _materials.Values; + + /// To make it clear something is edited here. + public DesignMaterialManager GetMaterialDataRef() + => _materials; /// For read-only information about the actual design. public ref readonly DesignData DesignData @@ -30,6 +39,7 @@ public class DesignBase CustomizeSet = SetCustomizationSet(customize); } + /// Used when importing .cma or .chara files. internal DesignBase(CustomizeService customize, in DesignData designData, EquipFlag equipFlags, CustomizeFlag customizeFlags) { _designData = designData; @@ -42,6 +52,7 @@ public class DesignBase internal DesignBase(DesignBase clone) { _designData = clone._designData; + _materials = clone._materials.Clone(); CustomizeSet = clone.CustomizeSet; ApplyCustomize = clone.ApplyCustomizeRaw; ApplyEquip = clone.ApplyEquip & EquipFlagExtensions.All; diff --git a/Glamourer/Designs/DesignConverter.cs b/Glamourer/Designs/DesignConverter.cs index 14c85f6..be70672 100644 --- a/Glamourer/Designs/DesignConverter.cs +++ b/Glamourer/Designs/DesignConverter.cs @@ -1,5 +1,4 @@ using Glamourer.Designs.Links; -using Glamourer.GameData; using Glamourer.Services; using Glamourer.State; using Glamourer.Utility; @@ -11,7 +10,12 @@ using Penumbra.GameData.Structs; namespace Glamourer.Designs; -public class DesignConverter(ItemManager _items, DesignManager _designs, CustomizeService _customize, HumanModelList _humans, DesignLinkLoader _linkLoader) +public class DesignConverter( + ItemManager _items, + DesignManager _designs, + CustomizeService _customize, + HumanModelList _humans, + DesignLinkLoader _linkLoader) { public const byte Version = 6; @@ -21,9 +25,9 @@ public class DesignConverter(ItemManager _items, DesignManager _designs, Customi public JObject ShareJObject(Design design) => design.JsonSerialize(); - public JObject ShareJObject(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags, CustomizeParameterFlag parameterFlags) + public JObject ShareJObject(ActorState state, in ApplicationRules rules) { - var design = Convert(state, equipFlags, customizeFlags, crestFlags, parameterFlags); + var design = Convert(state, rules); return ShareJObject(design); } @@ -33,32 +37,22 @@ public class DesignConverter(ItemManager _items, DesignManager _designs, Customi public string ShareBase64(DesignBase design) => ShareBase64(ShareJObject(design)); - public string ShareBase64(ActorState state) - => ShareBase64(state, EquipFlagExtensions.All, CustomizeFlagExtensions.All, CrestExtensions.All, CustomizeParameterExtensions.All); + public string ShareBase64(ActorState state, in ApplicationRules rules) + => ShareBase64(state.ModelData, rules); - public string ShareBase64(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags, CustomizeParameterFlag parameterFlags) - => ShareBase64(state.ModelData, equipFlags, customizeFlags, crestFlags, parameterFlags); - - public string ShareBase64(in DesignData data, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags, CustomizeParameterFlag parameterFlags) + public string ShareBase64(in DesignData data, in ApplicationRules rules) { - var design = Convert(data, equipFlags, customizeFlags, crestFlags, parameterFlags); + var design = Convert(data, rules); return ShareBase64(ShareJObject(design)); } - public DesignBase Convert(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags, CustomizeParameterFlag parameterFlags) - => Convert(state.ModelData, equipFlags, customizeFlags, crestFlags, parameterFlags); + public DesignBase Convert(ActorState state, in ApplicationRules rules) + => Convert(state.ModelData, rules); - public DesignBase Convert(in DesignData data, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags, CustomizeParameterFlag parameterFlags) + public DesignBase Convert(in DesignData data, in ApplicationRules rules) { var design = _designs.CreateTemporary(); - design.ApplyEquip = equipFlags & EquipFlagExtensions.All; - design.ApplyCustomize = customizeFlags & CustomizeFlagExtensions.AllRelevant; - design.ApplyCrest = crestFlags & CrestExtensions.All; - design.ApplyParameters = parameterFlags & CustomizeParameterExtensions.All; - 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); + rules.Apply(design); design.SetDesignData(_customize, data); return design; } @@ -139,7 +133,7 @@ public class DesignConverter(ItemManager _items, DesignManager _designs, Customi return ret; } - private static string ShareBase64(JObject jObject) + private static string ShareBase64(JToken jObject) { var json = jObject.ToString(Formatting.None); var compressed = json.Compress(Version); diff --git a/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs b/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs index 6ec62f5..94f4b56 100644 --- a/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs +++ b/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs @@ -356,8 +356,7 @@ public class ActorPanel( { ImGui.OpenPopup("Save as Design"); _newName = _state!.Identifier.ToName(); - var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags(); - _newDesign = _converter.Convert(_state, applyGear, applyCustomize, applyCrest, applyParameters); + _newDesign = _converter.Convert(_state, ApplicationRules.FromModifiers(_state)); } private void SaveDesignDrawPopup() @@ -392,8 +391,7 @@ public class ActorPanel( { try { - var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags(); - var text = _converter.ShareBase64(_state!, applyGear, applyCustomize, applyCrest, applyParameters); + var text = _converter.ShareBase64(_state!, ApplicationRules.FromModifiers(_state!)); ImGui.SetClipboardText(text); } catch (Exception ex) @@ -432,9 +430,8 @@ public class ActorPanel( !data.Valid || id == _identifier || _state!.ModelData.ModelId != 0)) return; - var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags(); if (_stateManager.GetOrCreate(id, data.Objects[0], out var state)) - _stateManager.ApplyDesign(state, _converter.Convert(_state!, applyGear, applyCustomize, applyCrest, applyParameters), + _stateManager.ApplyDesign(state, _converter.Convert(_state!, ApplicationRules.FromModifiers(_state!)), ApplySettings.Manual); } @@ -450,9 +447,8 @@ public class ActorPanel( !data.Valid || id == _identifier || _state!.ModelData.ModelId != 0)) return; - var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags(); if (_stateManager.GetOrCreate(id, data.Objects[0], out var state)) - _stateManager.ApplyDesign(state, _converter.Convert(_state!, applyGear, applyCustomize, applyCrest, applyParameters), + _stateManager.ApplyDesign(state, _converter.Convert(_state!, ApplicationRules.FromModifiers(_state!)), ApplySettings.Manual); } } diff --git a/Glamourer/Gui/Tabs/NpcTab/NpcPanel.cs b/Glamourer/Gui/Tabs/NpcTab/NpcPanel.cs index bd04a57..77dafa9 100644 --- a/Glamourer/Gui/Tabs/NpcTab/NpcPanel.cs +++ b/Glamourer/Gui/Tabs/NpcTab/NpcPanel.cs @@ -84,9 +84,8 @@ public class NpcPanel( { try { - var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags(); var data = ToDesignData(); - var text = _converter.ShareBase64(data, applyGear, applyCustomize, applyCrest, applyParameters); + var text = _converter.ShareBase64(data, ApplicationRules.NpcFromModifiers()); ImGui.SetClipboardText(text); } catch (Exception ex) @@ -100,11 +99,9 @@ public class NpcPanel( private void SaveDesignOpen() { ImGui.OpenPopup("Save as Design"); - _newName = _selector.Selection.Name; - var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags(); - + _newName = _selector.Selection.Name; var data = ToDesignData(); - _newDesign = _converter.Convert(data, applyGear, applyCustomize, applyCrest, applyParameters); + _newDesign = _converter.Convert(data, ApplicationRules.NpcFromModifiers()); } private void SaveDesignDrawPopup() @@ -198,8 +195,7 @@ public class NpcPanel( if (_state.GetOrCreate(id, data.Objects[0], out var state)) { - var (applyGear, applyCustomize, _, _) = UiHelpers.ConvertKeysToFlags(); - var design = _converter.Convert(ToDesignData(), applyGear, applyCustomize, 0, 0); + var design = _converter.Convert(ToDesignData(), ApplicationRules.NpcFromModifiers()); _state.ApplyDesign(state, design, ApplySettings.Manual); } } @@ -217,8 +213,7 @@ public class NpcPanel( if (_state.GetOrCreate(id, data.Objects[0], out var state)) { - var (applyGear, applyCustomize, _, _) = UiHelpers.ConvertKeysToFlags(); - var design = _converter.Convert(ToDesignData(), applyGear, applyCustomize, 0, 0); + var design = _converter.Convert(ToDesignData(), ApplicationRules.NpcFromModifiers()); _state.ApplyDesign(state, design, ApplySettings.Manual); } } diff --git a/Glamourer/Services/CommandService.cs b/Glamourer/Services/CommandService.cs index eb0e792..895ad2f 100644 --- a/Glamourer/Services/CommandService.cs +++ b/Glamourer/Services/CommandService.cs @@ -3,8 +3,6 @@ using Dalamud.Game.Text.SeStringHandling; using Dalamud.Plugin.Services; using Glamourer.Automation; using Glamourer.Designs; -using Glamourer.Events; -using Glamourer.GameData; using Glamourer.Gui; using Glamourer.Interop; using Glamourer.Interop.Penumbra; @@ -509,7 +507,7 @@ public class CommandService : IDisposable try { - var text = _converter.ShareBase64(state); + var text = _converter.ShareBase64(state, ApplicationRules.AllButParameters(state)); ImGui.SetClipboardText(text); return true; } @@ -548,8 +546,7 @@ public class CommandService : IDisposable && _stateManager.GetOrCreate(identifier, data.Objects[0], out state))) continue; - var design = _converter.Convert(state, EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant, CrestExtensions.All, - CustomizeParameterExtensions.All); + var design = _converter.Convert(state, ApplicationRules.FromModifiers(state)); _designManager.CreateClone(design, split[0], true); return true; }