Better handling of application rules.

This commit is contained in:
Ottermandias 2024-01-30 16:04:56 +01:00
parent cb45221be2
commit 962c4e53ad
8 changed files with 130 additions and 51 deletions

View file

@ -1,4 +1,5 @@
using Glamourer.Events; using Glamourer.Designs;
using Glamourer.Events;
using Glamourer.Interop.Structs; using Glamourer.Interop.Structs;
using Glamourer.State; using Glamourer.State;
using Penumbra.Api.Helpers; 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) private void OnStateChanged(StateChanged.Type type, StateSource source, ActorState state, ActorData actors, object? data = null)
{ {
foreach (var actor in actors.Objects) foreach (var actor in actors.Objects)
_stateChangedProvider.Invoke(type, actor.Address, new Lazy<string>(() => _designConverter.ShareBase64(state))); _stateChangedProvider.Invoke(type, actor.Address, new Lazy<string>(() => _designConverter.ShareBase64(state, ApplicationRules.AllButParameters(state))));
} }
private void OnGPoseChanged(bool value) private void OnGPoseChanged(bool value)

View file

@ -1,5 +1,6 @@
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin; using Dalamud.Plugin;
using Glamourer.Designs;
using Penumbra.Api.Helpers; using Penumbra.Api.Helpers;
using Penumbra.GameData.Actors; using Penumbra.GameData.Actors;
@ -40,6 +41,6 @@ public partial class GlamourerIpc
return null; return null;
} }
return _designConverter.ShareBase64(state); return _designConverter.ShareBase64(state, ApplicationRules.AllButParameters(state));
} }
} }

View file

@ -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;
}
}

View file

@ -1,7 +1,7 @@
using Dalamud.Interface.Internal.Notifications; using Dalamud.Interface.Internal.Notifications;
using Glamourer.GameData; using Glamourer.GameData;
using Glamourer.Interop.Material;
using Glamourer.Services; using Glamourer.Services;
using Glamourer.State;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using OtterGui.Classes; using OtterGui.Classes;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
@ -14,7 +14,16 @@ public class DesignBase
{ {
public const int FileVersion = 1; public const int FileVersion = 1;
private DesignData _designData = new(); private DesignData _designData = new();
private readonly DesignMaterialManager _materials = new();
/// <summary> For read-only information about custom material color changes. </summary>
public IReadOnlyList<(uint, MaterialValueDesign)> Materials
=> _materials.Values;
/// <summary> To make it clear something is edited here. </summary>
public DesignMaterialManager GetMaterialDataRef()
=> _materials;
/// <summary> For read-only information about the actual design. </summary> /// <summary> For read-only information about the actual design. </summary>
public ref readonly DesignData DesignData public ref readonly DesignData DesignData
@ -30,6 +39,7 @@ public class DesignBase
CustomizeSet = SetCustomizationSet(customize); CustomizeSet = SetCustomizationSet(customize);
} }
/// <summary> Used when importing .cma or .chara files. </summary>
internal DesignBase(CustomizeService customize, in DesignData designData, EquipFlag equipFlags, CustomizeFlag customizeFlags) internal DesignBase(CustomizeService customize, in DesignData designData, EquipFlag equipFlags, CustomizeFlag customizeFlags)
{ {
_designData = designData; _designData = designData;
@ -42,6 +52,7 @@ public class DesignBase
internal DesignBase(DesignBase clone) internal DesignBase(DesignBase clone)
{ {
_designData = clone._designData; _designData = clone._designData;
_materials = clone._materials.Clone();
CustomizeSet = clone.CustomizeSet; CustomizeSet = clone.CustomizeSet;
ApplyCustomize = clone.ApplyCustomizeRaw; ApplyCustomize = clone.ApplyCustomizeRaw;
ApplyEquip = clone.ApplyEquip & EquipFlagExtensions.All; ApplyEquip = clone.ApplyEquip & EquipFlagExtensions.All;

View file

@ -1,5 +1,4 @@
using Glamourer.Designs.Links; using Glamourer.Designs.Links;
using Glamourer.GameData;
using Glamourer.Services; using Glamourer.Services;
using Glamourer.State; using Glamourer.State;
using Glamourer.Utility; using Glamourer.Utility;
@ -11,7 +10,12 @@ using Penumbra.GameData.Structs;
namespace Glamourer.Designs; 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; public const byte Version = 6;
@ -21,9 +25,9 @@ public class DesignConverter(ItemManager _items, DesignManager _designs, Customi
public JObject ShareJObject(Design design) public JObject ShareJObject(Design design)
=> design.JsonSerialize(); => 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); return ShareJObject(design);
} }
@ -33,32 +37,22 @@ public class DesignConverter(ItemManager _items, DesignManager _designs, Customi
public string ShareBase64(DesignBase design) public string ShareBase64(DesignBase design)
=> ShareBase64(ShareJObject(design)); => ShareBase64(ShareJObject(design));
public string ShareBase64(ActorState state) public string ShareBase64(ActorState state, in ApplicationRules rules)
=> ShareBase64(state, EquipFlagExtensions.All, CustomizeFlagExtensions.All, CrestExtensions.All, CustomizeParameterExtensions.All); => ShareBase64(state.ModelData, rules);
public string ShareBase64(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags, CustomizeParameterFlag parameterFlags) public string ShareBase64(in DesignData data, in ApplicationRules rules)
=> ShareBase64(state.ModelData, equipFlags, customizeFlags, crestFlags, parameterFlags);
public string ShareBase64(in DesignData data, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags, CustomizeParameterFlag parameterFlags)
{ {
var design = Convert(data, equipFlags, customizeFlags, crestFlags, parameterFlags); var design = Convert(data, rules);
return ShareBase64(ShareJObject(design)); return ShareBase64(ShareJObject(design));
} }
public DesignBase Convert(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags, CustomizeParameterFlag parameterFlags) public DesignBase Convert(ActorState state, in ApplicationRules rules)
=> Convert(state.ModelData, equipFlags, customizeFlags, crestFlags, parameterFlags); => 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(); var design = _designs.CreateTemporary();
design.ApplyEquip = equipFlags & EquipFlagExtensions.All; rules.Apply(design);
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);
design.SetDesignData(_customize, data); design.SetDesignData(_customize, data);
return design; return design;
} }
@ -139,7 +133,7 @@ public class DesignConverter(ItemManager _items, DesignManager _designs, Customi
return ret; return ret;
} }
private static string ShareBase64(JObject jObject) private static string ShareBase64(JToken jObject)
{ {
var json = jObject.ToString(Formatting.None); var json = jObject.ToString(Formatting.None);
var compressed = json.Compress(Version); var compressed = json.Compress(Version);

View file

@ -356,8 +356,7 @@ public class ActorPanel(
{ {
ImGui.OpenPopup("Save as Design"); ImGui.OpenPopup("Save as Design");
_newName = _state!.Identifier.ToName(); _newName = _state!.Identifier.ToName();
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags(); _newDesign = _converter.Convert(_state, ApplicationRules.FromModifiers(_state));
_newDesign = _converter.Convert(_state, applyGear, applyCustomize, applyCrest, applyParameters);
} }
private void SaveDesignDrawPopup() private void SaveDesignDrawPopup()
@ -392,8 +391,7 @@ public class ActorPanel(
{ {
try try
{ {
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags(); var text = _converter.ShareBase64(_state!, ApplicationRules.FromModifiers(_state!));
var text = _converter.ShareBase64(_state!, applyGear, applyCustomize, applyCrest, applyParameters);
ImGui.SetClipboardText(text); ImGui.SetClipboardText(text);
} }
catch (Exception ex) catch (Exception ex)
@ -432,9 +430,8 @@ public class ActorPanel(
!data.Valid || id == _identifier || _state!.ModelData.ModelId != 0)) !data.Valid || id == _identifier || _state!.ModelData.ModelId != 0))
return; return;
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
if (_stateManager.GetOrCreate(id, data.Objects[0], out var state)) 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); ApplySettings.Manual);
} }
@ -450,9 +447,8 @@ public class ActorPanel(
!data.Valid || id == _identifier || _state!.ModelData.ModelId != 0)) !data.Valid || id == _identifier || _state!.ModelData.ModelId != 0))
return; return;
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
if (_stateManager.GetOrCreate(id, data.Objects[0], out var state)) 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); ApplySettings.Manual);
} }
} }

View file

@ -84,9 +84,8 @@ public class NpcPanel(
{ {
try try
{ {
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
var data = ToDesignData(); var data = ToDesignData();
var text = _converter.ShareBase64(data, applyGear, applyCustomize, applyCrest, applyParameters); var text = _converter.ShareBase64(data, ApplicationRules.NpcFromModifiers());
ImGui.SetClipboardText(text); ImGui.SetClipboardText(text);
} }
catch (Exception ex) catch (Exception ex)
@ -100,11 +99,9 @@ public class NpcPanel(
private void SaveDesignOpen() private void SaveDesignOpen()
{ {
ImGui.OpenPopup("Save as Design"); ImGui.OpenPopup("Save as Design");
_newName = _selector.Selection.Name; _newName = _selector.Selection.Name;
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
var data = ToDesignData(); var data = ToDesignData();
_newDesign = _converter.Convert(data, applyGear, applyCustomize, applyCrest, applyParameters); _newDesign = _converter.Convert(data, ApplicationRules.NpcFromModifiers());
} }
private void SaveDesignDrawPopup() private void SaveDesignDrawPopup()
@ -198,8 +195,7 @@ public class NpcPanel(
if (_state.GetOrCreate(id, data.Objects[0], out var state)) if (_state.GetOrCreate(id, data.Objects[0], out var state))
{ {
var (applyGear, applyCustomize, _, _) = UiHelpers.ConvertKeysToFlags(); var design = _converter.Convert(ToDesignData(), ApplicationRules.NpcFromModifiers());
var design = _converter.Convert(ToDesignData(), applyGear, applyCustomize, 0, 0);
_state.ApplyDesign(state, design, ApplySettings.Manual); _state.ApplyDesign(state, design, ApplySettings.Manual);
} }
} }
@ -217,8 +213,7 @@ public class NpcPanel(
if (_state.GetOrCreate(id, data.Objects[0], out var state)) if (_state.GetOrCreate(id, data.Objects[0], out var state))
{ {
var (applyGear, applyCustomize, _, _) = UiHelpers.ConvertKeysToFlags(); var design = _converter.Convert(ToDesignData(), ApplicationRules.NpcFromModifiers());
var design = _converter.Convert(ToDesignData(), applyGear, applyCustomize, 0, 0);
_state.ApplyDesign(state, design, ApplySettings.Manual); _state.ApplyDesign(state, design, ApplySettings.Manual);
} }
} }

View file

@ -3,8 +3,6 @@ using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using Glamourer.Automation; using Glamourer.Automation;
using Glamourer.Designs; using Glamourer.Designs;
using Glamourer.Events;
using Glamourer.GameData;
using Glamourer.Gui; using Glamourer.Gui;
using Glamourer.Interop; using Glamourer.Interop;
using Glamourer.Interop.Penumbra; using Glamourer.Interop.Penumbra;
@ -509,7 +507,7 @@ public class CommandService : IDisposable
try try
{ {
var text = _converter.ShareBase64(state); var text = _converter.ShareBase64(state, ApplicationRules.AllButParameters(state));
ImGui.SetClipboardText(text); ImGui.SetClipboardText(text);
return true; return true;
} }
@ -548,8 +546,7 @@ public class CommandService : IDisposable
&& _stateManager.GetOrCreate(identifier, data.Objects[0], out state))) && _stateManager.GetOrCreate(identifier, data.Objects[0], out state)))
continue; continue;
var design = _converter.Convert(state, EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant, CrestExtensions.All, var design = _converter.Convert(state, ApplicationRules.FromModifiers(state));
CustomizeParameterExtensions.All);
_designManager.CreateClone(design, split[0], true); _designManager.CreateClone(design, split[0], true);
return true; return true;
} }