Test state done.

This commit is contained in:
Ottermandias 2023-07-13 00:34:48 +02:00
parent 129f9e070f
commit b37167f2dd
18 changed files with 521 additions and 156 deletions

View file

@ -77,7 +77,11 @@ public partial class GlamourerIpc
continue;
}
_stateManager.ApplyDesign(design, state, StateChanged.Source.Ipc);
if (state.CanUnlock(0xDEADBEEF))
{
_stateManager.ApplyDesign(design, state, StateChanged.Source.Ipc, 0xDEADBEEF);
state.Lock(0xDEADBEEF);
}
}
}
}

View file

@ -31,7 +31,9 @@ public partial class GlamourerIpc
foreach (var id in actors)
{
if (_stateManager.TryGetValue(id, out var state))
_stateManager.ResetState(state);
{
_stateManager.ResetState(state, 0xDEADBEEF);
}
}
}
}

View file

@ -25,6 +25,7 @@ public class Configuration : IPluginConfiguration, ISavable
public bool IncognitoMode { get; set; } = false;
public bool UnlockDetailMode { get; set; } = true;
public bool SkipInvalidCustomizations { get; set; } = false;
public bool HideApplyCheckmarks { get; set; } = false;
public MainWindow.TabType SelectedTab { get; set; } = MainWindow.TabType.Settings;
public DoubleModifier DeleteDesignModifier { get; set; } = new(ModifierHotkey.Control, ModifierHotkey.Shift);

View file

@ -4,6 +4,7 @@ namespace Glamourer.Gui;
public enum ColorId
{
NormalDesign,
CustomizationDesign,
StateDesign,
EquipmentDesign,
@ -25,8 +26,9 @@ public static class Colors
=> color switch
{
// @formatter:off
ColorId.NormalDesign => (0xFFFFFFFF, "Normal Design", "A design with no specific traits." ),
ColorId.CustomizationDesign => (0xFFC000C0, "Customization Design", "A design that only changes customizations on a character." ),
ColorId.StateDesign => (0xFF00C0C0, "State Design", "A design that only changes meta state on a character." ),
ColorId.StateDesign => (0xFF00C0C0, "State Design", "A design that does not change equipment or customizations on a character." ),
ColorId.EquipmentDesign => (0xFF00C000, "Equipment Design", "A design that only changes equipment on a character." ),
ColorId.ActorAvailable => (0xFF18C018, "Actor Available", "The header in the Actor tab panel if the currently selected actor exists in the game world at least once." ),
ColorId.ActorUnavailable => (0xFF1818C0, "Actor Unavailable", "The Header in the Actor tab panel if the currently selected actor does not exist in the game world." ),

View file

@ -39,6 +39,13 @@ public partial class CustomizationDrawer
using (var group = ImRaii.Group())
{
DataInputInt(current);
if (_withApply)
{
ApplyCheckbox();
ImGui.SameLine();
}
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(custom.Color == 0 ? $"{_currentOption} (Custom #{custom.Value})" : _currentOption);
}

View file

@ -1,4 +1,5 @@
using System;
using System.Collections.Specialized;
using System.Linq;
using Dalamud.Interface;
using Glamourer.Customization;
@ -19,6 +20,17 @@ public partial class CustomizationDrawer
DrawRaceCombo();
var gender = _service.AwaitedService.GetName(CustomName.Gender);
var clan = _service.AwaitedService.GetName(CustomName.Clan);
if (_withApply)
{
if (UiHelpers.DrawCheckbox("##applyGender", "Apply gender of this design.", _currentApply, out var applyGender, _locked))
ChangeApply = applyGender ? ChangeApply | CustomizeFlag.Gender : ChangeApply & ~CustomizeFlag.Gender;
ImGui.SameLine();
if (UiHelpers.DrawCheckbox("##applyClan", "Apply clan of this design.", _currentApply, out var applyClan, _locked))
ChangeApply = applyClan ? ChangeApply | CustomizeFlag.Clan : ChangeApply & ~CustomizeFlag.Clan;
ImGui.SameLine();
}
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted($"{gender} & {clan}");
}
@ -32,7 +44,8 @@ public partial class CustomizationDrawer
_ => FontAwesomeIcon.Question,
};
if (!ImGuiUtil.DrawDisabledButton(icon.ToIconString(), _framedIconSize, string.Empty, icon is not FontAwesomeIcon.Mars and not FontAwesomeIcon.Venus, true))
if (!ImGuiUtil.DrawDisabledButton(icon.ToIconString(), _framedIconSize, string.Empty,
icon is not FontAwesomeIcon.Mars and not FontAwesomeIcon.Venus, true))
return;
Changed |= _service.ChangeGender(ref _customize, icon is FontAwesomeIcon.Mars ? Gender.Female : Gender.Male);

View file

@ -39,6 +39,12 @@ public partial class CustomizationDrawer
else
DataInputInt(current);
if (_withApply)
{
ApplyCheckbox();
ImGui.SameLine();
}
ImGui.TextUnformatted($"{label} ({custom.Value.Value})");
}
@ -115,16 +121,45 @@ public partial class CustomizationDrawer
DrawMultiIcons();
ImGui.SameLine();
using var group = ImRaii.Group();
ImGui.Dummy(new Vector2(0, ImGui.GetTextLineHeightWithSpacing() + ImGui.GetStyle().ItemSpacing.Y / 2));
_currentCount = 256;
PercentageInputInt();
if (_withApply)
{
ApplyCheckbox(CustomizeIndex.FacialFeature1);
ImGui.SameLine();
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + _spacing.X);
ApplyCheckbox(CustomizeIndex.FacialFeature2);
ImGui.SameLine();
ApplyCheckbox(CustomizeIndex.FacialFeature3);
ImGui.SameLine();
ApplyCheckbox(CustomizeIndex.FacialFeature4);
}
ImGui.TextUnformatted(_set.Option(CustomizeIndex.LegacyTattoo));
PercentageInputInt();
if (_set.DataByValue(CustomizeIndex.Face, _customize.Face, out _, _customize.Face) < 0)
{
ImGui.SameLine();
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("(Using Face 1)");
}
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + _spacing.Y);
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(_set.Option(CustomizeIndex.LegacyTattoo));
if (_withApply)
{
ApplyCheckbox(CustomizeIndex.FacialFeature5);
ImGui.SameLine();
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + _spacing.X);
ApplyCheckbox(CustomizeIndex.FacialFeature6);
ImGui.SameLine();
ApplyCheckbox(CustomizeIndex.FacialFeature7);
ImGui.SameLine();
ApplyCheckbox(CustomizeIndex.LegacyTattoo);
}
}
private void DrawMultiIcons()
{
var options = _set.Order[CharaMakeParams.MenuType.IconCheckmark];

View file

@ -16,7 +16,14 @@ public partial class CustomizationDrawer
DrawPercentageSlider();
ImGui.SameLine();
PercentageInputInt();
if (_withApply)
{
ImGui.SameLine();
ApplyCheckbox();
}
ImGui.SameLine();
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(_currentOption);
}
@ -60,7 +67,14 @@ public partial class CustomizationDrawer
ListCombo();
ImGui.SameLine();
ListInputInt();
if (_withApply)
{
ImGui.SameLine();
ApplyCheckbox();
}
ImGui.SameLine();
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(_currentOption);
}
@ -93,10 +107,41 @@ public partial class CustomizationDrawer
{
using var id = SetId(idx);
var tmp = _currentByte != CustomizeValue.Zero;
if (ImGui.Checkbox(_currentOption, ref tmp))
if (_withApply)
{
switch (UiHelpers.DrawMetaToggle(_currentOption, string.Empty, tmp, _currentApply, out var newValue, out var newApply, _locked))
{
case DataChange.Item:
ChangeApply = newApply ? ChangeApply | _currentFlag : ChangeApply & ~_currentFlag;
_customize.Set(idx, tmp ? CustomizeValue.Max : CustomizeValue.Zero);
Changed |= _currentFlag;
break;
case DataChange.ApplyItem:
ChangeApply = newApply ? ChangeApply | _currentFlag : ChangeApply & ~_currentFlag;
break;
case DataChange.Item | DataChange.ApplyItem:
_customize.Set(idx, tmp ? CustomizeValue.Max : CustomizeValue.Zero);
Changed |= _currentFlag;
break;
}
}
else if (ImGui.Checkbox(_currentOption, ref tmp))
{
_customize.Set(idx, tmp ? CustomizeValue.Max : CustomizeValue.Zero);
Changed |= _currentFlag;
}
}
private void ApplyCheckbox()
{
if (UiHelpers.DrawCheckbox("##apply", $"Apply the {_currentOption} customization in this design.", _currentApply, out _, _locked))
ToggleApply();
}
private void ApplyCheckbox(CustomizeIndex index)
{
SetId(index);
if (UiHelpers.DrawCheckbox("##apply", $"Apply the {_currentOption} customization in this design.", _currentApply, out _, _locked))
ToggleApply();
}
}

View file

@ -15,6 +15,7 @@ namespace Glamourer.Gui.Customization;
public partial class CustomizationDrawer : IDisposable
{
private readonly CodeService _codes;
private readonly Configuration _config;
private readonly Vector4 _redTint = new(0.6f, 0.3f, 0.3f, 1f);
private readonly ImGuiScene.TextureWrap? _legacyTattoo;
@ -29,23 +30,28 @@ public partial class CustomizationDrawer : IDisposable
public CustomizeFlag CurrentFlag { get; private set; }
public CustomizeFlag Changed { get; private set; }
public CustomizeFlag ChangeApply { get; private set; }
public bool RequiresRedraw
=> Changed.RequiresRedraw();
private bool _locked = false;
private Vector2 _defaultSpacing;
private Vector2 _spacing;
private Vector2 _iconSize;
private Vector2 _framedIconSize;
private float _inputIntSize;
private float _comboSelectorSize;
private float _raceSelectorWidth;
private bool _withApply;
private readonly CustomizationService _service;
public CustomizationDrawer(DalamudPluginInterface pi, CustomizationService service, CodeService codes)
public CustomizationDrawer(DalamudPluginInterface pi, CustomizationService service, CodeService codes, Configuration config)
{
_service = service;
_codes = codes;
_config = config;
_legacyTattoo = GetLegacyTattooIcon(pi);
_customize = Customize.Default;
}
@ -58,6 +64,17 @@ public partial class CustomizationDrawer : IDisposable
public bool Draw(Customize current, bool locked)
{
CurrentFlag = CustomizeFlagExtensions.All;
_withApply = false;
Init(current, locked);
return DrawInternal();
}
public bool Draw(Customize current, CustomizeFlag apply, bool locked)
{
CurrentFlag = CustomizeFlagExtensions.All;
ChangeApply = apply;
_withApply = !_config.HideApplyCheckmarks;
Init(current, locked);
return DrawInternal();
}
@ -75,6 +92,7 @@ public partial class CustomizationDrawer : IDisposable
private CustomizeIndex _currentIndex;
private CustomizeFlag _currentFlag;
private CustomizeValue _currentByte = CustomizeValue.Zero;
private bool _currentApply;
private int _currentCount;
private string _currentOption = string.Empty;
@ -83,6 +101,7 @@ public partial class CustomizationDrawer : IDisposable
{
_currentIndex = index;
_currentFlag = index.ToFlag();
_currentApply = ChangeApply.HasFlag(_currentFlag);
_currentByte = _customize[index];
_currentCount = _set.Count(index, _customize.Face);
_currentOption = _set.Option(index);
@ -99,8 +118,23 @@ public partial class CustomizationDrawer : IDisposable
Changed |= _currentFlag;
}
// Update the current Apply value.
private void ToggleApply()
{
_currentApply = !_currentApply;
ChangeApply = _currentApply ? ChangeApply | _currentFlag : ChangeApply & ~_currentFlag;
}
public bool DrawWetnessState(bool currentValue, out bool newValue, bool locked)
=> UiHelpers.DrawCheckbox("Force Wetness", "Force the character to be wet or not.", currentValue, out newValue, locked);
public DataChange DrawWetnessState(bool currentValue, bool currentApply, out bool newValue, out bool newApply, bool locked)
=> UiHelpers.DrawMetaToggle("Force Wetness", "Change the characters forced wetness state: Disabled, Enabled or Don't Apply.",
currentValue, currentApply, out newValue, out newApply, locked);
private bool DrawInternal()
{
using var spacing = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, _spacing);
using var disabled = ImRaii.Disabled(_locked);
try
@ -124,7 +158,7 @@ public partial class CustomizationDrawer : IDisposable
Functions.IteratePairwise(_set.Order[CharaMakeParams.MenuType.ColorPicker], DrawColorPicker, ImGui.SameLine);
Functions.IteratePairwise(_set.Order[CharaMakeParams.MenuType.Checkmark], DrawCheckbox,
() => ImGui.SameLine(_inputIntSize + _framedIconSize.X + 3 * ImGui.GetStyle().ItemSpacing.X));
() => ImGui.SameLine(_comboSelectorSize - _framedIconSize.X + _spacing.X));
return Changed != 0;
}
catch (Exception ex)
@ -144,9 +178,8 @@ public partial class CustomizationDrawer : IDisposable
using var id = ImRaii.PushId(i);
int value = _customize.Data.Data[i];
ImGui.SetNextItemWidth(40 * ImGuiHelpers.GlobalScale);
if (!ImGui.InputInt(string.Empty, ref value, 0, 0))
continue;
if (ImGui.InputInt(string.Empty, ref value, 0, 0))
{
var newValue = (byte)Math.Clamp(value, 0, byte.MaxValue);
if (newValue != _customize.Data.Data[i])
foreach (var flag in Enum.GetValues<CustomizeIndex>())
@ -158,16 +191,19 @@ public partial class CustomizationDrawer : IDisposable
_customize.Data.Data[i] = newValue;
}
}
return Changed != 0;
}
private void UpdateSizes()
{
_iconSize = new Vector2(ImGui.GetTextLineHeightWithSpacing() * 2);
_defaultSpacing = ImGui.GetStyle().ItemSpacing;
_spacing = ImGui.GetStyle().ItemSpacing with { X = ImGui.GetStyle().ItemInnerSpacing.X };
_iconSize = new Vector2(ImGui.GetTextLineHeight() * 2 + ImGui.GetStyle().ItemSpacing.Y + 2 * ImGui.GetStyle().FramePadding.Y);
_framedIconSize = _iconSize + 2 * ImGui.GetStyle().FramePadding;
_inputIntSize = 2 * _framedIconSize.X + ImGui.GetStyle().ItemSpacing.X;
_comboSelectorSize = 4 * _framedIconSize.X + 3 * ImGui.GetStyle().ItemSpacing.X;
_inputIntSize = 2 * _framedIconSize.X + 1 * _spacing.X;
_comboSelectorSize = 4 * _framedIconSize.X + 3 * _spacing.X;
_raceSelectorWidth = _inputIntSize + _comboSelectorSize - _framedIconSize.X;
}

View file

@ -20,6 +20,8 @@ namespace Glamourer.Gui.Equipment;
public class EquipmentDrawer
{
private const float DefaultWidth = 280;
private readonly ItemManager _items;
private readonly FilterComboColors _stainCombo;
private readonly StainData _stainData;
@ -27,14 +29,16 @@ public class EquipmentDrawer
private readonly Dictionary<FullEquipType, WeaponCombo> _weaponCombo;
private readonly CodeService _codes;
private readonly TextureService _textures;
private readonly Configuration _config;
public EquipmentDrawer(DataManager gameData, ItemManager items, CodeService codes, TextureService textures)
public EquipmentDrawer(DataManager gameData, ItemManager items, CodeService codes, TextureService textures, Configuration config)
{
_items = items;
_codes = codes;
_textures = textures;
_config = config;
_stainData = items.Stains;
_stainCombo = new FilterComboColors(280,
_stainCombo = new FilterComboColors(DefaultWidth - 20,
_stainData.Data.Prepend(new KeyValuePair<byte, (string Name, uint Dye, bool Gloss)>(0, ("None", 0, false))));
_itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(gameData, items, e, textures)).ToArray();
_weaponCombo = new Dictionary<FullEquipType, WeaponCombo>(FullEquipTypeExtensions.WeaponTypes.Count * 2);
@ -55,7 +59,7 @@ public class EquipmentDrawer
public void Prepare()
{
_iconSize = new Vector2(2 * ImGui.GetFrameHeight() + ImGui.GetStyle().ItemSpacing.Y);
_comboLength = 300 * ImGuiHelpers.GlobalScale;
_comboLength = DefaultWidth * ImGuiHelpers.GlobalScale;
}
private bool VerifyRestrictedGear(EquipSlot slot, EquipItem gear, Gender gender, Race race)
@ -67,45 +71,35 @@ public class EquipmentDrawer
return changed;
}
[Flags]
public enum EquipChange : byte
{
None = 0x00,
Item = 0x01,
Stain = 0x02,
ApplyItem = 0x04,
ApplyStain = 0x08,
Item2 = 0x10,
Stain2 = 0x20,
ApplyItem2 = 0x40,
ApplyStain2 = 0x80,
}
public EquipChange DrawEquip(EquipSlot slot, in DesignData designData, out EquipItem rArmor, out StainId rStain, EquipFlag? cApply,
public DataChange DrawEquip(EquipSlot slot, in DesignData designData, out EquipItem rArmor, out StainId rStain, EquipFlag? cApply,
out bool rApply, out bool rApplyStain, bool locked)
=> DrawEquip(slot, designData.Item(slot), out rArmor, designData.Stain(slot), out rStain, cApply, out rApply, out rApplyStain, locked,
designData.Customize.Gender, designData.Customize.Race);
public EquipChange DrawEquip(EquipSlot slot, EquipItem cArmor, out EquipItem rArmor, StainId cStain, out StainId rStain, EquipFlag? cApply,
public DataChange DrawEquip(EquipSlot slot, EquipItem cArmor, out EquipItem rArmor, StainId cStain, out StainId rStain, EquipFlag? cApply,
out bool rApply, out bool rApplyStain, bool locked, Gender gender = Gender.Unknown, Race race = Race.Unknown)
{
if (_config.HideApplyCheckmarks)
cApply = null;
if (!locked && _codes.EnabledArtisan)
return DrawEquipArtisan(slot, cArmor, out rArmor, cStain, out rStain, cApply, out rApply, out rApplyStain);
var spacing = ImGui.GetStyle().ItemInnerSpacing with { Y = ImGui.GetStyle().ItemSpacing.Y };
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing);
var changes = EquipChange.None;
var changes = DataChange.None;
cArmor.DrawIcon(_textures, _iconSize);
ImGui.SameLine();
using var group = ImRaii.Group();
if (DrawItem(slot, cArmor, out rArmor, out var label, locked))
changes |= EquipChange.Item;
changes |= DataChange.Item;
if (cApply.HasValue)
{
ImGui.SameLine();
if (DrawApply(slot, cApply.Value, out rApply, locked))
changes |= EquipChange.ApplyItem;
changes |= DataChange.ApplyItem;
}
else
{
@ -115,12 +109,12 @@ public class EquipmentDrawer
ImGui.SameLine();
ImGui.TextUnformatted(label);
if (DrawStain(slot, cStain, out rStain, locked))
changes |= EquipChange.Stain;
changes |= DataChange.Stain;
if (cApply.HasValue)
{
ImGui.SameLine();
if (DrawApplyStain(slot, cApply.Value, out rApplyStain, locked))
changes |= EquipChange.ApplyStain;
changes |= DataChange.ApplyStain;
}
else
{
@ -136,18 +130,21 @@ public class EquipmentDrawer
return changes;
}
public EquipChange DrawWeapons(in DesignData designData, out EquipItem rMainhand, out EquipItem rOffhand, out StainId rMainhandStain,
public DataChange DrawWeapons(in DesignData designData, out EquipItem rMainhand, out EquipItem rOffhand, out StainId rMainhandStain,
out StainId rOffhandStain, EquipFlag? cApply, out bool rApplyMainhand, out bool rApplyMainhandStain, out bool rApplyOffhand,
out bool rApplyOffhandStain, bool locked)
=> DrawWeapons(designData.Item(EquipSlot.MainHand), out rMainhand, designData.Item(EquipSlot.OffHand), out rOffhand,
designData.Stain(EquipSlot.MainHand), out rMainhandStain, designData.Stain(EquipSlot.OffHand), out rOffhandStain, cApply,
out rApplyMainhand, out rApplyMainhandStain, out rApplyOffhand, out rApplyOffhandStain, locked);
public EquipChange DrawWeapons(EquipItem cMainhand, out EquipItem rMainhand, EquipItem cOffhand, out EquipItem rOffhand,
public DataChange DrawWeapons(EquipItem cMainhand, out EquipItem rMainhand, EquipItem cOffhand, out EquipItem rOffhand,
StainId cMainhandStain, out StainId rMainhandStain, StainId cOffhandStain, out StainId rOffhandStain, EquipFlag? cApply,
out bool rApplyMainhand, out bool rApplyMainhandStain, out bool rApplyOffhand, out bool rApplyOffhandStain, bool locked)
{
var changes = EquipChange.None;
if (_config.HideApplyCheckmarks)
cApply = null;
var changes = DataChange.None;
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing,
ImGui.GetStyle().ItemInnerSpacing with { Y = ImGui.GetStyle().ItemSpacing.Y });
@ -159,11 +156,11 @@ public class EquipmentDrawer
rOffhand = cOffhand;
if (DrawMainhand(cMainhand, cApply.HasValue, out rMainhand, out var mainhandLabel, locked))
{
changes |= EquipChange.Item;
changes |= DataChange.Item;
if (rMainhand.Type.ValidOffhand() != cMainhand.Type.ValidOffhand())
{
rOffhand = _items.GetDefaultOffhand(rMainhand);
changes |= EquipChange.Item2;
changes |= DataChange.Item2;
}
}
@ -171,7 +168,7 @@ public class EquipmentDrawer
{
ImGui.SameLine();
if (DrawApply(EquipSlot.MainHand, cApply.Value, out rApplyMainhand, locked))
changes |= EquipChange.ApplyItem;
changes |= DataChange.ApplyItem;
}
else
{
@ -182,12 +179,12 @@ public class EquipmentDrawer
ImGui.TextUnformatted(mainhandLabel);
if (DrawStain(EquipSlot.MainHand, cMainhandStain, out rMainhandStain, locked))
changes |= EquipChange.Stain;
changes |= DataChange.Stain;
if (cApply.HasValue)
{
ImGui.SameLine();
if (DrawApplyStain(EquipSlot.MainHand, cApply.Value, out rApplyMainhandStain, locked))
changes |= EquipChange.ApplyStain;
changes |= DataChange.ApplyStain;
}
else
{
@ -208,12 +205,12 @@ public class EquipmentDrawer
using (var group = ImRaii.Group())
{
if (DrawOffhand(rMainhand, rOffhand, out rOffhand, out var offhandLabel, locked))
changes |= EquipChange.Item2;
changes |= DataChange.Item2;
if (cApply.HasValue)
{
ImGui.SameLine();
if (DrawApply(EquipSlot.OffHand, cApply.Value, out rApplyOffhand, locked))
changes |= EquipChange.ApplyItem2;
changes |= DataChange.ApplyItem2;
}
else
{
@ -224,12 +221,12 @@ public class EquipmentDrawer
ImGui.TextUnformatted(offhandLabel);
if (DrawStain(EquipSlot.OffHand, cOffhandStain, out rOffhandStain, locked))
changes |= EquipChange.Stain2;
changes |= DataChange.Stain2;
if (cApply.HasValue)
{
ImGui.SameLine();
if (DrawApplyStain(EquipSlot.OffHand, cApply.Value, out rApplyOffhandStain, locked))
changes |= EquipChange.ApplyStain2;
changes |= DataChange.ApplyStain2;
}
else
{
@ -240,8 +237,29 @@ public class EquipmentDrawer
return changes;
}
public bool DrawHatState(bool currentValue, out bool newValue, bool locked)
=> UiHelpers.DrawCheckbox("Hat Visible", "Hide or show the characters head gear.", currentValue, out newValue, locked);
public bool DrawMainhand(EquipItem current, bool drawAll, out EquipItem weapon, out string label, bool locked)
public DataChange DrawHatState(bool currentValue, bool currentApply, out bool newValue, out bool newApply, bool locked)
=> UiHelpers.DrawMetaToggle("Hat Visible", "Change the visibility of the characters head gear: Hidden, Visible or Don't Apply.",
currentValue, currentApply, out newValue, out newApply, locked);
public bool DrawVisorState(bool currentValue, out bool newValue, bool locked)
=> UiHelpers.DrawCheckbox("Visor Toggled", "Toggle the visor state of the characters head gear.", currentValue, out newValue, locked);
public DataChange DrawVisorState(bool currentValue, bool currentApply, out bool newValue, out bool newApply, bool locked)
=> UiHelpers.DrawMetaToggle("Visor Toggled", "Change the toggled state of the characters head gear: Normal, Toggled or Don't Apply.",
currentValue, currentApply, out newValue, out newApply, locked);
public bool DrawWeaponState(bool currentValue, out bool newValue, bool locked)
=> UiHelpers.DrawCheckbox("Weapon Visible", "Hide or show the characters weapons when not drawn.", currentValue, out newValue, locked);
public DataChange DrawWeaponState(bool currentValue, bool currentApply, out bool newValue, out bool newApply, bool locked)
=> UiHelpers.DrawMetaToggle("Weapon Visible",
"Change the visibility of the characters weapons when not drawn: Hidden, Visible or Don't Apply.", currentValue, currentApply,
out newValue, out newApply, locked);
private bool DrawMainhand(EquipItem current, bool drawAll, out EquipItem weapon, out string label, bool locked)
{
weapon = current;
if (!_weaponCombo.TryGetValue(drawAll ? FullEquipType.Unknown : current.Type, out var combo))
@ -259,7 +277,7 @@ public class EquipmentDrawer
return true;
}
public bool DrawOffhand(EquipItem mainhand, EquipItem current, out EquipItem weapon, out string label, bool locked)
private bool DrawOffhand(EquipItem mainhand, EquipItem current, out EquipItem weapon, out string label, bool locked)
{
weapon = current;
if (!_weaponCombo.TryGetValue(current.Type, out var combo))
@ -291,11 +309,11 @@ public class EquipmentDrawer
return change;
}
public bool DrawApply(EquipSlot slot, EquipFlag flags, out bool enabled, bool locked)
private bool DrawApply(EquipSlot slot, EquipFlag flags, out bool enabled, bool locked)
=> UiHelpers.DrawCheckbox($"##apply{slot}", "Apply this item when applying the Design.", flags.HasFlag(slot.ToFlag()), out enabled,
locked);
public bool DrawApplyStain(EquipSlot slot, EquipFlag flags, out bool enabled, bool locked)
private bool DrawApplyStain(EquipSlot slot, EquipFlag flags, out bool enabled, bool locked)
=> UiHelpers.DrawCheckbox($"##applyStain{slot}", "Apply this dye when applying the Design.", flags.HasFlag(slot.ToStainFlag()),
out enabled, locked);
@ -397,23 +415,23 @@ public class EquipmentDrawer
return false;
}
private EquipChange DrawEquipArtisan(EquipSlot slot, EquipItem cArmor, out EquipItem rArmor, StainId cStain, out StainId rStain,
private DataChange DrawEquipArtisan(EquipSlot slot, EquipItem cArmor, out EquipItem rArmor, StainId cStain, out StainId rStain,
EquipFlag? cApply, out bool rApply, out bool rApplyStain)
{
var changes = EquipChange.None;
var changes = DataChange.None;
if (DrawStainArtisan(slot, cStain, out rStain))
changes |= EquipChange.Stain;
changes |= DataChange.Stain;
ImGui.SameLine();
if (DrawArmorArtisan(slot, cArmor, out rArmor))
changes |= EquipChange.Item;
changes |= DataChange.Item;
if (cApply.HasValue)
{
ImGui.SameLine();
if (DrawApply(slot, cApply.Value, out rApply, false))
changes |= EquipChange.ApplyItem;
changes |= DataChange.ApplyItem;
ImGui.SameLine();
if (DrawApplyStain(slot, cApply.Value, out rApplyStain, false))
changes |= EquipChange.ApplyStain;
changes |= DataChange.ApplyStain;
}
else
{

View file

@ -107,46 +107,77 @@ public class ActorPanel
private void DrawHumanPanel()
{
if (_customizationDrawer.Draw(_state!.ModelData.Customize, false))
DrawCustomizationsHeader();
DrawEquipmentHeader();
}
private void DrawCustomizationsHeader()
{
if (!ImGui.CollapsingHeader("Customizations"))
return;
if (_customizationDrawer.Draw(_state!.ModelData.Customize, _state.IsLocked))
_stateManager.ChangeCustomize(_state, _customizationDrawer.Customize, _customizationDrawer.Changed, StateChanged.Source.Manual);
if (_customizationDrawer.DrawWetnessState(_state!.ModelData.IsWet(), out var newWetness, _state.IsLocked))
_stateManager.ChangeWetness(_state, newWetness, StateChanged.Source.Manual);
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
}
private void DrawEquipmentHeader()
{
if (!ImGui.CollapsingHeader("Equipment"))
return;
_equipmentDrawer.Prepare();
foreach (var slot in EquipSlotExtensions.EqdpSlots)
{
var changes = _equipmentDrawer.DrawEquip(slot, _state.ModelData, out var newArmor, out var newStain, null, out _, out _,
var changes = _equipmentDrawer.DrawEquip(slot, _state!.ModelData, out var newArmor, out var newStain, null, out _, out _,
_state.IsLocked);
switch (changes)
{
case EquipmentDrawer.EquipChange.Item:
case DataChange.Item:
_stateManager.ChangeItem(_state, slot, newArmor, StateChanged.Source.Manual);
break;
case EquipmentDrawer.EquipChange.Stain:
case DataChange.Stain:
_stateManager.ChangeStain(_state, slot, newStain, StateChanged.Source.Manual);
break;
case EquipmentDrawer.EquipChange.Item | EquipmentDrawer.EquipChange.Stain:
case DataChange.Item | DataChange.Stain:
_stateManager.ChangeEquip(_state, slot, newArmor, newStain, StateChanged.Source.Manual);
break;
}
}
var weaponChanges = _equipmentDrawer.DrawWeapons(_state.ModelData, out var newMainhand, out var newOffhand, out var newMainhandStain,
var weaponChanges = _equipmentDrawer.DrawWeapons(_state!.ModelData, out var newMainhand, out var newOffhand,
out var newMainhandStain,
out var newOffhandStain, null, out _, out _, out _, out _, _state.IsLocked);
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Item))
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain))
if (weaponChanges.HasFlag(DataChange.Item))
if (weaponChanges.HasFlag(DataChange.Stain))
_stateManager.ChangeEquip(_state, EquipSlot.MainHand, newMainhand, newMainhandStain, StateChanged.Source.Manual);
else
_stateManager.ChangeItem(_state, EquipSlot.MainHand, newMainhand, StateChanged.Source.Manual);
else if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain))
else if (weaponChanges.HasFlag(DataChange.Stain))
_stateManager.ChangeStain(_state, EquipSlot.MainHand, newMainhandStain, StateChanged.Source.Manual);
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Item2))
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain2))
if (weaponChanges.HasFlag(DataChange.Item2))
if (weaponChanges.HasFlag(DataChange.Stain2))
_stateManager.ChangeEquip(_state, EquipSlot.OffHand, newOffhand, newOffhandStain, StateChanged.Source.Manual);
else
_stateManager.ChangeItem(_state, EquipSlot.OffHand, newOffhand, StateChanged.Source.Manual);
else if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain2))
else if (weaponChanges.HasFlag(DataChange.Stain2))
_stateManager.ChangeStain(_state, EquipSlot.OffHand, newOffhandStain, StateChanged.Source.Manual);
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
if (_equipmentDrawer.DrawHatState(_state!.ModelData.IsHatVisible(), out var newHatState, _state!.IsLocked))
_stateManager.ChangeHatState(_state, newHatState, StateChanged.Source.Manual);
ImGui.SameLine();
if (_equipmentDrawer.DrawVisorState(_state!.ModelData.IsVisorToggled(), out var newVisorState, _state!.IsLocked))
_stateManager.ChangeVisorState(_state, newVisorState, StateChanged.Source.Manual);
ImGui.SameLine();
if (_equipmentDrawer.DrawWeaponState(_state!.ModelData.IsWeaponVisible(), out var newWeaponState, _state!.IsLocked))
_stateManager.ChangeWeaponState(_state, newWeaponState, StateChanged.Source.Manual);
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
}
private void DrawMonsterPanel()
@ -217,6 +248,7 @@ public class ActorPanel
Icon = FontAwesomeIcon.Clipboard,
OnClick = SetFromClipboard,
Visible = _state != null,
Disabled = _state?.IsLocked ?? true,
};
private HeaderDrawer.Button ExportToClipboardButton()
@ -301,15 +333,19 @@ public class ActorPanel
private void RevertButtons()
{
if (ImGui.Button("Revert to Game"))
if (ImGuiUtil.DrawDisabledButton("Revert to Game", Vector2.Zero, "Revert the character to its actual state in the game.",
_state!.IsLocked))
_stateManager.ResetState(_state!);
ImGui.SameLine();
if (ImGui.Button("Reapply State"))
if (ImGuiUtil.DrawDisabledButton("Reapply State", Vector2.Zero, "Try to reapply the configured state if something went wrong.",
_state!.IsLocked))
_stateManager.ReapplyState(_actor);
ImGui.SameLine();
if (ImGuiUtil.DrawDisabledButton("Reapply Automation", Vector2.Zero, string.Empty, !_config.EnableAutoDesigns))
if (ImGuiUtil.DrawDisabledButton("Reapply Automation", Vector2.Zero,
"Try to revert the character to the state it would have using automated designs.",
!_config.EnableAutoDesigns || _state!.IsLocked))
{
_autoDesignApplier.ReapplyAutomation(_actor, _identifier, _state!);
_stateManager.ReapplyState(_actor);

View file

@ -1,13 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Game.ClientState.Keys;
using Dalamud.Interface;
using Dalamud.Interface.Internal.Notifications;
using Glamourer.Customization;
using Glamourer.Designs;
using Glamourer.Events;
using ImGuiNET;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Filesystem;
using OtterGui.FileSystem.Selector;
using OtterGui.Raii;
@ -39,7 +41,9 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
=> base.SelectedLeaf;
public struct DesignState
{ }
{
public ColorId Color;
}
public DesignFileSystemSelector(DesignManager designManager, DesignFileSystem fileSystem, KeyState keyState, DesignChanged @event,
Configuration config, DesignConverter converter)
@ -55,6 +59,7 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
AddButton(ImportDesignButton, 10);
AddButton(CloneDesignButton, 20);
AddButton(DeleteButton, 1000);
SetFilterTooltip();
}
protected override void DrawPopups()
@ -66,6 +71,7 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
{
var flag = selected ? ImGuiTreeNodeFlags.Selected | LeafFlags : LeafFlags;
var name = IncognitoMode ? leaf.Value.Incognito : leaf.Value.Name.Text;
using var color = ImRaii.PushColor(ImGuiCol.Text, state.Color.Value());
using var _ = ImRaii.TreeNode(name, flag);
}
@ -103,6 +109,8 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
case DesignChanged.Type.RemovedMod:
case DesignChanged.Type.Created:
case DesignChanged.Type.Deleted:
case DesignChanged.Type.ApplyCustomize:
case DesignChanged.Type.ApplyEquip:
SetFilterDirty();
break;
}
@ -188,4 +196,91 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
_newName = string.Empty;
}
#region Filters
private const StringComparison IgnoreCase = StringComparison.OrdinalIgnoreCase;
private LowerString _designFilter = LowerString.Empty;
private int _filterType = -1;
private void SetFilterTooltip()
{
FilterTooltip = "Filter designs for those where their full paths or names contain the given substring.\n"
+ "Enter m:[string] to filter for designs with with a mod association containing the string.\n"
+ "Enter t:[string] to filter for designs set to specific tags.\n"
+ "Enter n:[string] to filter only for design names and no paths.";
}
/// <summary> Appropriately identify and set the string filter and its type. </summary>
protected override bool ChangeFilter(string filterValue)
{
(_designFilter, _filterType) = filterValue.Length switch
{
0 => (LowerString.Empty, -1),
> 1 when filterValue[1] == ':' =>
filterValue[0] switch
{
'n' => filterValue.Length == 2 ? (LowerString.Empty, -1) : (new LowerString(filterValue[2..]), 1),
'N' => filterValue.Length == 2 ? (LowerString.Empty, -1) : (new LowerString(filterValue[2..]), 1),
'm' => filterValue.Length == 2 ? (LowerString.Empty, -1) : (new LowerString(filterValue[2..]), 2),
'M' => filterValue.Length == 2 ? (LowerString.Empty, -1) : (new LowerString(filterValue[2..]), 2),
't' => filterValue.Length == 2 ? (LowerString.Empty, -1) : (new LowerString(filterValue[2..]), 3),
'T' => filterValue.Length == 2 ? (LowerString.Empty, -1) : (new LowerString(filterValue[2..]), 3),
_ => (new LowerString(filterValue), 0),
},
_ => (new LowerString(filterValue), 0),
};
return true;
}
/// <summary>
/// The overwritten filter method also computes the state.
/// Folders have default state and are filtered out on the direct string instead of the other options.
/// If any filter is set, they should be hidden by default unless their children are visible,
/// or they contain the path search string.
/// </summary>
protected override bool ApplyFiltersAndState(FileSystem<Design>.IPath path, out DesignState state)
{
if (path is DesignFileSystem.Folder f)
{
state = default;
return FilterValue.Length > 0 && !f.FullName().Contains(FilterValue, IgnoreCase);
}
return ApplyFiltersAndState((DesignFileSystem.Leaf)path, out state);
}
/// <summary> Apply the string filters. </summary>
private bool ApplyStringFilters(DesignFileSystem.Leaf leaf, Design design)
{
return _filterType switch
{
-1 => false,
0 => !(_designFilter.IsContained(leaf.FullName()) || design.Name.Contains(_designFilter)),
1 => !design.Name.Contains(_designFilter),
2 => !design.AssociatedMods.Any(kvp => _designFilter.IsContained(kvp.Key.Name)),
3 => !design.Tags.Any(_designFilter.IsContained),
_ => false, // Should never happen
};
}
/// <summary> Combined wrapper for handling all filters and setting state. </summary>
private bool ApplyFiltersAndState(DesignFileSystem.Leaf leaf, out DesignState state)
{
var applyEquip = leaf.Value.ApplyEquip != 0;
var applyCustomize = (leaf.Value.ApplyCustomize & ~(CustomizeFlag.BodyType | CustomizeFlag.Race)) != 0;
state.Color = (applyEquip, applyCustomize) switch
{
(false, false) => ColorId.StateDesign,
(false, true) => ColorId.CustomizationDesign,
(true, false) => ColorId.EquipmentDesign,
(true, true) => ColorId.NormalDesign,
};
return ApplyStringFilters(leaf, leaf.Value);
}
#endregion
}

View file

@ -95,36 +95,6 @@ public class DesignPanel
private string SelectionName
=> _selector.Selected == null ? "No Selection" : _selector.IncognitoMode ? _selector.Selected.Incognito : _selector.Selected.Name.Text;
private void DrawMetaData()
{
if (!ImGui.CollapsingHeader("MetaData"))
return;
using (var group1 = ImRaii.Group())
{
var apply = _selector.Selected!.DesignData.IsHatVisible();
if (ImGui.Checkbox("Hat Visible", ref apply))
_manager.ChangeMeta(_selector.Selected, ActorState.MetaIndex.HatState, apply);
apply = _selector.Selected.DesignData.IsWeaponVisible();
if (ImGui.Checkbox("Weapon Visible", ref apply))
_manager.ChangeMeta(_selector.Selected, ActorState.MetaIndex.WeaponState, apply);
}
ImGui.SameLine(ImGui.GetContentRegionAvail().X / 2);
using (var group2 = ImRaii.Group())
{
var apply = _selector.Selected.DesignData.IsVisorToggled();
if (ImGui.Checkbox("Visor Toggled", ref apply))
_manager.ChangeMeta(_selector.Selected, ActorState.MetaIndex.VisorState, apply);
apply = _selector.Selected.DesignData.IsWet();
if (ImGui.Checkbox("Force Wetness", ref apply))
_manager.ChangeMeta(_selector.Selected, ActorState.MetaIndex.Wetness, apply);
}
}
private void DrawEquipment()
{
if (!ImGui.CollapsingHeader("Equipment"))
@ -135,41 +105,82 @@ public class DesignPanel
{
var changes = _equipmentDrawer.DrawEquip(slot, _selector.Selected!.DesignData, out var newArmor, out var newStain,
_selector.Selected.ApplyEquip, out var newApply, out var newApplyStain, _selector.Selected!.WriteProtected());
if (changes.HasFlag(EquipmentDrawer.EquipChange.Item))
if (changes.HasFlag(DataChange.Item))
_manager.ChangeEquip(_selector.Selected, slot, newArmor);
if (changes.HasFlag(EquipmentDrawer.EquipChange.Stain))
if (changes.HasFlag(DataChange.Stain))
_manager.ChangeStain(_selector.Selected, slot, newStain);
if (changes.HasFlag(EquipmentDrawer.EquipChange.ApplyItem))
if (changes.HasFlag(DataChange.ApplyItem))
_manager.ChangeApplyEquip(_selector.Selected, slot, newApply);
if (changes.HasFlag(EquipmentDrawer.EquipChange.ApplyStain))
if (changes.HasFlag(DataChange.ApplyStain))
_manager.ChangeApplyStain(_selector.Selected, slot, newApplyStain);
}
var weaponChanges = _equipmentDrawer.DrawWeapons(_selector.Selected!.DesignData, out var newMainhand, out var newOffhand,
out var newMainhandStain, out var newOffhandStain, _selector.Selected.ApplyEquip, out var applyMain, out var applyMainStain,
out var applyOff, out var applyOffStain, _selector.Selected!.WriteProtected());
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Item))
if (weaponChanges.HasFlag(DataChange.Item))
_manager.ChangeWeapon(_selector.Selected, EquipSlot.MainHand, newMainhand);
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain))
if (weaponChanges.HasFlag(DataChange.Stain))
_manager.ChangeStain(_selector.Selected, EquipSlot.MainHand, newMainhandStain);
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.ApplyItem))
if (weaponChanges.HasFlag(DataChange.ApplyItem))
_manager.ChangeApplyEquip(_selector.Selected, EquipSlot.MainHand, applyMain);
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.ApplyStain))
if (weaponChanges.HasFlag(DataChange.ApplyStain))
_manager.ChangeApplyStain(_selector.Selected, EquipSlot.MainHand, applyMainStain);
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Item2))
if (weaponChanges.HasFlag(DataChange.Item2))
_manager.ChangeWeapon(_selector.Selected, EquipSlot.OffHand, newOffhand);
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain2))
if (weaponChanges.HasFlag(DataChange.Stain2))
_manager.ChangeStain(_selector.Selected, EquipSlot.OffHand, newOffhandStain);
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.ApplyItem2))
if (weaponChanges.HasFlag(DataChange.ApplyItem2))
_manager.ChangeApplyEquip(_selector.Selected, EquipSlot.OffHand, applyOff);
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.ApplyStain2))
if (weaponChanges.HasFlag(DataChange.ApplyStain2))
_manager.ChangeApplyStain(_selector.Selected, EquipSlot.OffHand, applyOffStain);
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
DrawEquipmentMetaToggles();
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
}
private void DrawEquipmentMetaToggles()
{
var hatChanges = _equipmentDrawer.DrawHatState(_selector.Selected!.DesignData.IsHatVisible(),
_selector.Selected.DoApplyHatVisible(),
out var newHatState, out var newHatApply, _selector.Selected.WriteProtected());
ApplyChanges(ActorState.MetaIndex.HatState, hatChanges, newHatState, newHatApply);
ImGui.SameLine();
var visorChanges = _equipmentDrawer.DrawVisorState(_selector.Selected!.DesignData.IsVisorToggled(),
_selector.Selected.DoApplyVisorToggle(),
out var newVisorState, out var newVisorApply, _selector.Selected.WriteProtected());
ApplyChanges(ActorState.MetaIndex.VisorState, visorChanges, newVisorState, newVisorApply);
ImGui.SameLine();
var weaponChanges = _equipmentDrawer.DrawWeaponState(_selector.Selected!.DesignData.IsWeaponVisible(),
_selector.Selected.DoApplyWeaponVisible(),
out var newWeaponState, out var newWeaponApply, _selector.Selected.WriteProtected());
ApplyChanges(ActorState.MetaIndex.WeaponState, weaponChanges, newWeaponState, newWeaponApply);
}
private void DrawCustomize()
{
if (ImGui.CollapsingHeader("Customization"))
_customizationDrawer.Draw(_selector.Selected!.DesignData.Customize, _selector.Selected!.WriteProtected());
if (!ImGui.CollapsingHeader("Customization"))
return;
_customizationDrawer.Draw(_selector.Selected!.DesignData.Customize, _selector.Selected.ApplyCustomize,
_selector.Selected!.WriteProtected());
if (_customizationDrawer.ChangeApply != _selector.Selected.ApplyCustomize)
foreach (var idx in Enum.GetValues<CustomizeIndex>())
{
var flag = idx.ToFlag();
var newValue = _customizationDrawer.ChangeApply.HasFlag(flag);
_manager.ChangeApplyCustomize(_selector.Selected, idx, newValue);
}
var wetnessChanges = _customizationDrawer.DrawWetnessState(_selector.Selected!.DesignData.IsWet(),
_selector.Selected!.DoApplyWetness(), out var newWetnessState, out var newWetnessApply, _selector.Selected!.WriteProtected());
ApplyChanges(ActorState.MetaIndex.Wetness, wetnessChanges, newWetnessState, newWetnessApply);
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
}
private void DrawApplicationRules()
@ -285,7 +296,6 @@ public class DesignPanel
return;
DrawButtonRow();
DrawMetaData();
DrawCustomize();
DrawEquipment();
_designDetails.Draw();
@ -354,4 +364,21 @@ public class DesignPanel
if (_state.GetOrCreate(id, data.Objects[0], out var state))
_state.ApplyDesign(_selector.Selected!, state, StateChanged.Source.Manual);
}
private void ApplyChanges(ActorState.MetaIndex index, DataChange change, bool value, bool apply)
{
switch (change)
{
case DataChange.Item:
_manager.ChangeMeta(_selector.Selected!, index, value);
break;
case DataChange.ApplyItem:
_manager.ChangeApplyMeta(_selector.Selected!, index, apply);
break;
case DataChange.Item | DataChange.ApplyItem:
_manager.ChangeApplyMeta(_selector.Selected!, index, apply);
_manager.ChangeMeta(_selector.Selected!, index, value);
break;
}
}
}

View file

@ -54,6 +54,10 @@ public class SettingsTab : ITab
Checkbox("Auto-Reload Gear",
"Automatically reload equipment pieces on your own character when changing any mod options in Penumbra in their associated collection.",
_config.AutoRedrawEquipOnChanges, _autoRedraw.SetState);
Checkbox("Hide Application Checkboxes",
"Hide the application checkboxes in the Customization and Equipment panels of the design tab, and only show them under Application Rules.",
_config.HideApplyCheckmarks, v => _config.HideApplyCheckmarks = v);
if (Widget.DoubleModifierSelector("Design Deletion Modifier",
"A modifier you need to hold while clicking the Delete Design button for it to take effect.", 100 * ImGuiHelpers.GlobalScale,
_config.DeleteDesignModifier, v => _config.DeleteDesignModifier = v))

View file

@ -1,3 +1,4 @@
using System;
using System.Numerics;
using Dalamud.Interface;
using Glamourer.Services;
@ -8,6 +9,20 @@ using Penumbra.GameData.Structs;
namespace Glamourer.Gui;
[Flags]
public enum DataChange : byte
{
None = 0x00,
Item = 0x01,
Stain = 0x02,
ApplyItem = 0x04,
ApplyStain = 0x08,
Item2 = 0x10,
Stain2 = 0x20,
ApplyItem2 = 0x40,
ApplyStain2 = 0x80,
}
public static class UiHelpers
{
public static void DrawIcon(this EquipItem item, TextureService textures, Vector2 size)
@ -40,15 +55,32 @@ public static class UiHelpers
return ret;
}
public static bool DrawVisor(bool current, out bool on, bool locked)
=> DrawCheckbox("##visorToggled", string.Empty, current, out on, locked);
public static DataChange DrawMetaToggle(string label, string tooltip, bool currentValue, bool currentApply, out bool newValue, out bool newApply,
bool locked)
{
var flags = currentApply ? currentValue ? 3 : 0 : 2;
bool ret;
using (var disabled = ImRaii.Disabled(locked))
{
ret = ImGui.CheckboxFlags(label, ref flags, 3);
}
public static bool DrawHat(bool current, out bool on, bool locked)
=> DrawCheckbox("##hatVisible", string.Empty, current, out on, locked);
ImGuiUtil.HoverTooltip(tooltip);
public static bool DrawWeapon(bool current, out bool on, bool locked)
=> DrawCheckbox("##weaponVisible", string.Empty, current, out on, locked);
if (ret)
{
(newValue, newApply, var change) = (currentValue, currentApply) switch
{
(false, false) => (false, true, DataChange.ApplyItem),
(false, true) => (true, true, DataChange.Item),
(true, false) => (false, false, DataChange.Item), // Should not happen
(true, true) => (false, false, DataChange.Item | DataChange.ApplyItem),
};
return change;
}
public static bool DrawWetness(bool current, out bool on, bool locked)
=> DrawCheckbox("##wetness", string.Empty, current, out on, locked);
newValue = currentValue;
newApply = currentApply;
return DataChange.None;
}
}

View file

@ -59,7 +59,7 @@ public unsafe class WeaponService : IDisposable
_loadWeaponHook.Original(drawData, slot, weapon.Value, redrawOnEquality, unk2, skipGameObject, unk4);
if (tmpWeapon.Value != weapon.Value)
_loadWeaponHook.Original(drawData, slot, tmpWeapon.Value, 1, unk2, 1, unk4);
Glamourer.Log.Information(
Glamourer.Log.Excessive(
$"Weapon reloaded for 0x{actor.Address:X} ({actor.Utf8Name}) with attributes {slot} {weapon.Value:X14}, {redrawOnEquality}, {unk2}, {skipGameObject}, {unk4}");
}

View file

@ -165,10 +165,10 @@ public class StateEditor
{
(var setter, oldValue) = index switch
{
ActorState.MetaIndex.Wetness => ((Func<bool, bool>)state.ModelData.SetIsWet, state.ModelData.IsWet()),
ActorState.MetaIndex.HatState => ((Func<bool, bool>)state.ModelData.SetHatVisible, state.ModelData.IsHatVisible()),
ActorState.MetaIndex.VisorState => ((Func<bool, bool>)state.ModelData.SetVisor, state.ModelData.IsVisorToggled()),
ActorState.MetaIndex.WeaponState => ((Func<bool, bool>)state.ModelData.SetWeaponVisible, state.ModelData.IsWeaponVisible()),
ActorState.MetaIndex.Wetness => ((Func<bool, bool>) (v => state.ModelData.SetIsWet(v)), state.ModelData.IsWet()),
ActorState.MetaIndex.HatState => ((Func<bool, bool>) (v => state.ModelData.SetHatVisible(v)), state.ModelData.IsHatVisible()),
ActorState.MetaIndex.VisorState => ((Func<bool, bool>) (v => state.ModelData.SetVisor(v)), state.ModelData.IsVisorToggled()),
ActorState.MetaIndex.WeaponState => ((Func<bool, bool>) (v => state.ModelData.SetWeaponVisible(v)), state.ModelData.IsWeaponVisible()),
_ => throw new Exception("Invalid MetaIndex."),
};

View file

@ -116,7 +116,7 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
if (!_humans.IsHuman((uint)actor.AsCharacter->CharacterData.ModelCharaId))
{
ret.LoadNonHuman((uint)actor.AsCharacter->CharacterData.ModelCharaId, *(Customize*)&actor.AsCharacter->DrawData.CustomizeData,
(nint) (&actor.AsCharacter->DrawData.Head));
(nint)(&actor.AsCharacter->DrawData.Head));
return ret;
}
@ -320,7 +320,7 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
if (!_editor.ChangeMetaState(state, ActorState.MetaIndex.Wetness, value, source, out var old, key))
return;
var actors = _applier.ChangeVisor(state, true);
var actors = _applier.ChangeWetness(state, true);
Glamourer.Log.Verbose(
$"Set Wetness in state {state.Identifier.Incognito(null)} from {old} to {value}. [Affecting {actors.ToLazyString("nothing")}.]");
_event.Invoke(StateChanged.Type.Other, state[ActorState.MetaIndex.Wetness], state, actors, (old, value, ActorState.MetaIndex.Wetness));
@ -382,21 +382,29 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
else
{
_applier.ChangeCustomize(actors, state.ModelData.Customize);
_applier.ChangeHatState(actors, state.ModelData.IsHatVisible());
_applier.ChangeWeaponState(actors, state.ModelData.IsWeaponVisible());
_applier.ChangeVisor(actors, state.ModelData.IsVisorToggled());
foreach (var slot in EquipSlotExtensions.EqdpSlots)
_applier.ChangeArmor(actors, slot, state.ModelData.Armor(slot), state.ModelData.IsHatVisible());
foreach (var slot in EquipSlotExtensions.WeaponSlots)
_applier.ChangeWeapon(actors, slot, state.ModelData.Item(slot), state.ModelData.Stain(slot));
}
if (state.ModelData.IsHuman)
{
_applier.ChangeHatState(actors, state.ModelData.IsHatVisible());
_applier.ChangeWeaponState(actors, state.ModelData.IsWeaponVisible());
_applier.ChangeVisor(actors, state.ModelData.IsVisorToggled());
}
return actors;
}
public void ResetState(ActorState state)
public void ResetState(ActorState state, uint key = 0)
{
var redraw = state.ModelData.ModelId != state.BaseData.ModelId || !state.ModelData.IsHuman
if (!state.Unlock(key))
return;
var redraw = state.ModelData.ModelId != state.BaseData.ModelId
|| !state.ModelData.IsHuman
|| Customize.Compare(state.ModelData.Customize, state.BaseData.Customize).RequiresRedraw();
state.ModelData = state.BaseData;
foreach (var index in Enum.GetValues<CustomizeIndex>())