mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 10:17:23 +01:00
Add parameter handling.
This commit is contained in:
parent
9361560350
commit
1a0a0f681f
27 changed files with 633 additions and 155 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
|
using Glamourer.GameData;
|
||||||
using Glamourer.Interop.Structs;
|
using Glamourer.Interop.Structs;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
@ -80,20 +81,24 @@ public class AutoDesign
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public (EquipFlag Equip, CustomizeFlag Customize, CrestFlag Crest, bool ApplyHat, bool ApplyVisor, bool ApplyWeapon, bool ApplyWet) ApplyWhat()
|
public (EquipFlag Equip, CustomizeFlag Customize, CrestFlag Crest, CustomizeParameterFlag Parameters, bool ApplyHat, bool ApplyVisor, bool
|
||||||
|
ApplyWeapon, bool ApplyWet) ApplyWhat()
|
||||||
{
|
{
|
||||||
var equipFlags = (ApplicationType.HasFlag(Type.Weapons) ? WeaponFlags : 0)
|
var equipFlags = (ApplicationType.HasFlag(Type.Weapons) ? WeaponFlags : 0)
|
||||||
| (ApplicationType.HasFlag(Type.Armor) ? ArmorFlags : 0)
|
| (ApplicationType.HasFlag(Type.Armor) ? ArmorFlags : 0)
|
||||||
| (ApplicationType.HasFlag(Type.Accessories) ? AccessoryFlags : 0)
|
| (ApplicationType.HasFlag(Type.Accessories) ? AccessoryFlags : 0)
|
||||||
| (ApplicationType.HasFlag(Type.GearCustomization) ? StainFlags : 0);
|
| (ApplicationType.HasFlag(Type.GearCustomization) ? StainFlags : 0);
|
||||||
var customizeFlags = ApplicationType.HasFlag(Type.Customizations) ? CustomizeFlagExtensions.All : 0;
|
var customizeFlags = ApplicationType.HasFlag(Type.Customizations) ? CustomizeFlagExtensions.All : 0;
|
||||||
|
var parameterFlags = ApplicationType.HasFlag(Type.Customizations) ? CustomizeParameterExtensions.All : 0;
|
||||||
var crestFlag = ApplicationType.HasFlag(Type.GearCustomization) ? CrestExtensions.AllRelevant : 0;
|
var crestFlag = ApplicationType.HasFlag(Type.GearCustomization) ? CrestExtensions.AllRelevant : 0;
|
||||||
|
|
||||||
if (Revert)
|
if (Revert)
|
||||||
return (equipFlags, customizeFlags, crestFlag, ApplicationType.HasFlag(Type.Armor), ApplicationType.HasFlag(Type.Armor),
|
return (equipFlags, customizeFlags, crestFlag, parameterFlags, ApplicationType.HasFlag(Type.Armor),
|
||||||
|
ApplicationType.HasFlag(Type.Armor),
|
||||||
ApplicationType.HasFlag(Type.Weapons), ApplicationType.HasFlag(Type.Customizations));
|
ApplicationType.HasFlag(Type.Weapons), ApplicationType.HasFlag(Type.Customizations));
|
||||||
|
|
||||||
return (equipFlags & Design!.ApplyEquip, customizeFlags & Design.ApplyCustomize, crestFlag & Design.ApplyCrest,
|
return (equipFlags & Design!.ApplyEquip, customizeFlags & Design.ApplyCustomize, crestFlag & Design.ApplyCrest,
|
||||||
|
parameterFlags & Design.ApplyParameters,
|
||||||
ApplicationType.HasFlag(Type.Armor) && Design.DoApplyHatVisible(),
|
ApplicationType.HasFlag(Type.Armor) && Design.DoApplyHatVisible(),
|
||||||
ApplicationType.HasFlag(Type.Armor) && Design.DoApplyVisorToggle(),
|
ApplicationType.HasFlag(Type.Armor) && Design.DoApplyVisorToggle(),
|
||||||
ApplicationType.HasFlag(Type.Weapons) && Design.DoApplyWeaponVisible(),
|
ApplicationType.HasFlag(Type.Weapons) && Design.DoApplyWeaponVisible(),
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using Dalamud.Plugin.Services;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
|
using Glamourer.GameData;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
using Glamourer.Interop.Structs;
|
using Glamourer.Interop.Structs;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
|
|
@ -271,10 +272,11 @@ public class AutoDesignApplier : IDisposable
|
||||||
|
|
||||||
private unsafe void Reduce(Actor actor, ActorState state, AutoDesignSet set, bool respectManual, bool fromJobChange)
|
private unsafe void Reduce(Actor actor, ActorState state, AutoDesignSet set, bool respectManual, bool fromJobChange)
|
||||||
{
|
{
|
||||||
EquipFlag totalEquipFlags = 0;
|
EquipFlag totalEquipFlags = 0;
|
||||||
CustomizeFlag totalCustomizeFlags = 0;
|
CustomizeFlag totalCustomizeFlags = 0;
|
||||||
CrestFlag totalCrestFlags = 0;
|
CrestFlag totalCrestFlags = 0;
|
||||||
byte totalMetaFlags = 0;
|
CustomizeParameterFlag totalParameterFlags = 0;
|
||||||
|
byte totalMetaFlags = 0;
|
||||||
if (set.BaseState == AutoDesignSet.Base.Game)
|
if (set.BaseState == AutoDesignSet.Base.Game)
|
||||||
_state.ResetStateFixed(state);
|
_state.ResetStateFixed(state);
|
||||||
else if (!respectManual)
|
else if (!respectManual)
|
||||||
|
|
@ -297,18 +299,19 @@ public class AutoDesignApplier : IDisposable
|
||||||
if (!data.IsHuman)
|
if (!data.IsHuman)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var (equipFlags, customizeFlags, crestFlags, applyHat, applyVisor, applyWeapon, applyWet) = design.ApplyWhat();
|
var (equipFlags, customizeFlags, crestFlags, parameterFlags, applyHat, applyVisor, applyWeapon, applyWet) = design.ApplyWhat();
|
||||||
ReduceMeta(state, data, applyHat, applyVisor, applyWeapon, applyWet, ref totalMetaFlags, respectManual, source);
|
ReduceMeta(state, data, applyHat, applyVisor, applyWeapon, applyWet, ref totalMetaFlags, respectManual, source);
|
||||||
ReduceCustomize(state, data, customizeFlags, ref totalCustomizeFlags, respectManual, source);
|
ReduceCustomize(state, data, customizeFlags, ref totalCustomizeFlags, respectManual, source);
|
||||||
ReduceEquip(state, data, equipFlags, ref totalEquipFlags, respectManual, source, fromJobChange);
|
ReduceEquip(state, data, equipFlags, ref totalEquipFlags, respectManual, source, fromJobChange);
|
||||||
ReduceCrests(state, data, crestFlags, ref totalCrestFlags, respectManual, source);
|
ReduceCrests(state, data, crestFlags, ref totalCrestFlags, respectManual, source);
|
||||||
|
ReduceParameters(state, data, parameterFlags, ref totalParameterFlags, respectManual, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalCustomizeFlags != 0)
|
if (totalCustomizeFlags != 0)
|
||||||
state.ModelData.ModelId = 0;
|
state.ModelData.ModelId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Get world-specific first and all-world afterwards. </summary>
|
/// <summary> Get world-specific first and all-world afterward. </summary>
|
||||||
private bool GetPlayerSet(ActorIdentifier identifier, [NotNullWhen(true)] out AutoDesignSet? set)
|
private bool GetPlayerSet(ActorIdentifier identifier, [NotNullWhen(true)] out AutoDesignSet? set)
|
||||||
{
|
{
|
||||||
switch (identifier.Type)
|
switch (identifier.Type)
|
||||||
|
|
@ -349,6 +352,24 @@ public class AutoDesignApplier : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ReduceParameters(ActorState state, in DesignData design, CustomizeParameterFlag parameterFlags,
|
||||||
|
ref CustomizeParameterFlag totalParameterFlags, bool respectManual, StateChanged.Source source)
|
||||||
|
{
|
||||||
|
parameterFlags &= ~totalParameterFlags;
|
||||||
|
if (parameterFlags == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var flag in CustomizeParameterExtensions.AllFlags)
|
||||||
|
{
|
||||||
|
if (!parameterFlags.HasFlag(flag))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!respectManual || state[flag] is not StateChanged.Source.Manual)
|
||||||
|
_state.ChangeCustomizeParameter(state, flag, design.Parameters[flag], source);
|
||||||
|
totalParameterFlags |= flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ReduceEquip(ActorState state, in DesignData design, EquipFlag equipFlags, ref EquipFlag totalEquipFlags, bool respectManual,
|
private void ReduceEquip(ActorState state, in DesignData design, EquipFlag equipFlags, ref EquipFlag totalEquipFlags, bool respectManual,
|
||||||
StateChanged.Source source, bool fromJobChange)
|
StateChanged.Source source, bool fromJobChange)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ public class Configuration : IPluginConfiguration, ISavable
|
||||||
public bool RevertManualChangesOnZoneChange { get; set; } = false;
|
public bool RevertManualChangesOnZoneChange { get; set; } = false;
|
||||||
public bool ShowQuickBarInTabs { get; set; } = true;
|
public bool ShowQuickBarInTabs { get; set; } = true;
|
||||||
public bool OpenWindowAtStart { get; set; } = false;
|
public bool OpenWindowAtStart { get; set; } = false;
|
||||||
|
public bool UseAdvancedParameters { get; set; } = false;
|
||||||
public ModifiableHotkey ToggleQuickDesignBar { get; set; } = new(VirtualKey.NO_KEY);
|
public ModifiableHotkey ToggleQuickDesignBar { get; set; } = new(VirtualKey.NO_KEY);
|
||||||
public DoubleModifier DeleteDesignModifier { get; set; } = new(ModifierHotkey.Control, ModifierHotkey.Shift);
|
public DoubleModifier DeleteDesignModifier { get; set; } = new(ModifierHotkey.Control, ModifierHotkey.Shift);
|
||||||
public ChangeLogDisplayType ChangeLogDisplayType { get; set; } = ChangeLogDisplayType.New;
|
public ChangeLogDisplayType ChangeLogDisplayType { get; set; } = ChangeLogDisplayType.New;
|
||||||
|
|
|
||||||
|
|
@ -54,20 +54,21 @@ public sealed class Design : DesignBase, ISavable
|
||||||
public new JObject JsonSerialize()
|
public new JObject JsonSerialize()
|
||||||
{
|
{
|
||||||
var ret = new JObject()
|
var ret = new JObject()
|
||||||
{
|
{
|
||||||
["FileVersion"] = FileVersion,
|
["FileVersion"] = FileVersion,
|
||||||
["Identifier"] = Identifier,
|
["Identifier"] = Identifier,
|
||||||
["CreationDate"] = CreationDate,
|
["CreationDate"] = CreationDate,
|
||||||
["LastEdit"] = LastEdit,
|
["LastEdit"] = LastEdit,
|
||||||
["Name"] = Name.Text,
|
["Name"] = Name.Text,
|
||||||
["Description"] = Description,
|
["Description"] = Description,
|
||||||
["Color"] = Color,
|
["Color"] = Color,
|
||||||
["Tags"] = JArray.FromObject(Tags),
|
["Tags"] = JArray.FromObject(Tags),
|
||||||
["WriteProtected"] = WriteProtected(),
|
["WriteProtected"] = WriteProtected(),
|
||||||
["Equipment"] = SerializeEquipment(),
|
["Equipment"] = SerializeEquipment(),
|
||||||
["Customize"] = SerializeCustomize(),
|
["Customize"] = SerializeCustomize(),
|
||||||
["Mods"] = SerializeMods(),
|
["Parameters"] = SerializeParameters(),
|
||||||
};
|
["Mods"] = SerializeMods(),
|
||||||
|
};
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,7 +134,8 @@ public sealed class Design : DesignBase, ISavable
|
||||||
LoadCustomize(customizations, json["Customize"], design, design.Name, true, false);
|
LoadCustomize(customizations, json["Customize"], design, design.Name, true, false);
|
||||||
LoadEquip(items, json["Equipment"], design, design.Name, true);
|
LoadEquip(items, json["Equipment"], design, design.Name, true);
|
||||||
LoadMods(json["Mods"], design);
|
LoadMods(json["Mods"], design);
|
||||||
design.Color = json["Color"]?.ToObject<string>() ?? string.Empty;
|
LoadParameters(json["Parameters"], design, design.Name);
|
||||||
|
design.Color = json["Color"]?.ToObject<string>() ?? string.Empty;
|
||||||
return design;
|
return design;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,9 @@ using OtterGui.Classes;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
using Penumbra.GameData.DataContainers;
|
using Penumbra.GameData.DataContainers;
|
||||||
|
|
||||||
namespace Glamourer.Designs;
|
namespace Glamourer.Designs;
|
||||||
|
|
@ -71,6 +73,8 @@ public class DesignBase
|
||||||
private CustomizeFlag _applyCustomize = CustomizeFlagExtensions.AllRelevant;
|
private CustomizeFlag _applyCustomize = CustomizeFlagExtensions.AllRelevant;
|
||||||
public CustomizeSet CustomizeSet { get; private set; }
|
public CustomizeSet CustomizeSet { get; private set; }
|
||||||
|
|
||||||
|
public CustomizeParameterFlag ApplyParameters { get; private set; }
|
||||||
|
|
||||||
internal CustomizeFlag ApplyCustomize
|
internal CustomizeFlag ApplyCustomize
|
||||||
{
|
{
|
||||||
get => _applyCustomize.FixApplication(CustomizeSet);
|
get => _applyCustomize.FixApplication(CustomizeSet);
|
||||||
|
|
@ -174,6 +178,9 @@ public class DesignBase
|
||||||
public bool DoApplyCrest(CrestFlag slot)
|
public bool DoApplyCrest(CrestFlag slot)
|
||||||
=> ApplyCrest.HasFlag(slot);
|
=> ApplyCrest.HasFlag(slot);
|
||||||
|
|
||||||
|
public bool DoApplyParameter(CustomizeParameterFlag flag)
|
||||||
|
=> ApplyParameters.HasFlag(flag);
|
||||||
|
|
||||||
internal bool SetApplyEquip(EquipSlot slot, bool value)
|
internal bool SetApplyEquip(EquipSlot slot, bool value)
|
||||||
{
|
{
|
||||||
var newValue = value ? ApplyEquip | slot.ToFlag() : ApplyEquip & ~slot.ToFlag();
|
var newValue = value ? ApplyEquip | slot.ToFlag() : ApplyEquip & ~slot.ToFlag();
|
||||||
|
|
@ -214,32 +221,48 @@ public class DesignBase
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal FlagRestrictionResetter TemporarilyRestrictApplication(EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags)
|
internal bool SetApplyParameter(CustomizeParameterFlag flag, bool value)
|
||||||
=> new(this, equipFlags, customizeFlags, crestFlags);
|
{
|
||||||
|
var newValue = value ? ApplyParameters | flag : ApplyParameters & ~flag;
|
||||||
|
if (newValue == ApplyParameters)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ApplyParameters = newValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal FlagRestrictionResetter TemporarilyRestrictApplication(EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags,
|
||||||
|
CustomizeParameterFlag parameterFlags)
|
||||||
|
=> new(this, equipFlags, customizeFlags, crestFlags, parameterFlags);
|
||||||
|
|
||||||
internal readonly struct FlagRestrictionResetter : IDisposable
|
internal readonly struct FlagRestrictionResetter : IDisposable
|
||||||
{
|
{
|
||||||
private readonly DesignBase _design;
|
private readonly DesignBase _design;
|
||||||
private readonly EquipFlag _oldEquipFlags;
|
private readonly EquipFlag _oldEquipFlags;
|
||||||
private readonly CustomizeFlag _oldCustomizeFlags;
|
private readonly CustomizeFlag _oldCustomizeFlags;
|
||||||
private readonly CrestFlag _oldCrestFlags;
|
private readonly CrestFlag _oldCrestFlags;
|
||||||
|
private readonly CustomizeParameterFlag _oldParameterFlags;
|
||||||
|
|
||||||
public FlagRestrictionResetter(DesignBase d, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags)
|
public FlagRestrictionResetter(DesignBase d, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags,
|
||||||
|
CustomizeParameterFlag parameterFlags)
|
||||||
{
|
{
|
||||||
_design = d;
|
_design = d;
|
||||||
_oldEquipFlags = d.ApplyEquip;
|
_oldEquipFlags = d.ApplyEquip;
|
||||||
_oldCustomizeFlags = d.ApplyCustomizeRaw;
|
_oldCustomizeFlags = d.ApplyCustomizeRaw;
|
||||||
_oldCrestFlags = d.ApplyCrest;
|
_oldCrestFlags = d.ApplyCrest;
|
||||||
|
_oldParameterFlags = d.ApplyParameters;
|
||||||
d.ApplyEquip &= equipFlags;
|
d.ApplyEquip &= equipFlags;
|
||||||
d.ApplyCustomize &= customizeFlags;
|
d.ApplyCustomize &= customizeFlags;
|
||||||
d.ApplyCrest &= crestFlags;
|
d.ApplyCrest &= crestFlags;
|
||||||
|
d.ApplyParameters &= parameterFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_design.ApplyEquip = _oldEquipFlags;
|
_design.ApplyEquip = _oldEquipFlags;
|
||||||
_design.ApplyCustomize = _oldCustomizeFlags;
|
_design.ApplyCustomize = _oldCustomizeFlags;
|
||||||
_design.ApplyCrest = _oldCrestFlags;
|
_design.ApplyCrest = _oldCrestFlags;
|
||||||
|
_design.ApplyParameters = _oldParameterFlags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,26 +279,16 @@ public class DesignBase
|
||||||
{
|
{
|
||||||
var ret = new JObject
|
var ret = new JObject
|
||||||
{
|
{
|
||||||
["FileVersion"] = FileVersion,
|
["FileVersion"] = FileVersion,
|
||||||
["Equipment"] = SerializeEquipment(),
|
["Equipment"] = SerializeEquipment(),
|
||||||
["Customize"] = SerializeCustomize(),
|
["Customize"] = SerializeCustomize(),
|
||||||
|
["Parameters"] = SerializeParameters(),
|
||||||
};
|
};
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JObject SerializeEquipment()
|
protected JObject SerializeEquipment()
|
||||||
{
|
{
|
||||||
static JObject Serialize(CustomItemId id, StainId stain, bool crest, bool apply, bool applyStain, bool applyCrest)
|
|
||||||
=> new()
|
|
||||||
{
|
|
||||||
["ItemId"] = id.Id,
|
|
||||||
["Stain"] = stain.Id,
|
|
||||||
["Crest"] = crest,
|
|
||||||
["Apply"] = apply,
|
|
||||||
["ApplyStain"] = applyStain,
|
|
||||||
["ApplyCrest"] = applyCrest,
|
|
||||||
};
|
|
||||||
|
|
||||||
var ret = new JObject();
|
var ret = new JObject();
|
||||||
if (_designData.IsHuman)
|
if (_designData.IsHuman)
|
||||||
{
|
{
|
||||||
|
|
@ -298,6 +311,17 @@ public class DesignBase
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
static JObject Serialize(CustomItemId id, StainId stain, bool crest, bool apply, bool applyStain, bool applyCrest)
|
||||||
|
=> new()
|
||||||
|
{
|
||||||
|
["ItemId"] = id.Id,
|
||||||
|
["Stain"] = stain.Id,
|
||||||
|
["Crest"] = crest,
|
||||||
|
["Apply"] = apply,
|
||||||
|
["ApplyStain"] = applyStain,
|
||||||
|
["ApplyCrest"] = applyCrest,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JObject SerializeCustomize()
|
protected JObject SerializeCustomize()
|
||||||
|
|
@ -329,6 +353,42 @@ public class DesignBase
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected JObject SerializeParameters()
|
||||||
|
{
|
||||||
|
var ret = new JObject();
|
||||||
|
|
||||||
|
foreach (var flag in CustomizeParameterExtensions.ValueFlags)
|
||||||
|
{
|
||||||
|
ret[flag.ToString()] = new JObject()
|
||||||
|
{
|
||||||
|
["Value"] = DesignData.Parameters[flag][0],
|
||||||
|
["Apply"] = DoApplyParameter(flag),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var flag in CustomizeParameterExtensions.PercentageFlags)
|
||||||
|
{
|
||||||
|
ret[flag.ToString()] = new JObject()
|
||||||
|
{
|
||||||
|
["Percentage"] = DesignData.Parameters[flag][0],
|
||||||
|
["Apply"] = DoApplyParameter(flag),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var flag in CustomizeParameterExtensions.TripleFlags)
|
||||||
|
{
|
||||||
|
ret[flag.ToString()] = new JObject()
|
||||||
|
{
|
||||||
|
["Red"] = DesignData.Parameters[flag][0],
|
||||||
|
["Green"] = DesignData.Parameters[flag][1],
|
||||||
|
["Blue"] = DesignData.Parameters[flag][2],
|
||||||
|
["Apply"] = DoApplyParameter(flag),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Deserialization
|
#region Deserialization
|
||||||
|
|
@ -348,9 +408,68 @@ public class DesignBase
|
||||||
var ret = new DesignBase(customizations, items);
|
var ret = new DesignBase(customizations, items);
|
||||||
LoadCustomize(customizations, json["Customize"], ret, "Temporary Design", false, true);
|
LoadCustomize(customizations, json["Customize"], ret, "Temporary Design", false, true);
|
||||||
LoadEquip(items, json["Equipment"], ret, "Temporary Design", true);
|
LoadEquip(items, json["Equipment"], ret, "Temporary Design", true);
|
||||||
|
LoadParameters(json["Parameters"], ret, "Temporary Design");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static void LoadParameters(JToken? parameters, DesignBase design, string name)
|
||||||
|
{
|
||||||
|
if (parameters == null)
|
||||||
|
{
|
||||||
|
design.ApplyParameters = 0;
|
||||||
|
design.GetDesignDataRef().Parameters = default;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var flag in CustomizeParameterExtensions.ValueFlags)
|
||||||
|
{
|
||||||
|
if (!TryGetToken(flag, out var token))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var value = token["Value"]?.ToObject<float>() ?? 0f;
|
||||||
|
design.GetDesignDataRef().Parameters[flag] = new Vector3(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var flag in CustomizeParameterExtensions.PercentageFlags)
|
||||||
|
{
|
||||||
|
if (!TryGetToken(flag, out var token))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var value = Math.Clamp(token["Percentage"]?.ToObject<float>() ?? 0f, 0f, 1f);
|
||||||
|
design.GetDesignDataRef().Parameters[flag] = new Vector3(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var flag in CustomizeParameterExtensions.TripleFlags)
|
||||||
|
{
|
||||||
|
if (!TryGetToken(flag, out var token))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var r = Math.Clamp(token["Red"]?.ToObject<float>() ?? 0f, 0, 1);
|
||||||
|
var g = Math.Clamp(token["Green"]?.ToObject<float>() ?? 0f, 0, 1);
|
||||||
|
var b = Math.Clamp(token["Blue"]?.ToObject<float>() ?? 0f, 0, 1);
|
||||||
|
design.GetDesignDataRef().Parameters[flag] = new Vector3(r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Load the token and set application.
|
||||||
|
bool TryGetToken(CustomizeParameterFlag flag, [NotNullWhen(true)] out JToken? token)
|
||||||
|
{
|
||||||
|
token = parameters![flag.ToString()];
|
||||||
|
if (token != null)
|
||||||
|
{
|
||||||
|
var apply = token["Apply"]?.ToObject<bool>() ?? false;
|
||||||
|
design.SetApplyParameter(flag, apply);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
design.ApplyParameters &= ~flag;
|
||||||
|
design.GetDesignDataRef().Parameters[flag] = Vector3.Zero;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected static void LoadEquip(ItemManager items, JToken? equip, DesignBase design, string name, bool allowUnknown)
|
protected static void LoadEquip(ItemManager items, JToken? equip, DesignBase design, string name, bool allowUnknown)
|
||||||
{
|
{
|
||||||
if (equip == null)
|
if (equip == null)
|
||||||
|
|
@ -514,8 +633,10 @@ public class DesignBase
|
||||||
_designData = DesignBase64Migration.MigrateBase64(items, humans, base64, out var equipFlags, out var customizeFlags,
|
_designData = DesignBase64Migration.MigrateBase64(items, humans, base64, out var equipFlags, out var customizeFlags,
|
||||||
out var writeProtected,
|
out var writeProtected,
|
||||||
out var applyHat, out var applyVisor, out var applyWeapon);
|
out var applyHat, out var applyVisor, out var applyWeapon);
|
||||||
ApplyEquip = equipFlags;
|
ApplyEquip = equipFlags;
|
||||||
ApplyCustomize = customizeFlags;
|
ApplyCustomize = customizeFlags;
|
||||||
|
ApplyParameters = 0;
|
||||||
|
ApplyCrest = 0;
|
||||||
SetWriteProtected(writeProtected);
|
SetWriteProtected(writeProtected);
|
||||||
SetApplyHatVisible(applyHat);
|
SetApplyHatVisible(applyHat);
|
||||||
SetApplyVisorToggle(applyVisor);
|
SetApplyVisorToggle(applyVisor);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Glamourer.GameData;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
using Glamourer.Utility;
|
using Glamourer.Utility;
|
||||||
|
|
@ -23,9 +24,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)
|
public JObject ShareJObject(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags, CustomizeParameterFlag parameterFlags)
|
||||||
{
|
{
|
||||||
var design = Convert(state, equipFlags, customizeFlags, crestFlags);
|
var design = Convert(state, equipFlags, customizeFlags, crestFlags, parameterFlags);
|
||||||
return ShareJObject(design);
|
return ShareJObject(design);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,21 +37,21 @@ public class DesignConverter(ItemManager _items, DesignManager _designs, Customi
|
||||||
=> ShareBase64(ShareJObject(design));
|
=> ShareBase64(ShareJObject(design));
|
||||||
|
|
||||||
public string ShareBase64(ActorState state)
|
public string ShareBase64(ActorState state)
|
||||||
=> ShareBase64(state, EquipFlagExtensions.All, CustomizeFlagExtensions.All, CrestExtensions.All);
|
=> ShareBase64(state, EquipFlagExtensions.All, CustomizeFlagExtensions.All, CrestExtensions.All, CustomizeParameterExtensions.All);
|
||||||
|
|
||||||
public string ShareBase64(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags)
|
public string ShareBase64(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags, CustomizeParameterFlag parameterFlags)
|
||||||
=> ShareBase64(state.ModelData, equipFlags, customizeFlags, crestFlags);
|
=> ShareBase64(state.ModelData, equipFlags, customizeFlags, crestFlags, parameterFlags);
|
||||||
|
|
||||||
public string ShareBase64(in DesignData data, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags)
|
public string ShareBase64(in DesignData data, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags, CustomizeParameterFlag parameterFlags)
|
||||||
{
|
{
|
||||||
var design = Convert(data, equipFlags, customizeFlags, crestFlags);
|
var design = Convert(data, equipFlags, customizeFlags, crestFlags, parameterFlags);
|
||||||
return ShareBase64(ShareJObject(design));
|
return ShareBase64(ShareJObject(design));
|
||||||
}
|
}
|
||||||
|
|
||||||
public DesignBase Convert(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags)
|
public DesignBase Convert(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags, CustomizeParameterFlag parameterFlags)
|
||||||
=> Convert(state.ModelData, equipFlags, customizeFlags, crestFlags);
|
=> Convert(state.ModelData, equipFlags, customizeFlags, crestFlags, parameterFlags);
|
||||||
|
|
||||||
public DesignBase Convert(in DesignData data, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags)
|
public DesignBase Convert(in DesignData data, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags, CustomizeParameterFlag parameterFlags)
|
||||||
{
|
{
|
||||||
var design = _designs.CreateTemporary();
|
var design = _designs.CreateTemporary();
|
||||||
design.ApplyEquip = equipFlags & EquipFlagExtensions.All;
|
design.ApplyEquip = equipFlags & EquipFlagExtensions.All;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using Glamourer.GameData;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
|
|
@ -10,30 +11,31 @@ namespace Glamourer.Designs;
|
||||||
|
|
||||||
public unsafe struct DesignData
|
public unsafe struct DesignData
|
||||||
{
|
{
|
||||||
private string _nameHead = string.Empty;
|
private string _nameHead = string.Empty;
|
||||||
private string _nameBody = string.Empty;
|
private string _nameBody = string.Empty;
|
||||||
private string _nameHands = string.Empty;
|
private string _nameHands = string.Empty;
|
||||||
private string _nameLegs = string.Empty;
|
private string _nameLegs = string.Empty;
|
||||||
private string _nameFeet = string.Empty;
|
private string _nameFeet = string.Empty;
|
||||||
private string _nameEars = string.Empty;
|
private string _nameEars = string.Empty;
|
||||||
private string _nameNeck = string.Empty;
|
private string _nameNeck = string.Empty;
|
||||||
private string _nameWrists = string.Empty;
|
private string _nameWrists = string.Empty;
|
||||||
private string _nameRFinger = string.Empty;
|
private string _nameRFinger = string.Empty;
|
||||||
private string _nameLFinger = string.Empty;
|
private string _nameLFinger = string.Empty;
|
||||||
private string _nameMainhand = string.Empty;
|
private string _nameMainhand = string.Empty;
|
||||||
private string _nameOffhand = string.Empty;
|
private string _nameOffhand = string.Empty;
|
||||||
private fixed uint _itemIds[12];
|
private fixed uint _itemIds[12];
|
||||||
private fixed ushort _iconIds[12];
|
private fixed ushort _iconIds[12];
|
||||||
private fixed byte _equipmentBytes[48];
|
private fixed byte _equipmentBytes[48];
|
||||||
public CustomizeArray Customize = CustomizeArray.Default;
|
public CustomizeParameterData Parameters;
|
||||||
public uint ModelId;
|
public CustomizeArray Customize = CustomizeArray.Default;
|
||||||
public CrestFlag CrestVisibility;
|
public uint ModelId;
|
||||||
private SecondaryId _secondaryMainhand;
|
public CrestFlag CrestVisibility;
|
||||||
private SecondaryId _secondaryOffhand;
|
private SecondaryId _secondaryMainhand;
|
||||||
private FullEquipType _typeMainhand;
|
private SecondaryId _secondaryOffhand;
|
||||||
private FullEquipType _typeOffhand;
|
private FullEquipType _typeMainhand;
|
||||||
private byte _states;
|
private FullEquipType _typeOffhand;
|
||||||
public bool IsHuman = true;
|
private byte _states;
|
||||||
|
public bool IsHuman = true;
|
||||||
|
|
||||||
public DesignData()
|
public DesignData()
|
||||||
{ }
|
{ }
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,13 @@ using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
|
using Glamourer.GameData;
|
||||||
using Glamourer.Interop.Penumbra;
|
using Glamourer.Interop.Penumbra;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
|
|
@ -17,6 +20,7 @@ using OtterGui;
|
||||||
using Penumbra.GameData.DataContainers;
|
using Penumbra.GameData.DataContainers;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
|
using static Glamourer.State.ActorState;
|
||||||
|
|
||||||
namespace Glamourer.Designs;
|
namespace Glamourer.Designs;
|
||||||
|
|
||||||
|
|
@ -424,6 +428,20 @@ public class DesignManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Change a customize parameter. </summary>
|
||||||
|
public void ChangeCustomizeParameter(Design design, CustomizeParameterFlag flag, Vector3 value)
|
||||||
|
{
|
||||||
|
var old = design.DesignData.Parameters[flag];
|
||||||
|
if (!design.GetDesignDataRef().Parameters.Set(flag, value))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var @new = design.DesignData.Parameters[flag];
|
||||||
|
design.LastEdit = DateTimeOffset.UtcNow;
|
||||||
|
Glamourer.Log.Debug($"Set customize parameter {flag} in design {design.Identifier} from {old} to {@new}.");
|
||||||
|
_saveService.QueueSave(design);
|
||||||
|
_event.Invoke(DesignChanged.Type.Parameter, design, (old, @new, flag));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Change whether to apply a specific equipment piece. </summary>
|
/// <summary> Change whether to apply a specific equipment piece. </summary>
|
||||||
public void ChangeApplyEquip(Design design, EquipSlot slot, bool value)
|
public void ChangeApplyEquip(Design design, EquipSlot slot, bool value)
|
||||||
{
|
{
|
||||||
|
|
@ -529,6 +547,18 @@ public class DesignManager
|
||||||
_event.Invoke(DesignChanged.Type.Other, design, (metaIndex, true, value));
|
_event.Invoke(DesignChanged.Type.Other, design, (metaIndex, true, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Change the application value of a customize parameter. </summary>
|
||||||
|
public void ChangeApplyParameter(Design design, CustomizeParameterFlag flag, bool value)
|
||||||
|
{
|
||||||
|
if (!design.SetApplyParameter(flag, value))
|
||||||
|
return;
|
||||||
|
|
||||||
|
design.LastEdit = DateTimeOffset.UtcNow;
|
||||||
|
_saveService.QueueSave(design);
|
||||||
|
Glamourer.Log.Debug($"Set applying of parameter {flag} to {value}.");
|
||||||
|
_event.Invoke(DesignChanged.Type.ApplyParameter, design, flag);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Apply an entire design based on its appliance rules piece by piece. </summary>
|
/// <summary> Apply an entire design based on its appliance rules piece by piece. </summary>
|
||||||
public void ApplyDesign(Design design, DesignBase other)
|
public void ApplyDesign(Design design, DesignBase other)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,9 @@ public sealed class DesignChanged()
|
||||||
/// <summary> An existing design had a crest visibility changed. Data is the old crest visibility, the new crest visibility and the slot [(bool, bool, EquipSlot)]. </summary>
|
/// <summary> An existing design had a crest visibility changed. Data is the old crest visibility, the new crest visibility and the slot [(bool, bool, EquipSlot)]. </summary>
|
||||||
Crest,
|
Crest,
|
||||||
|
|
||||||
|
/// <summary> An existing design had a customize parameter changed. Data is the old value, the new value and the flag [(Vector3, Vector3, CustomizeParameterFlag)]. </summary>
|
||||||
|
Parameter,
|
||||||
|
|
||||||
/// <summary> An existing design changed whether a specific customization is applied. Data is the type of customization [CustomizeIndex]. </summary>
|
/// <summary> An existing design changed whether a specific customization is applied. Data is the type of customization [CustomizeIndex]. </summary>
|
||||||
ApplyCustomize,
|
ApplyCustomize,
|
||||||
|
|
||||||
|
|
@ -77,6 +80,9 @@ public sealed class DesignChanged()
|
||||||
/// <summary> An existing design changed whether a specific crest visibility is applied. Data is the slot of the equipment [EquipSlot]. </summary>
|
/// <summary> An existing design changed whether a specific crest visibility is applied. Data is the slot of the equipment [EquipSlot]. </summary>
|
||||||
ApplyCrest,
|
ApplyCrest,
|
||||||
|
|
||||||
|
/// <summary> An existing design changed whether a specific customize parameter is applied. Data is the flag for the parameter [CustomizeParameterFlag]. </summary>
|
||||||
|
ApplyParameter,
|
||||||
|
|
||||||
/// <summary> An existing design changed its write protection status. Data is the new value [bool]. </summary>
|
/// <summary> An existing design changed its write protection status. Data is the new value [bool]. </summary>
|
||||||
WriteProtection,
|
WriteProtection,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,9 @@ public sealed class StateChanged()
|
||||||
/// <summary> 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)]. </summary>
|
/// <summary> 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)]. </summary>
|
||||||
Crest,
|
Crest,
|
||||||
|
|
||||||
|
/// <summary> A characters saved state had its customize parameter changed. Data is the old value, the new value and the type [(Vector3, Vector3, CustomizeParameterFlag)]. </summary>
|
||||||
|
Parameter,
|
||||||
|
|
||||||
/// <summary> A characters saved state had a design applied. This means everything may have changed. Data is the applied design. [DesignBase] </summary>
|
/// <summary> A characters saved state had a design applied. This means everything may have changed. Data is the applied design. [DesignBase] </summary>
|
||||||
Design,
|
Design,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -159,8 +159,8 @@ public class DesignQuickBar : Window, IDisposable
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var (applyGear, applyCustomize, applyCrest) = UiHelpers.ConvertKeysToFlags();
|
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
|
||||||
using var _ = design!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest);
|
using var _ = design!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest, applyParameters);
|
||||||
_stateManager.ApplyDesign(design, state, StateChanged.Source.Manual);
|
_stateManager.ApplyDesign(design, state, StateChanged.Source.Manual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,8 @@ public class ActorPanel(
|
||||||
DesignManager _designManager,
|
DesignManager _designManager,
|
||||||
ImportService _importService,
|
ImportService _importService,
|
||||||
ICondition _conditions,
|
ICondition _conditions,
|
||||||
DictModelChara _modelChara)
|
DictModelChara _modelChara,
|
||||||
|
CustomizeParameterDrawer _parameterDrawer)
|
||||||
{
|
{
|
||||||
private ActorIdentifier _identifier;
|
private ActorIdentifier _identifier;
|
||||||
private string _actorName = string.Empty;
|
private string _actorName = string.Empty;
|
||||||
|
|
@ -127,6 +128,7 @@ public class ActorPanel(
|
||||||
{
|
{
|
||||||
DrawCustomizationsHeader();
|
DrawCustomizationsHeader();
|
||||||
DrawEquipmentHeader();
|
DrawEquipmentHeader();
|
||||||
|
DrawParameterHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawCustomizationsHeader()
|
private void DrawCustomizationsHeader()
|
||||||
|
|
@ -169,6 +171,14 @@ public class ActorPanel(
|
||||||
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawParameterHeader()
|
||||||
|
{
|
||||||
|
if (!_config.UseAdvancedParameters || !ImGui.CollapsingHeader("Advanced Customizations"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_parameterDrawer.Draw(_stateManager, _state!);
|
||||||
|
}
|
||||||
|
|
||||||
private void DrawEquipmentMetaToggles()
|
private void DrawEquipmentMetaToggles()
|
||||||
{
|
{
|
||||||
using (_ = ImRaii.Group())
|
using (_ = ImRaii.Group())
|
||||||
|
|
@ -302,9 +312,9 @@ public class ActorPanel(
|
||||||
private void SaveDesignOpen()
|
private void SaveDesignOpen()
|
||||||
{
|
{
|
||||||
ImGui.OpenPopup("Save as Design");
|
ImGui.OpenPopup("Save as Design");
|
||||||
_newName = _state!.Identifier.ToName();
|
_newName = _state!.Identifier.ToName();
|
||||||
var (applyGear, applyCustomize, applyCrest) = UiHelpers.ConvertKeysToFlags();
|
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
|
||||||
_newDesign = _converter.Convert(_state, applyGear, applyCustomize, applyCrest);
|
_newDesign = _converter.Convert(_state, applyGear, applyCustomize, applyCrest, applyParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveDesignDrawPopup()
|
private void SaveDesignDrawPopup()
|
||||||
|
|
@ -339,8 +349,8 @@ public class ActorPanel(
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var (applyGear, applyCustomize, applyCrest) = UiHelpers.ConvertKeysToFlags();
|
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
|
||||||
var text = _converter.ShareBase64(_state!, applyGear, applyCustomize, applyCrest);
|
var text = _converter.ShareBase64(_state!, applyGear, applyCustomize, applyCrest, applyParameters);
|
||||||
ImGui.SetClipboardText(text);
|
ImGui.SetClipboardText(text);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -379,9 +389,9 @@ 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) = UiHelpers.ConvertKeysToFlags();
|
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(_converter.Convert(_state!, applyGear, applyCustomize, applyCrest), state,
|
_stateManager.ApplyDesign(_converter.Convert(_state!, applyGear, applyCustomize, applyCrest, applyParameters), state,
|
||||||
StateChanged.Source.Manual);
|
StateChanged.Source.Manual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -397,9 +407,9 @@ 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) = UiHelpers.ConvertKeysToFlags();
|
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(_converter.Convert(_state!, applyGear, applyCustomize, applyCrest), state,
|
_stateManager.ApplyDesign(_converter.Convert(_state!, applyGear, applyCustomize, applyCrest, applyParameters), state,
|
||||||
StateChanged.Source.Manual);
|
StateChanged.Source.Manual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,7 @@ public class SetPanel(
|
||||||
var size = new Vector2(ImGui.GetFrameHeight());
|
var size = new Vector2(ImGui.GetFrameHeight());
|
||||||
size.X += ImGuiHelpers.GlobalScale;
|
size.X += ImGuiHelpers.GlobalScale;
|
||||||
|
|
||||||
var (equipFlags, customizeFlags, _, _, _, _, _) = design.ApplyWhat();
|
var (equipFlags, customizeFlags, _, _, _, _, _, _) = design.ApplyWhat();
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
foreach (var slot in EquipSlotExtensions.EqdpSlots.Append(EquipSlot.MainHand).Append(EquipSlot.OffHand))
|
foreach (var slot in EquipSlotExtensions.EqdpSlots.Append(EquipSlot.MainHand).Append(EquipSlot.OffHand))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,18 @@ public class ActiveStatePanel(StateManager _stateManager, ObjectManager _objectM
|
||||||
PrintRow(type.ToDefaultName(), state.BaseData.Customize[type].Value, state.ModelData.Customize[type].Value, state[type]);
|
PrintRow(type.ToDefaultName(), state.BaseData.Customize[type].Value, state.ModelData.Customize[type].Value, state[type]);
|
||||||
ImGui.TableNextRow();
|
ImGui.TableNextRow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var crest in CrestExtensions.AllRelevantSet)
|
||||||
|
{
|
||||||
|
PrintRow(crest.ToLabel(), state.BaseData.Crest(crest), state.ModelData.Crest(crest), state[crest]);
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var flag in CustomizeParameterExtensions.AllFlags)
|
||||||
|
{
|
||||||
|
PrintRow(flag.ToString(), state.BaseData.Parameters[flag], state.ModelData.Parameters[flag], state[flag]);
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||||
|
using FFXIVClientStructs.FFXIV.Shader;
|
||||||
|
using Glamourer.GameData;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
using Glamourer.Interop.Structs;
|
using Glamourer.Interop.Structs;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
@ -78,6 +80,28 @@ public unsafe class ModelEvaluationPanel(
|
||||||
DrawEquip(actor, model);
|
DrawEquip(actor, model);
|
||||||
DrawCustomize(actor, model);
|
DrawCustomize(actor, model);
|
||||||
DrawCrests(actor, model);
|
DrawCrests(actor, model);
|
||||||
|
DrawParameters(actor, model);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawParameters(Actor actor, Model model)
|
||||||
|
{
|
||||||
|
if (!model.IsHuman)
|
||||||
|
return;
|
||||||
|
if (model.AsHuman->CustomizeParameterCBuffer == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var ptr = (CustomizeParameter*)model.AsHuman->CustomizeParameterCBuffer->UnsafeSourcePointer;
|
||||||
|
if (ptr == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var convert = CustomizeParameterData.FromParameters(*ptr);
|
||||||
|
foreach (var flag in CustomizeParameterExtensions.AllFlags)
|
||||||
|
{
|
||||||
|
ImGuiUtil.DrawTableColumn(flag.ToString());
|
||||||
|
ImGuiUtil.DrawTableColumn(string.Empty);
|
||||||
|
ImGuiUtil.DrawTableColumn(convert[flag].ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawVisor(Actor actor, Model model)
|
private void DrawVisor(Actor actor, Model model)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ using FFXIVClientStructs.FFXIV.Client.System.Framework;
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
|
using Glamourer.GameData;
|
||||||
using Glamourer.Gui.Customization;
|
using Glamourer.Gui.Customization;
|
||||||
using Glamourer.Gui.Equipment;
|
using Glamourer.Gui.Equipment;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
|
|
@ -21,9 +22,20 @@ using Penumbra.GameData.Enums;
|
||||||
|
|
||||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||||
|
|
||||||
public class DesignPanel(DesignFileSystemSelector _selector, CustomizationDrawer _customizationDrawer, DesignManager _manager,
|
public class DesignPanel(
|
||||||
ObjectManager _objects, StateManager _state, EquipmentDrawer _equipmentDrawer, ModAssociationsTab _modAssociations,
|
DesignFileSystemSelector _selector,
|
||||||
DesignDetailTab _designDetails, DesignConverter _converter, ImportService _importService, MultiDesignPanel _multiDesignPanel)
|
CustomizationDrawer _customizationDrawer,
|
||||||
|
DesignManager _manager,
|
||||||
|
ObjectManager _objects,
|
||||||
|
StateManager _state,
|
||||||
|
EquipmentDrawer _equipmentDrawer,
|
||||||
|
ModAssociationsTab _modAssociations,
|
||||||
|
Configuration _config,
|
||||||
|
DesignDetailTab _designDetails,
|
||||||
|
DesignConverter _converter,
|
||||||
|
ImportService _importService,
|
||||||
|
MultiDesignPanel _multiDesignPanel,
|
||||||
|
CustomizeParameterDrawer _parameterDrawer)
|
||||||
{
|
{
|
||||||
private readonly FileDialogManager _fileDialog = new();
|
private readonly FileDialogManager _fileDialog = new();
|
||||||
|
|
||||||
|
|
@ -152,11 +164,20 @@ public class DesignPanel(DesignFileSystemSelector _selector, CustomizationDrawer
|
||||||
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawCustomizeParameters()
|
||||||
|
{
|
||||||
|
if (!_config.UseAdvancedParameters || !ImGui.CollapsingHeader("Advanced Customization"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_parameterDrawer.Draw(_manager, _selector.Selected!);
|
||||||
|
}
|
||||||
|
|
||||||
private void DrawCustomizeApplication()
|
private void DrawCustomizeApplication()
|
||||||
{
|
{
|
||||||
var set = _selector.Selected!.CustomizeSet;
|
var set = _selector.Selected!.CustomizeSet;
|
||||||
var available = set.SettingAvailable | CustomizeFlag.Clan | CustomizeFlag.Gender | CustomizeFlag.BodyType;
|
var available = set.SettingAvailable | CustomizeFlag.Clan | CustomizeFlag.Gender | CustomizeFlag.BodyType;
|
||||||
var flags = _selector.Selected!.ApplyCustomizeExcludingBodyType == 0 ? 0 : (_selector.Selected!.ApplyCustomize & available) == available ? 3 : 1;
|
var flags = _selector.Selected!.ApplyCustomizeExcludingBodyType == 0 ? 0 :
|
||||||
|
(_selector.Selected!.ApplyCustomize & available) == available ? 3 : 1;
|
||||||
if (ImGui.CheckboxFlags("Apply All Customizations", ref flags, 3))
|
if (ImGui.CheckboxFlags("Apply All Customizations", ref flags, 3))
|
||||||
{
|
{
|
||||||
var newFlags = flags == 3;
|
var newFlags = flags == 3;
|
||||||
|
|
@ -205,6 +226,9 @@ public class DesignPanel(DesignFileSystemSelector _selector, CustomizationDrawer
|
||||||
DrawCustomizeApplication();
|
DrawCustomizeApplication();
|
||||||
ImGui.NewLine();
|
ImGui.NewLine();
|
||||||
DrawCrestApplication();
|
DrawCrestApplication();
|
||||||
|
ImGui.NewLine();
|
||||||
|
if (_config.UseAdvancedParameters)
|
||||||
|
DrawMetaApplication();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.SameLine(ImGui.GetContentRegionAvail().X / 2);
|
ImGui.SameLine(ImGui.GetContentRegionAvail().X / 2);
|
||||||
|
|
@ -248,27 +272,47 @@ public class DesignPanel(DesignFileSystemSelector _selector, CustomizationDrawer
|
||||||
EquipSlotExtensions.FullSlots);
|
EquipSlotExtensions.FullSlots);
|
||||||
|
|
||||||
ImGui.NewLine();
|
ImGui.NewLine();
|
||||||
const uint all = 0x0Fu;
|
if (_config.UseAdvancedParameters)
|
||||||
var flags = (_selector.Selected!.DoApplyHatVisible() ? 0x01u : 0x00)
|
DrawParameterApplication();
|
||||||
| (_selector.Selected!.DoApplyVisorToggle() ? 0x02u : 0x00)
|
else
|
||||||
| (_selector.Selected!.DoApplyWeaponVisible() ? 0x04u : 0x00)
|
DrawMetaApplication();
|
||||||
| (_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!, ActorState.MetaIndex.HatState, apply);
|
|
||||||
|
|
||||||
apply = bigChange ? (flags & 0x02) == 0x02 : _selector.Selected!.DoApplyVisorToggle();
|
private void DrawMetaApplication()
|
||||||
if (ImGui.Checkbox("Apply Visor State", ref apply) || bigChange)
|
{
|
||||||
_manager.ChangeApplyMeta(_selector.Selected!, ActorState.MetaIndex.VisorState, apply);
|
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!, ActorState.MetaIndex.HatState, apply);
|
||||||
|
|
||||||
apply = bigChange ? (flags & 0x04) == 0x04 : _selector.Selected!.DoApplyWeaponVisible();
|
apply = bigChange ? (flags & 0x02) == 0x02 : _selector.Selected!.DoApplyVisorToggle();
|
||||||
if (ImGui.Checkbox("Apply Weapon Visibility", ref apply) || bigChange)
|
if (ImGui.Checkbox("Apply Visor State", ref apply) || bigChange)
|
||||||
_manager.ChangeApplyMeta(_selector.Selected!, ActorState.MetaIndex.WeaponState, apply);
|
_manager.ChangeApplyMeta(_selector.Selected!, ActorState.MetaIndex.VisorState, apply);
|
||||||
|
|
||||||
apply = bigChange ? (flags & 0x08) == 0x08 : _selector.Selected!.DoApplyWetness();
|
apply = bigChange ? (flags & 0x04) == 0x04 : _selector.Selected!.DoApplyWeaponVisible();
|
||||||
if (ImGui.Checkbox("Apply Wetness", ref apply) || bigChange)
|
if (ImGui.Checkbox("Apply Weapon Visibility", ref apply) || bigChange)
|
||||||
_manager.ChangeApplyMeta(_selector.Selected!, ActorState.MetaIndex.Wetness, apply);
|
_manager.ChangeApplyMeta(_selector.Selected!, ActorState.MetaIndex.WeaponState, apply);
|
||||||
|
|
||||||
|
apply = bigChange ? (flags & 0x08) == 0x08 : _selector.Selected!.DoApplyWetness();
|
||||||
|
if (ImGui.Checkbox("Apply Wetness", ref apply) || bigChange)
|
||||||
|
_manager.ChangeApplyMeta(_selector.Selected!, ActorState.MetaIndex.Wetness, apply);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawParameterApplication()
|
||||||
|
{
|
||||||
|
var flags = (uint)_selector.Selected!.ApplyParameters;
|
||||||
|
var bigChange = ImGui.CheckboxFlags("Apply All Customize Parameters", ref flags, (uint)CustomizeParameterExtensions.All);
|
||||||
|
foreach (var flag in CustomizeParameterExtensions.AllFlags)
|
||||||
|
{
|
||||||
|
var apply = bigChange ? ((CustomizeParameterFlag)flags).HasFlag(flag) : _selector.Selected!.DoApplyParameter(flag);
|
||||||
|
if (ImGui.Checkbox($"Apply {flag}", ref apply) || bigChange)
|
||||||
|
_manager.ChangeApplyParameter(_selector.Selected!, flag, apply);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -316,6 +360,7 @@ public class DesignPanel(DesignFileSystemSelector _selector, CustomizationDrawer
|
||||||
DrawButtonRow();
|
DrawButtonRow();
|
||||||
DrawCustomize();
|
DrawCustomize();
|
||||||
DrawEquipment();
|
DrawEquipment();
|
||||||
|
DrawCustomizeParameters();
|
||||||
_designDetails.Draw();
|
_designDetails.Draw();
|
||||||
DrawApplicationRules();
|
DrawApplicationRules();
|
||||||
_modAssociations.Draw();
|
_modAssociations.Draw();
|
||||||
|
|
@ -386,8 +431,8 @@ public class DesignPanel(DesignFileSystemSelector _selector, CustomizationDrawer
|
||||||
|
|
||||||
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
||||||
{
|
{
|
||||||
var (applyGear, applyCustomize, applyCrest) = UiHelpers.ConvertKeysToFlags();
|
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
|
||||||
using var _ = _selector.Selected!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest);
|
using var _ = _selector.Selected!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest, applyParameters);
|
||||||
_state.ApplyDesign(_selector.Selected!, state, StateChanged.Source.Manual);
|
_state.ApplyDesign(_selector.Selected!, state, StateChanged.Source.Manual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -405,8 +450,8 @@ public class DesignPanel(DesignFileSystemSelector _selector, CustomizationDrawer
|
||||||
|
|
||||||
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
||||||
{
|
{
|
||||||
var (applyGear, applyCustomize, applyCrest) = UiHelpers.ConvertKeysToFlags();
|
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
|
||||||
using var _ = _selector.Selected!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest);
|
using var _ = _selector.Selected!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest, applyParameters);
|
||||||
_state.ApplyDesign(_selector.Selected!, state, StateChanged.Source.Manual);
|
_state.ApplyDesign(_selector.Selected!, state, StateChanged.Source.Manual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,9 +89,9 @@ public class NpcPanel(
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var (applyGear, applyCustomize, applyCrest) = UiHelpers.ConvertKeysToFlags();
|
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
|
||||||
var data = ToDesignData();
|
var data = ToDesignData();
|
||||||
var text = _converter.ShareBase64(data, applyGear, applyCustomize, applyCrest);
|
var text = _converter.ShareBase64(data, applyGear, applyCustomize, applyCrest, applyParameters);
|
||||||
ImGui.SetClipboardText(text);
|
ImGui.SetClipboardText(text);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -105,11 +105,11 @@ 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) = UiHelpers.ConvertKeysToFlags();
|
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
|
||||||
|
|
||||||
var data = ToDesignData();
|
var data = ToDesignData();
|
||||||
_newDesign = _converter.Convert(data, applyGear, applyCustomize, applyCrest);
|
_newDesign = _converter.Convert(data, applyGear, applyCustomize, applyCrest, applyParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveDesignDrawPopup()
|
private void SaveDesignDrawPopup()
|
||||||
|
|
@ -198,8 +198,8 @@ 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, applyCrest) = UiHelpers.ConvertKeysToFlags();
|
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
|
||||||
var design = _converter.Convert(ToDesignData(), applyGear, applyCustomize, applyCrest);
|
var design = _converter.Convert(ToDesignData(), applyGear, applyCustomize, applyCrest, applyParameters);
|
||||||
_state.ApplyDesign(design, state, StateChanged.Source.Manual);
|
_state.ApplyDesign(design, state, StateChanged.Source.Manual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -217,8 +217,8 @@ 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, applyCrest) = UiHelpers.ConvertKeysToFlags();
|
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
|
||||||
var design = _converter.Convert(ToDesignData(), applyGear, applyCustomize, applyCrest);
|
var design = _converter.Convert(ToDesignData(), applyGear, applyCustomize, applyCrest, applyParameters);
|
||||||
_state.ApplyDesign(design, state, StateChanged.Source.Manual);
|
_state.ApplyDesign(design, state, StateChanged.Source.Manual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,9 @@ public class SettingsTab : ITab
|
||||||
if (!child)
|
if (!child)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Checkbox("Enable Auto Designs", "Enable the application of designs associated to characters in the Automation tab to be applied automatically.",
|
Checkbox("Enable Auto Designs",
|
||||||
_config.EnableAutoDesigns, v => _config.EnableAutoDesigns = v);
|
"Enable the application of designs associated to characters in the Automation tab to be applied automatically.",
|
||||||
|
_config.EnableAutoDesigns, v => _config.EnableAutoDesigns = v);
|
||||||
ImGui.NewLine();
|
ImGui.NewLine();
|
||||||
ImGui.NewLine();
|
ImGui.NewLine();
|
||||||
ImGui.NewLine();
|
ImGui.NewLine();
|
||||||
|
|
@ -97,6 +98,8 @@ public class SettingsTab : ITab
|
||||||
Checkbox("Revert Manual Changes on Zone Change",
|
Checkbox("Revert Manual Changes on Zone Change",
|
||||||
"Restores the old behaviour of reverting your character to its game or automation base whenever you change the zone.",
|
"Restores the old behaviour of reverting your character to its game or automation base whenever you change the zone.",
|
||||||
_config.RevertManualChangesOnZoneChange, v => _config.RevertManualChangesOnZoneChange = v);
|
_config.RevertManualChangesOnZoneChange, v => _config.RevertManualChangesOnZoneChange = v);
|
||||||
|
Checkbox("Enable Advanced Customization Options", "Enable the display and editing of advanced customization options like arbitrary colors.",
|
||||||
|
_config.UseAdvancedParameters, v => _config.UseAdvancedParameters = v);
|
||||||
ImGui.NewLine();
|
ImGui.NewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,7 +111,8 @@ public class SettingsTab : ITab
|
||||||
EphemeralCheckbox("Show Quick Design Bar",
|
EphemeralCheckbox("Show Quick Design Bar",
|
||||||
"Show a bar separate from the main window that allows you to quickly apply designs or revert your character and target.",
|
"Show a bar separate from the main window that allows you to quickly apply designs or revert your character and target.",
|
||||||
_config.Ephemeral.ShowDesignQuickBar, v => _config.Ephemeral.ShowDesignQuickBar = v);
|
_config.Ephemeral.ShowDesignQuickBar, v => _config.Ephemeral.ShowDesignQuickBar = v);
|
||||||
EphemeralCheckbox("Lock Quick Design Bar", "Prevent the quick design bar from being moved and lock it in place.", _config.Ephemeral.LockDesignQuickBar,
|
EphemeralCheckbox("Lock Quick Design Bar", "Prevent the quick design bar from being moved and lock it in place.",
|
||||||
|
_config.Ephemeral.LockDesignQuickBar,
|
||||||
v => _config.Ephemeral.LockDesignQuickBar = v);
|
v => _config.Ephemeral.LockDesignQuickBar = v);
|
||||||
if (Widget.ModifiableKeySelector("Hotkey to Toggle Quick Design Bar", "Set a hotkey that opens or closes the quick design bar.",
|
if (Widget.ModifiableKeySelector("Hotkey to Toggle Quick Design Bar", "Set a hotkey that opens or closes the quick design bar.",
|
||||||
100 * ImGuiHelpers.GlobalScale,
|
100 * ImGuiHelpers.GlobalScale,
|
||||||
|
|
@ -138,7 +142,8 @@ public class SettingsTab : ITab
|
||||||
_config.HideWindowInCutscene = v;
|
_config.HideWindowInCutscene = v;
|
||||||
_uiBuilder.DisableCutsceneUiHide = !v;
|
_uiBuilder.DisableCutsceneUiHide = !v;
|
||||||
});
|
});
|
||||||
EphemeralCheckbox("Lock Main Window", "Prevent the main window from being moved and lock it in place.", _config.Ephemeral.LockMainWindow,
|
EphemeralCheckbox("Lock Main Window", "Prevent the main window from being moved and lock it in place.",
|
||||||
|
_config.Ephemeral.LockMainWindow,
|
||||||
v => _config.Ephemeral.LockMainWindow = v);
|
v => _config.Ephemeral.LockMainWindow = v);
|
||||||
Checkbox("Open Main Window at Game Start", "Whether the main Glamourer window should be open or closed after launching the game.",
|
Checkbox("Open Main Window at Game Start", "Whether the main Glamourer window should be open or closed after launching the game.",
|
||||||
_config.OpenWindowAtStart, v => _config.OpenWindowAtStart = v);
|
_config.OpenWindowAtStart, v => _config.OpenWindowAtStart = v);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
|
using Glamourer.GameData;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using Glamourer.Unlocks;
|
using Glamourer.Unlocks;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
@ -98,13 +99,13 @@ public static class UiHelpers
|
||||||
return (currentValue != newValue, currentApply != newApply);
|
return (currentValue != newValue, currentApply != newApply);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (EquipFlag, CustomizeFlag, CrestFlag) ConvertKeysToFlags()
|
public static (EquipFlag, CustomizeFlag, CrestFlag, CustomizeParameterFlag) ConvertKeysToFlags()
|
||||||
=> (ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift) switch
|
=> (ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift) switch
|
||||||
{
|
{
|
||||||
(false, false) => (EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant, CrestExtensions.All),
|
(false, false) => (EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant, CrestExtensions.All, CustomizeParameterExtensions.All),
|
||||||
(true, true) => (EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant, CrestExtensions.All),
|
(true, true) => (EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant, CrestExtensions.All, CustomizeParameterExtensions.All),
|
||||||
(true, false) => (EquipFlagExtensions.All, (CustomizeFlag)0, CrestExtensions.All),
|
(true, false) => (EquipFlagExtensions.All, (CustomizeFlag)0, CrestExtensions.All, 0),
|
||||||
(false, true) => ((EquipFlag)0, CustomizeFlagExtensions.AllRelevant, 0),
|
(false, true) => ((EquipFlag)0, CustomizeFlagExtensions.AllRelevant, 0, CustomizeParameterExtensions.All),
|
||||||
};
|
};
|
||||||
|
|
||||||
public static (bool, bool) ConvertKeysToBool()
|
public static (bool, bool) ConvertKeysToBool()
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ public unsafe class ChangeCustomizeService : EventWrapperRef2<Model, CustomizeAr
|
||||||
private readonly PenumbraReloaded _penumbraReloaded;
|
private readonly PenumbraReloaded _penumbraReloaded;
|
||||||
private readonly IGameInteropProvider _interop;
|
private readonly IGameInteropProvider _interop;
|
||||||
private readonly delegate* unmanaged[Stdcall]<Human*, byte*, bool, bool> _original;
|
private readonly delegate* unmanaged[Stdcall]<Human*, byte*, bool, bool> _original;
|
||||||
|
private readonly Post _postEvent = new();
|
||||||
|
|
||||||
|
|
||||||
/// <summary> Check whether we in a manual customize update, in which case we need to not toggle certain flags. </summary>
|
/// <summary> Check whether we in a manual customize update, in which case we need to not toggle certain flags. </summary>
|
||||||
public static readonly InMethodChecker InUpdate = new();
|
public static readonly InMethodChecker InUpdate = new();
|
||||||
|
|
@ -36,6 +38,7 @@ public unsafe class ChangeCustomizeService : EventWrapperRef2<Model, CustomizeAr
|
||||||
_interop = interop;
|
_interop = interop;
|
||||||
_changeCustomizeHook = Create();
|
_changeCustomizeHook = Create();
|
||||||
_original = Human.MemberFunctionPointers.UpdateDrawData;
|
_original = Human.MemberFunctionPointers.UpdateDrawData;
|
||||||
|
interop.InitializeFromAttributes(this);
|
||||||
_penumbraReloaded.Subscribe(Restore, PenumbraReloaded.Priority.ChangeCustomizeService);
|
_penumbraReloaded.Subscribe(Restore, PenumbraReloaded.Priority.ChangeCustomizeService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,6 +84,23 @@ public unsafe class ChangeCustomizeService : EventWrapperRef2<Model, CustomizeAr
|
||||||
if (!InUpdate.InMethod)
|
if (!InUpdate.InMethod)
|
||||||
Invoke(human, ref *(CustomizeArray*)data);
|
Invoke(human, ref *(CustomizeArray*)data);
|
||||||
|
|
||||||
return _changeCustomizeHook.Original(human, data, skipEquipment);
|
var ret = _changeCustomizeHook.Original(human, data, skipEquipment);
|
||||||
|
_postEvent.Invoke(human);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Subscribe(Action<Model> action, Post.Priority priority)
|
||||||
|
=> _postEvent.Subscribe(action, priority);
|
||||||
|
|
||||||
|
public void Unsubscribe(Action<Model> action)
|
||||||
|
=> _postEvent.Unsubscribe(action);
|
||||||
|
|
||||||
|
public sealed class Post() : EventWrapper<Model, Post.Priority>(nameof(ChangeCustomizeService) + '.' + nameof(Post))
|
||||||
|
{
|
||||||
|
public enum Priority
|
||||||
|
{
|
||||||
|
/// <seealso cref="State.StateListener.OnCustomizeChanged"/>
|
||||||
|
StateListener = 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OtterGui.Log;
|
using OtterGui.Log;
|
||||||
using Penumbra.GameData.Actors;
|
|
||||||
|
|
||||||
namespace Glamourer.Interop.Structs;
|
namespace Glamourer.Interop.Structs;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ using Dalamud.Plugin.Services;
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
|
using Glamourer.GameData;
|
||||||
using Glamourer.Gui;
|
using Glamourer.Gui;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
|
|
@ -500,7 +501,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, EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant, CrestExtensions.All, CustomizeParameterExtensions.All);
|
||||||
_designManager.CreateClone(design, split[0], true);
|
_designManager.CreateClone(design, split[0], true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using Penumbra.GameData.Enums;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Dalamud.Game.ClientState.Conditions;
|
using Dalamud.Game.ClientState.Conditions;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
|
using Glamourer.GameData;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
namespace Glamourer.State;
|
namespace Glamourer.State;
|
||||||
|
|
@ -79,7 +80,11 @@ public class ActorState
|
||||||
/// <summary> This contains whether a change to the base data was made by the game, the user via manual input or through automatic application. </summary>
|
/// <summary> This contains whether a change to the base data was made by the game, the user via manual input or through automatic application. </summary>
|
||||||
private readonly StateChanged.Source[] _sources = Enumerable
|
private readonly StateChanged.Source[] _sources = Enumerable
|
||||||
.Repeat(StateChanged.Source.Game,
|
.Repeat(StateChanged.Source.Game,
|
||||||
EquipFlagExtensions.NumEquipFlags + CustomizationExtensions.NumIndices + 5 + CrestExtensions.AllRelevantSet.Count).ToArray();
|
EquipFlagExtensions.NumEquipFlags
|
||||||
|
+ CustomizationExtensions.NumIndices
|
||||||
|
+ 5
|
||||||
|
+ CrestExtensions.AllRelevantSet.Count
|
||||||
|
+ CustomizeParameterExtensions.AllFlags.Count).ToArray();
|
||||||
|
|
||||||
internal ActorState(ActorIdentifier identifier)
|
internal ActorState(ActorIdentifier identifier)
|
||||||
=> Identifier = identifier.CreatePermanent();
|
=> Identifier = identifier.CreatePermanent();
|
||||||
|
|
@ -96,6 +101,13 @@ public class ActorState
|
||||||
public ref StateChanged.Source this[MetaIndex index]
|
public ref StateChanged.Source this[MetaIndex index]
|
||||||
=> ref _sources[(int)index];
|
=> ref _sources[(int)index];
|
||||||
|
|
||||||
|
public ref StateChanged.Source this[CustomizeParameterFlag flag]
|
||||||
|
=> ref _sources[
|
||||||
|
EquipFlagExtensions.NumEquipFlags
|
||||||
|
+ CustomizationExtensions.NumIndices + 5
|
||||||
|
+ CrestExtensions.AllRelevantSet.Count
|
||||||
|
+ flag.ToInternalIndex()];
|
||||||
|
|
||||||
public void RemoveFixedDesignSources()
|
public void RemoveFixedDesignSources()
|
||||||
{
|
{
|
||||||
for (var i = 0; i < _sources.Length; ++i)
|
for (var i = 0; i < _sources.Length; ++i)
|
||||||
|
|
@ -105,6 +117,9 @@ public class ActorState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CustomizeParameterFlag OnlyChangedParameters()
|
||||||
|
=> CustomizeParameterExtensions.AllFlags.Where(f => this[f] is not StateChanged.Source.Game).Aggregate((CustomizeParameterFlag) 0, (a, b) => a | b);
|
||||||
|
|
||||||
public bool UpdateTerritory(ushort territory)
|
public bool UpdateTerritory(ushort territory)
|
||||||
{
|
{
|
||||||
if (territory == LastTerritory)
|
if (territory == LastTerritory)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using FFXIVClientStructs.FFXIV.Shader;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
|
using Glamourer.GameData;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
using Glamourer.Interop.Penumbra;
|
using Glamourer.Interop.Penumbra;
|
||||||
using Glamourer.Interop.Structs;
|
using Glamourer.Interop.Structs;
|
||||||
|
|
@ -14,8 +16,17 @@ namespace Glamourer.State;
|
||||||
/// This class applies changes made to state to actual objects in the game.
|
/// This class applies changes made to state to actual objects in the game.
|
||||||
/// It handles applying those changes as well as redrawing the actor if necessary.
|
/// It handles applying those changes as well as redrawing the actor if necessary.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class StateApplier(UpdateSlotService _updateSlot, VisorService _visor, WeaponService _weapon, ChangeCustomizeService _changeCustomize,
|
public class StateApplier(
|
||||||
ItemManager _items, PenumbraService _penumbra, MetaService _metaService, ObjectManager _objects, CrestService _crests)
|
UpdateSlotService _updateSlot,
|
||||||
|
VisorService _visor,
|
||||||
|
WeaponService _weapon,
|
||||||
|
ChangeCustomizeService _changeCustomize,
|
||||||
|
ItemManager _items,
|
||||||
|
PenumbraService _penumbra,
|
||||||
|
MetaService _metaService,
|
||||||
|
ObjectManager _objects,
|
||||||
|
CrestService _crests,
|
||||||
|
Configuration _config)
|
||||||
{
|
{
|
||||||
/// <summary> Simply force a redraw regardless of conditions. </summary>
|
/// <summary> Simply force a redraw regardless of conditions. </summary>
|
||||||
public void ForceRedraw(ActorData data)
|
public void ForceRedraw(ActorData data)
|
||||||
|
|
@ -271,6 +282,35 @@ public class StateApplier(UpdateSlotService _updateSlot, VisorService _visor, We
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Change the customize parameters on models. Can change multiple at once. </summary>
|
||||||
|
public unsafe void ChangeParameters(ActorData data, CustomizeParameterFlag flags, in CustomizeParameterData values)
|
||||||
|
{
|
||||||
|
if (!_config.UseAdvancedParameters)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var actor in data.Objects.Where(a => a is { IsCharacter: true, Model.IsHuman: true }))
|
||||||
|
{
|
||||||
|
var buffer = actor.Model.AsHuman->CustomizeParameterCBuffer;
|
||||||
|
if (buffer == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var ptr = (CustomizeParameter*)buffer->UnsafeSourcePointer;
|
||||||
|
if (ptr == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
values.Apply(ref *ptr, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ChangeParameters(ActorData,CustomizeParameterFlag,in CustomizeParameterData)"/>
|
||||||
|
public ActorData ChangeParameters(ActorState state, CustomizeParameterFlag flags, bool apply)
|
||||||
|
{
|
||||||
|
var data = GetData(state);
|
||||||
|
if (apply)
|
||||||
|
ChangeParameters(data, flags, state.ModelData.Parameters);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
private ActorData GetData(ActorState state)
|
private ActorData GetData(ActorState state)
|
||||||
{
|
{
|
||||||
_objects.Update();
|
_objects.Update();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
|
using FFXIVClientStructs.FFXIV.Common.Math;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
|
using Glamourer.GameData;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using Penumbra.GameData.DataContainers;
|
using Penumbra.GameData.DataContainers;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
|
|
@ -11,11 +13,11 @@ namespace Glamourer.State;
|
||||||
|
|
||||||
public class StateEditor
|
public class StateEditor
|
||||||
{
|
{
|
||||||
private readonly ItemManager _items;
|
private readonly ItemManager _items;
|
||||||
private readonly CustomizeService _customizations;
|
private readonly CustomizeService _customizations;
|
||||||
private readonly HumanModelList _humans;
|
private readonly HumanModelList _humans;
|
||||||
private readonly GPoseService _gPose;
|
private readonly GPoseService _gPose;
|
||||||
private readonly ICondition _condition;
|
private readonly ICondition _condition;
|
||||||
|
|
||||||
public StateEditor(CustomizeService customizations, HumanModelList humans, ItemManager items, GPoseService gPose, ICondition condition)
|
public StateEditor(CustomizeService customizations, HumanModelList humans, ItemManager items, GPoseService gPose, ICondition condition)
|
||||||
{
|
{
|
||||||
|
|
@ -208,6 +210,19 @@ public class StateEditor
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Change the customize flags of a character. </summary>
|
||||||
|
public bool ChangeParameter(ActorState state, CustomizeParameterFlag flag, Vector3 value, StateChanged.Source source, out Vector3 oldValue,
|
||||||
|
uint key = 0)
|
||||||
|
{
|
||||||
|
oldValue = state.ModelData.Parameters[flag];
|
||||||
|
if (!state.CanUnlock(key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.ModelData.Parameters.Set(flag, value);
|
||||||
|
state[flag] = source;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool ChangeMetaState(ActorState state, ActorState.MetaIndex index, bool value, StateChanged.Source source, out bool oldValue,
|
public bool ChangeMetaState(ActorState state, ActorState.MetaIndex index, bool value, StateChanged.Source source, out bool oldValue,
|
||||||
uint key = 0)
|
uint key = 0)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,14 @@ using Glamourer.Interop;
|
||||||
using Glamourer.Interop.Penumbra;
|
using Glamourer.Interop.Penumbra;
|
||||||
using Glamourer.Interop.Structs;
|
using Glamourer.Interop.Structs;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using OtterGui.Classes;
|
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using System;
|
using System;
|
||||||
using Dalamud.Game.ClientState.Conditions;
|
using Dalamud.Game.ClientState.Conditions;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
|
using FFXIVClientStructs.FFXIV.Shader;
|
||||||
|
using Glamourer.GameData;
|
||||||
using Penumbra.GameData.DataContainers;
|
using Penumbra.GameData.DataContainers;
|
||||||
|
|
||||||
namespace Glamourer.State;
|
namespace Glamourer.State;
|
||||||
|
|
@ -46,6 +47,7 @@ public class StateListener : IDisposable
|
||||||
|
|
||||||
private ActorIdentifier _creatingIdentifier = ActorIdentifier.Invalid;
|
private ActorIdentifier _creatingIdentifier = ActorIdentifier.Invalid;
|
||||||
private ActorState? _creatingState;
|
private ActorState? _creatingState;
|
||||||
|
private ActorState? _customizeState;
|
||||||
private CharacterWeapon _lastFistOffhand = CharacterWeapon.Empty;
|
private CharacterWeapon _lastFistOffhand = CharacterWeapon.Empty;
|
||||||
|
|
||||||
public StateListener(StateManager manager, ItemManager items, PenumbraService penumbra, ActorManager actors, Configuration config,
|
public StateListener(StateManager manager, ItemManager items, PenumbraService penumbra, ActorManager actors, Configuration config,
|
||||||
|
|
@ -148,10 +150,10 @@ public class StateListener : IDisposable
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!actor.Identifier(_actors, out var identifier)
|
if (!actor.Identifier(_actors, out var identifier)
|
||||||
|| !_manager.TryGetValue(identifier, out var state))
|
|| !_manager.TryGetValue(identifier, out _customizeState))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
UpdateCustomize(actor, state, ref customize, false);
|
UpdateCustomize(actor, _customizeState, ref customize, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateCustomize(Actor actor, ActorState state, ref CustomizeArray customize, bool checkTransform)
|
private void UpdateCustomize(Actor actor, ActorState state, ref CustomizeArray customize, bool checkTransform)
|
||||||
|
|
@ -671,6 +673,7 @@ public class StateListener : IDisposable
|
||||||
_changeCustomizeService.Subscribe(OnCustomizeChange, ChangeCustomizeService.Priority.StateListener);
|
_changeCustomizeService.Subscribe(OnCustomizeChange, ChangeCustomizeService.Priority.StateListener);
|
||||||
_crestService.Subscribe(OnCrestChange, CrestService.Priority.StateListener);
|
_crestService.Subscribe(OnCrestChange, CrestService.Priority.StateListener);
|
||||||
_crestService.ModelCrestSetup += OnModelCrestSetup;
|
_crestService.ModelCrestSetup += OnModelCrestSetup;
|
||||||
|
_changeCustomizeService.Subscribe(OnCustomizeChanged, ChangeCustomizeService.Post.Priority.StateListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Unsubscribe()
|
private void Unsubscribe()
|
||||||
|
|
@ -686,6 +689,7 @@ public class StateListener : IDisposable
|
||||||
_changeCustomizeService.Unsubscribe(OnCustomizeChange);
|
_changeCustomizeService.Unsubscribe(OnCustomizeChange);
|
||||||
_crestService.Unsubscribe(OnCrestChange);
|
_crestService.Unsubscribe(OnCrestChange);
|
||||||
_crestService.ModelCrestSetup -= OnModelCrestSetup;
|
_crestService.ModelCrestSetup -= OnModelCrestSetup;
|
||||||
|
_changeCustomizeService.Unsubscribe(OnCustomizeChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCreatedCharacterBase(nint gameObject, string _, nint drawObject)
|
private void OnCreatedCharacterBase(nint gameObject, string _, nint drawObject)
|
||||||
|
|
@ -700,5 +704,58 @@ public class StateListener : IDisposable
|
||||||
_applier.ChangeHatState(data, _creatingState.ModelData.IsHatVisible());
|
_applier.ChangeHatState(data, _creatingState.ModelData.IsHatVisible());
|
||||||
_applier.ChangeWeaponState(data, _creatingState.ModelData.IsWeaponVisible());
|
_applier.ChangeWeaponState(data, _creatingState.ModelData.IsWeaponVisible());
|
||||||
_applier.ChangeWetness(data, _creatingState.ModelData.IsWet());
|
_applier.ChangeWetness(data, _creatingState.ModelData.IsWet());
|
||||||
|
|
||||||
|
ApplyParameters(_creatingState, drawObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCustomizeChanged(Model model)
|
||||||
|
{
|
||||||
|
if (_customizeState == null)
|
||||||
|
{
|
||||||
|
var actor = _penumbra.GameObjectFromDrawObject(model);
|
||||||
|
if (_condition[ConditionFlag.CreatingCharacter] && actor.Index >= ObjectIndex.CutsceneStart)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!actor.Identifier(_actors, out var identifier)
|
||||||
|
|| !_manager.TryGetValue(identifier, out _customizeState))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplyParameters(_customizeState, model);
|
||||||
|
_customizeState = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe void ApplyParameters(ActorState state, Model model)
|
||||||
|
{
|
||||||
|
if (!model.IsHuman)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var cBuffer = model.AsHuman->CustomizeParameterCBuffer;
|
||||||
|
if (cBuffer == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var ptr = (CustomizeParameter*)cBuffer->UnsafeSourcePointer;
|
||||||
|
if (ptr == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var flag in CustomizeParameterExtensions.AllFlags)
|
||||||
|
{
|
||||||
|
var newValue = CustomizeParameterData.FromParameter(*ptr, flag);
|
||||||
|
|
||||||
|
switch (state[flag])
|
||||||
|
{
|
||||||
|
case StateChanged.Source.Game:
|
||||||
|
case StateChanged.Source.Manual:
|
||||||
|
if (state.BaseData.Parameters.Set(flag, newValue))
|
||||||
|
_manager.ChangeCustomizeParameter(state, flag, newValue, StateChanged.Source.Game);
|
||||||
|
break;
|
||||||
|
case StateChanged.Source.Fixed:
|
||||||
|
case StateChanged.Source.Ipc:
|
||||||
|
state.BaseData.Parameters.Set(flag, newValue);
|
||||||
|
if (_config.UseAdvancedParameters)
|
||||||
|
state.ModelData.Parameters.ApplySingle(ref *ptr, flag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,12 @@ using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
|
using FFXIVClientStructs.FFXIV.Shader;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
|
using Glamourer.GameData;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
using Glamourer.Interop.Structs;
|
using Glamourer.Interop.Structs;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
|
|
@ -189,6 +192,14 @@ public class StateManager(
|
||||||
// Weapon visibility could technically be inferred from the weapon draw objects,
|
// Weapon visibility could technically be inferred from the weapon draw objects,
|
||||||
// but since we use hat visibility from the game object we can also use weapon visibility from it.
|
// but since we use hat visibility from the game object we can also use weapon visibility from it.
|
||||||
ret.SetWeaponVisible(!actor.AsCharacter->DrawData.IsWeaponHidden);
|
ret.SetWeaponVisible(!actor.AsCharacter->DrawData.IsWeaponHidden);
|
||||||
|
|
||||||
|
if (model.IsHuman && model.AsHuman->CustomizeParameterCBuffer != null)
|
||||||
|
{
|
||||||
|
var ptr = model.AsHuman->CustomizeParameterCBuffer->UnsafeSourcePointer;
|
||||||
|
if (ptr != null)
|
||||||
|
ret.Parameters = CustomizeParameterData.FromParameters(*(CustomizeParameter*)ptr);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -309,6 +320,19 @@ public class StateManager(
|
||||||
_event.Invoke(StateChanged.Type.Crest, source, state, actors, (old, crest, slot));
|
_event.Invoke(StateChanged.Type.Crest, source, state, actors, (old, crest, slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Change the crest of an equipment piece. </summary>
|
||||||
|
public void ChangeCustomizeParameter(ActorState state, CustomizeParameterFlag flag, Vector3 value, StateChanged.Source source, uint key = 0)
|
||||||
|
{
|
||||||
|
if (!_editor.ChangeParameter(state, flag, value, source, out var old, key))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var @new = state.ModelData.Parameters[flag];
|
||||||
|
var actors = _applier.ChangeParameters(state, flag, source is StateChanged.Source.Manual or StateChanged.Source.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));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Change hat visibility. </summary>
|
/// <summary> Change hat visibility. </summary>
|
||||||
public void ChangeHatState(ActorState state, bool value, StateChanged.Source source, uint key = 0)
|
public void ChangeHatState(ActorState state, bool value, StateChanged.Source source, uint key = 0)
|
||||||
{
|
{
|
||||||
|
|
@ -390,6 +414,9 @@ public class StateManager(
|
||||||
|
|
||||||
foreach (var slot in CrestExtensions.AllRelevantSet.Where(design.DoApplyCrest))
|
foreach (var slot in CrestExtensions.AllRelevantSet.Where(design.DoApplyCrest))
|
||||||
_editor.ChangeCrest(state, slot, design.DesignData.Crest(slot), source, out _, key);
|
_editor.ChangeCrest(state, slot, design.DesignData.Crest(slot), source, out _, key);
|
||||||
|
|
||||||
|
foreach (var flag in CustomizeParameterExtensions.AllFlags.Where(design.DoApplyParameter))
|
||||||
|
_editor.ChangeParameter(state, flag, design.DesignData.Parameters[flag], source, out _, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
var actors = ApplyAll(state, redraw, false);
|
var actors = ApplyAll(state, redraw, false);
|
||||||
|
|
@ -441,6 +468,7 @@ public class StateManager(
|
||||||
_applier.ChangeWeaponState(actors, state.ModelData.IsWeaponVisible());
|
_applier.ChangeWeaponState(actors, state.ModelData.IsWeaponVisible());
|
||||||
_applier.ChangeVisor(actors, state.ModelData.IsVisorToggled());
|
_applier.ChangeVisor(actors, state.ModelData.IsVisorToggled());
|
||||||
_applier.ChangeCrests(actors, state.ModelData.CrestVisibility);
|
_applier.ChangeCrests(actors, state.ModelData.CrestVisibility);
|
||||||
|
_applier.ChangeParameters(actors, state.OnlyChangedParameters(), state.ModelData.Parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
return actors;
|
return actors;
|
||||||
|
|
@ -454,6 +482,7 @@ public class StateManager(
|
||||||
var redraw = state.ModelData.ModelId != state.BaseData.ModelId
|
var redraw = state.ModelData.ModelId != state.BaseData.ModelId
|
||||||
|| !state.ModelData.IsHuman
|
|| !state.ModelData.IsHuman
|
||||||
|| CustomizeArray.Compare(state.ModelData.Customize, state.BaseData.Customize).RequiresRedraw();
|
|| CustomizeArray.Compare(state.ModelData.Customize, state.BaseData.Customize).RequiresRedraw();
|
||||||
|
|
||||||
state.ModelData = state.BaseData;
|
state.ModelData = state.BaseData;
|
||||||
state.ModelData.SetIsWet(false);
|
state.ModelData.SetIsWet(false);
|
||||||
foreach (var index in Enum.GetValues<CustomizeIndex>())
|
foreach (var index in Enum.GetValues<CustomizeIndex>())
|
||||||
|
|
@ -471,9 +500,13 @@ public class StateManager(
|
||||||
foreach (var slot in CrestExtensions.AllRelevantSet)
|
foreach (var slot in CrestExtensions.AllRelevantSet)
|
||||||
state[slot] = StateChanged.Source.Game;
|
state[slot] = StateChanged.Source.Game;
|
||||||
|
|
||||||
|
foreach (var flag in CustomizeParameterExtensions.AllFlags)
|
||||||
|
state[flag] = StateChanged.Source.Game;
|
||||||
|
|
||||||
var actors = ActorData.Invalid;
|
var actors = ActorData.Invalid;
|
||||||
if (source is StateChanged.Source.Manual or StateChanged.Source.Ipc)
|
if (source is StateChanged.Source.Manual or StateChanged.Source.Ipc)
|
||||||
actors = ApplyAll(state, redraw, true);
|
actors = ApplyAll(state, redraw, true);
|
||||||
|
|
||||||
Glamourer.Log.Verbose(
|
Glamourer.Log.Verbose(
|
||||||
$"Reset entire state of {state.Identifier.Incognito(null)} to game base. [Affecting {actors.ToLazyString("nothing")}.]");
|
$"Reset entire state of {state.Identifier.Incognito(null)} to game base. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||||
_event.Invoke(StateChanged.Type.Reset, StateChanged.Source.Manual, state, actors, null);
|
_event.Invoke(StateChanged.Type.Reset, StateChanged.Source.Manual, state, actors, null);
|
||||||
|
|
@ -514,6 +547,15 @@ public class StateManager(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var flag in CustomizeParameterExtensions.AllFlags)
|
||||||
|
{
|
||||||
|
if (state[flag] is StateChanged.Source.Fixed)
|
||||||
|
{
|
||||||
|
state[flag] = StateChanged.Source.Game;
|
||||||
|
state.ModelData.Parameters[flag] = state.BaseData.Parameters[flag];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (state[ActorState.MetaIndex.HatState] is StateChanged.Source.Fixed)
|
if (state[ActorState.MetaIndex.HatState] is StateChanged.Source.Fixed)
|
||||||
{
|
{
|
||||||
state[ActorState.MetaIndex.HatState] = StateChanged.Source.Game;
|
state[ActorState.MetaIndex.HatState] = StateChanged.Source.Game;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue