Remove GlamourerOld.

This commit is contained in:
Ottermandias 2023-06-29 15:05:17 +02:00
parent d621369094
commit c505286220
75 changed files with 384 additions and 8734 deletions

View file

@ -25,6 +25,14 @@ public class AutoDesign
public JobGroup Jobs;
public Type ApplicationType;
public AutoDesign Clone()
=> new()
{
Design = Design,
ApplicationType = ApplicationType,
Jobs = Jobs,
};
public unsafe bool IsActive(Actor actor)
=> actor.IsCharacter && Jobs.Fits(actor.AsCharacter->CharacterData.ClassJob);

View file

@ -1,5 +1,6 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Security.AccessControl;
using Glamourer.Customization;
using Glamourer.Designs;
using Glamourer.Events;
@ -8,6 +9,8 @@ using Glamourer.Interop.Structs;
using Glamourer.Services;
using Glamourer.State;
using Glamourer.Structs;
using Lumina.Excel.GeneratedSheets;
using Newtonsoft.Json.Linq;
using Penumbra.GameData.Actors;
using Penumbra.GameData.Enums;
@ -46,13 +49,19 @@ public class AutoDesignApplier : IDisposable
if (!_config.EnableAutoDesigns || !actor.Identifier(_actors.AwaitedService, out var id))
return;
if (!_manager.EnabledSets.TryGetValue(id, out var set))
if (!GetPlayerSet(id, out var set))
{
if (_state.TryGetValue(id, out var s))
s.LastJob = actor.Job;
return;
}
if (!_state.GetOrCreate(id, actor, out var state))
return;
Reduce(actor, state, set);
var sameJob = state.LastJob == actor.Job;
state.LastJob = actor.Job;
Reduce(actor, state, set, sameJob);
_state.ReapplyState(actor);
}
@ -63,15 +72,15 @@ public class AutoDesignApplier : IDisposable
if (!GetPlayerSet(identifier, out var set))
return;
Reduce(actor, state, set);
Reduce(actor, state, set, true);
}
private unsafe void Reduce(Actor actor, ActorState state, AutoDesignSet set)
private unsafe void Reduce(Actor actor, ActorState state, AutoDesignSet set, bool respectManual)
{
EquipFlag totalEquipFlags = 0;
//var totalCustomizeFlags = _phrasing.Phrasing2 ? 0 : CustomizeFlagExtensions.RedrawRequired;
var totalCustomizeFlags = CustomizeFlagExtensions.RedrawRequired;
byte totalMetaFlags = 0;
EquipFlag totalEquipFlags = 0;
var totalCustomizeFlags = _phrasing.Phrasing2 ? 0 : CustomizeFlagExtensions.RedrawRequired;
byte totalMetaFlags = 0;
foreach (var design in set.Designs)
{
if (!design.IsActive(actor))
@ -84,9 +93,9 @@ public class AutoDesignApplier : IDisposable
continue;
var (equipFlags, customizeFlags, applyHat, applyVisor, applyWeapon, applyWet) = design.ApplyWhat();
Reduce(state, in design.Design.DesignData, equipFlags, ref totalEquipFlags);
Reduce(state, in design.Design.DesignData, customizeFlags, ref totalCustomizeFlags);
Reduce(state, in design.Design.DesignData, applyHat, applyVisor, applyWeapon, applyWet, ref totalMetaFlags);
Reduce(state, in design.Design.DesignData, equipFlags, ref totalEquipFlags, respectManual);
Reduce(state, in design.Design.DesignData, customizeFlags, ref totalCustomizeFlags, respectManual);
Reduce(state, in design.Design.DesignData, applyHat, applyVisor, applyWeapon, applyWet, ref totalMetaFlags, respectManual);
}
}
@ -103,7 +112,7 @@ public class AutoDesignApplier : IDisposable
return _manager.EnabledSets.TryGetValue(identifier, out set);
}
private void Reduce(ActorState state, in DesignData design, EquipFlag equipFlags, ref EquipFlag totalEquipFlags)
private void Reduce(ActorState state, in DesignData design, EquipFlag equipFlags, ref EquipFlag totalEquipFlags, bool respectManual)
{
equipFlags &= ~totalEquipFlags;
if (equipFlags == 0)
@ -115,14 +124,16 @@ public class AutoDesignApplier : IDisposable
var flag = slot.ToFlag();
if (equipFlags.HasFlag(flag))
{
_state.ChangeItem(state, slot, design.Item(slot), StateChanged.Source.Fixed);
if (!respectManual || state[slot, false] is not StateChanged.Source.Manual)
_state.ChangeItem(state, slot, design.Item(slot), StateChanged.Source.Fixed);
totalEquipFlags |= flag;
}
var stainFlag = slot.ToStainFlag();
if (equipFlags.HasFlag(stainFlag))
{
_state.ChangeStain(state, slot, design.Stain(slot), StateChanged.Source.Fixed);
if (!respectManual || state[slot, true] is not StateChanged.Source.Manual)
_state.ChangeStain(state, slot, design.Stain(slot), StateChanged.Source.Fixed);
totalEquipFlags |= stainFlag;
}
}
@ -132,7 +143,8 @@ public class AutoDesignApplier : IDisposable
var item = design.Item(EquipSlot.MainHand);
if (state.ModelData.Item(EquipSlot.MainHand).Type == item.Type)
{
_state.ChangeItem(state, EquipSlot.MainHand, item, StateChanged.Source.Fixed);
if (!respectManual || state[EquipSlot.MainHand, false] is not StateChanged.Source.Manual)
_state.ChangeItem(state, EquipSlot.MainHand, item, StateChanged.Source.Fixed);
totalEquipFlags |= EquipFlag.Mainhand;
}
}
@ -142,31 +154,63 @@ public class AutoDesignApplier : IDisposable
var item = design.Item(EquipSlot.OffHand);
if (state.ModelData.Item(EquipSlot.OffHand).Type == item.Type)
{
_state.ChangeItem(state, EquipSlot.OffHand, item, StateChanged.Source.Fixed);
if (!respectManual || state[EquipSlot.OffHand, false] is not StateChanged.Source.Manual)
_state.ChangeItem(state, EquipSlot.OffHand, item, StateChanged.Source.Fixed);
totalEquipFlags |= EquipFlag.Offhand;
}
}
if (equipFlags.HasFlag(EquipFlag.MainhandStain))
{
_state.ChangeStain(state, EquipSlot.MainHand, design.Stain(EquipSlot.MainHand), StateChanged.Source.Fixed);
if (!respectManual || state[EquipSlot.MainHand, true] is not StateChanged.Source.Manual)
_state.ChangeStain(state, EquipSlot.MainHand, design.Stain(EquipSlot.MainHand), StateChanged.Source.Fixed);
totalEquipFlags |= EquipFlag.MainhandStain;
}
if (equipFlags.HasFlag(EquipFlag.OffhandStain))
{
_state.ChangeStain(state, EquipSlot.OffHand, design.Stain(EquipSlot.OffHand), StateChanged.Source.Fixed);
if (!respectManual || state[EquipSlot.OffHand, true] is not StateChanged.Source.Manual)
_state.ChangeStain(state, EquipSlot.OffHand, design.Stain(EquipSlot.OffHand), StateChanged.Source.Fixed);
totalEquipFlags |= EquipFlag.OffhandStain;
}
}
private void Reduce(ActorState state, in DesignData design, CustomizeFlag customizeFlags, ref CustomizeFlag totalCustomizeFlags)
private void Reduce(ActorState state, in DesignData design, CustomizeFlag customizeFlags, ref CustomizeFlag totalCustomizeFlags,
bool respectManual)
{
customizeFlags &= ~totalCustomizeFlags;
if (customizeFlags == 0)
return;
// TODO add race/gender handling
var customize = state.ModelData.Customize;
CustomizeFlag fixFlags = 0;
if (customizeFlags.HasFlag(CustomizeFlag.Clan))
{
if (!respectManual || state[CustomizeIndex.Clan] is not StateChanged.Source.Manual)
fixFlags |= _customizations.ChangeClan(ref customize, design.Customize.Clan);
customizeFlags &= ~(CustomizeFlag.Clan | CustomizeFlag.Race);
totalCustomizeFlags |= CustomizeFlag.Clan | CustomizeFlag.Race;
}
if (customizeFlags.HasFlag(CustomizeFlag.Gender))
{
if (!respectManual || state[CustomizeIndex.Gender] is not StateChanged.Source.Manual)
fixFlags |= _customizations.ChangeGender(ref customize, design.Customize.Gender);
customizeFlags &= ~CustomizeFlag.Gender;
totalCustomizeFlags |= CustomizeFlag.Gender;
}
if (fixFlags != 0)
_state.ChangeCustomize(state, customize, fixFlags, StateChanged.Source.Fixed);
if (customizeFlags.HasFlag(CustomizeFlag.Face))
{
if (!respectManual || state[CustomizeIndex.Face] is not StateChanged.Source.Manual)
_state.ChangeCustomize(state, CustomizeIndex.Face, design.Customize.Face, StateChanged.Source.Fixed);
customizeFlags &= ~CustomizeFlag.Face;
totalCustomizeFlags |= CustomizeFlag.Face;
}
var set = _customizations.AwaitedService.GetList(state.ModelData.Customize.Clan, state.ModelData.Customize.Gender);
var face = state.ModelData.Customize.Face;
foreach (var index in Enum.GetValues<CustomizeIndex>())
@ -178,36 +222,41 @@ public class AutoDesignApplier : IDisposable
var value = design.Customize[index];
if (CustomizationService.IsCustomizationValid(set, face, index, value))
{
_state.ChangeCustomize(state, index, value, StateChanged.Source.Fixed);
if (!respectManual || state[index] is not StateChanged.Source.Manual)
_state.ChangeCustomize(state, index, value, StateChanged.Source.Fixed);
totalCustomizeFlags |= flag;
}
}
}
private void Reduce(ActorState state, in DesignData design, bool applyHat, bool applyVisor, bool applyWeapon, bool applyWet,
ref byte totalMetaFlags)
ref byte totalMetaFlags, bool respectManual)
{
if (applyHat && (totalMetaFlags & 0x01) == 0)
{
_state.ChangeHatState(state, design.IsHatVisible(), StateChanged.Source.Fixed);
if (!respectManual || state[ActorState.MetaFlag.HatState] is not StateChanged.Source.Manual)
_state.ChangeHatState(state, design.IsHatVisible(), StateChanged.Source.Fixed);
totalMetaFlags |= 0x01;
}
if (applyVisor && (totalMetaFlags & 0x02) == 0)
{
_state.ChangeVisorState(state, design.IsVisorToggled(), StateChanged.Source.Fixed);
if (!respectManual || state[ActorState.MetaFlag.VisorState] is not StateChanged.Source.Manual)
_state.ChangeVisorState(state, design.IsVisorToggled(), StateChanged.Source.Fixed);
totalMetaFlags |= 0x02;
}
if (applyWeapon && (totalMetaFlags & 0x04) == 0)
{
_state.ChangeWeaponState(state, design.IsWeaponVisible(), StateChanged.Source.Fixed);
if (!respectManual || state[ActorState.MetaFlag.WeaponState] is not StateChanged.Source.Manual)
_state.ChangeWeaponState(state, design.IsWeaponVisible(), StateChanged.Source.Fixed);
totalMetaFlags |= 0x04;
}
if (applyWet && (totalMetaFlags & 0x08) == 0)
{
_state.ChangeWetness(state, design.IsWet(), StateChanged.Source.Fixed);
if (!respectManual || state[ActorState.MetaFlag.Wetness] is not StateChanged.Source.Manual)
_state.ChangeWetness(state, design.IsWet(), StateChanged.Source.Fixed);
totalMetaFlags |= 0x08;
}
}

View file

@ -3,6 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Utility;
using Glamourer.Designs;
@ -66,7 +67,32 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
var newSet = new AutoDesignSet(name, identifier.CreatePermanent()) { Enabled = false };
_data.Add(newSet);
Save();
Glamourer.Log.Debug($"Created new design set for {identifier.Incognito(null)}.");
Glamourer.Log.Debug($"Created new design set for {newSet.Identifier.Incognito(null)}.");
_event.Invoke(AutomationChanged.Type.AddedSet, newSet, (_data.Count - 1, name));
}
public void DuplicateDesignSet(AutoDesignSet set)
{
var name = set.Name;
var match = Regex.Match(name, @"\(Duplicate( (?<Number>\d+))?\)$",
RegexOptions.Compiled | RegexOptions.NonBacktracking | RegexOptions.ExplicitCapture);
if (match.Success)
{
var number = match.Groups["Number"];
var replacement = number.Success ? $"(Duplicate {int.Parse(number.Value) + 1})" : "(Duplicate 2)";
name = name.Replace(match.Value, replacement);
}
else
{
name += " (Duplicate)";
}
var newSet = new AutoDesignSet(name, set.Identifier) { Enabled = false };
newSet.Designs.AddRange(set.Designs.Select(d => d.Clone()));
_data.Add(newSet);
Save();
Glamourer.Log.Debug(
$"Duplicated new design set for {newSet.Identifier.Incognito(null)} with {newSet.Designs.Count} auto designs from existing set.");
_event.Invoke(AutomationChanged.Type.AddedSet, newSet, (_data.Count - 1, name));
}
@ -82,6 +108,7 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
_enabled.Remove(set.Identifier);
}
_data.RemoveAt(whichSet);
Save();
Glamourer.Log.Debug($"Deleted design set {whichSet + 1}.");
_event.Invoke(AutomationChanged.Type.DeletedSet, set, whichSet);
@ -156,6 +183,10 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
oldEnabled.Enabled = false;
_enabled.Add(set.Identifier, set);
}
else
{
_enabled.Remove(set.Identifier, out oldEnabled);
}
Save();
Glamourer.Log.Debug($"Changed enabled state of design set {whichSet + 1} to {value}.");

View file

@ -14,6 +14,8 @@ public enum ColorId
FolderLine,
EnabledAutoSet,
DisabledAutoSet,
AutomationActorAvailable,
AutomationActorUnavailable,
}
public static class Colors
@ -22,17 +24,19 @@ public static class Colors
=> color switch
{
// @formatter:off
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.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." ),
ColorId.FolderExpanded => (0xFFFFF0C0, "Expanded Design Folder", "A design folder that is currently expanded." ),
ColorId.FolderCollapsed => (0xFFFFF0C0, "Collapsed Design Folder", "A design folder that is currently collapsed." ),
ColorId.FolderLine => (0xFFFFF0C0, "Expanded Design Folder Line", "The line signifying which descendants belong to an expanded design folder." ),
ColorId.EnabledAutoSet => (0xFFA0F0A0, "Enabled Automation Set", "An automation set that is currently enabled. Only one set can be enabled for each identifier at once." ),
ColorId.DisabledAutoSet => (0xFF808080, "Disabled Automation Set", "An automation set that is currently disabled." ),
_ => (0x00000000, string.Empty, string.Empty ),
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.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." ),
ColorId.FolderExpanded => (0xFFFFF0C0, "Expanded Design Folder", "A design folder that is currently expanded." ),
ColorId.FolderCollapsed => (0xFFFFF0C0, "Collapsed Design Folder", "A design folder that is currently collapsed." ),
ColorId.FolderLine => (0xFFFFF0C0, "Expanded Design Folder Line", "The line signifying which descendants belong to an expanded design folder." ),
ColorId.EnabledAutoSet => (0xFFA0F0A0, "Enabled Automation Set", "An automation set that is currently enabled. Only one set can be enabled for each identifier at once." ),
ColorId.DisabledAutoSet => (0xFF808080, "Disabled Automation Set", "An automation set that is currently disabled." ),
ColorId.AutomationActorAvailable => (0xFFFFFFFF, "Automation Actor Available", "A character associated with the given automated design set is currently visible." ),
ColorId.AutomationActorUnavailable => (0xFF808080, "Automation Actor Unavailable", "No character associated with the given automated design set is currently visible." ),
_ => (0x00000000, string.Empty, string.Empty ),
// @formatter:on
};

View file

@ -5,9 +5,12 @@ using System.Numerics;
using Dalamud.Interface;
using Glamourer.Automation;
using Glamourer.Designs;
using Glamourer.Interop;
using Glamourer.Structs;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using OtterGui.Widgets;
namespace Glamourer.Gui.Tabs.AutomationTab;
@ -16,10 +19,20 @@ public class SetPanel
private readonly AutoDesignManager _manager;
private readonly SetSelector _selector;
public SetPanel(SetSelector selector, AutoDesignManager manager)
private readonly DesignCombo _designCombo;
private readonly JobGroupCombo _jobGroupCombo;
private string? _tempName;
private int _dragIndex = -1;
private Action? _endAction;
public SetPanel(SetSelector selector, AutoDesignManager manager, DesignManager designs, JobService jobs)
{
_selector = selector;
_manager = manager;
_selector = selector;
_manager = manager;
_designCombo = new DesignCombo(_manager, designs);
_jobGroupCombo = new JobGroupCombo(manager, jobs);
}
private AutoDesignSet Selection
@ -43,8 +56,6 @@ public class SetPanel
ImGuiUtil.DrawTextButton(Selection.Name, -Vector2.UnitX, buttonColor);
}
private string? _tempName;
private void DrawPanel()
{
using var child = ImRaii.Child("##SetPanel", -Vector2.One, true);
@ -66,47 +77,84 @@ public class SetPanel
if (ImGui.Checkbox("Enabled", ref enabled))
_manager.SetState(_selector.SelectionIndex, enabled);
using var table = ImRaii.Table("SetTable", 4, ImGuiTableFlags.RowBg);
DrawDesignTable();
}
private void DrawDesignTable()
{
using var table = ImRaii.Table("SetTable", 5, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX | ImGuiTableFlags.ScrollY);
if (!table)
return;
ImGui.TableSetupColumn("##Index", ImGuiTableColumnFlags.WidthFixed, 40 * ImGuiHelpers.GlobalScale);
ImGui.TableSetupColumn("Design", ImGuiTableColumnFlags.WidthFixed, 200 * ImGuiHelpers.GlobalScale);
ImGui.TableSetupColumn("##del", ImGuiTableColumnFlags.WidthFixed, ImGui.GetFrameHeight());
ImGui.TableSetupColumn("##Index", ImGuiTableColumnFlags.WidthFixed, 30 * ImGuiHelpers.GlobalScale);
ImGui.TableSetupColumn("Design", ImGuiTableColumnFlags.WidthFixed, 220 * ImGuiHelpers.GlobalScale);
ImGui.TableSetupColumn("Application", ImGuiTableColumnFlags.WidthFixed, 5 * ImGui.GetFrameHeight() + 4 * 2 * ImGuiHelpers.GlobalScale);
ImGui.TableSetupColumn("Job Restrictions", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableHeadersRow();
foreach (var (design, idx) in Selection.Designs.WithIndex())
{
ImGuiUtil.DrawTableColumn($"#{idx:D2}");
using var id = ImRaii.PushId(idx);
ImGui.TableNextColumn();
DrawDesignCombo(Selection, design, idx);
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), new Vector2(ImGui.GetFrameHeight()),
"Remove this design from the set.", false, true))
_endAction = () => _manager.DeleteDesign(Selection, idx);
ImGui.TableNextColumn();
ImGui.Selectable($"#{idx + 1:D2}");
DrawDragDrop(Selection, idx);
ImGui.TableNextColumn();
DrawJobGroupCombo(Selection, design, idx);
_designCombo.Draw(Selection, design, idx);
DrawDragDrop(Selection, idx);
ImGui.TableNextColumn();
DrawApplicationTypeBoxes(Selection, design, idx);
ImGui.TableNextColumn();
_jobGroupCombo.Draw(Selection, design, idx);
}
ImGui.TableNextColumn();
ImGui.TableNextColumn();
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("New");
ImGui.TableNextColumn();
_designCombo.Draw(Selection, null, -1);
ImGui.TableNextColumn();
ImGui.TableNextColumn();
_endAction?.Invoke();
_endAction = null;
}
private void DrawDesignCombo(AutoDesignSet set, AutoDesign design, int autoDesignIndex)
private void DrawDragDrop(AutoDesignSet set, int index)
{
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
using var combo = ImRaii.Combo("##design", design.Design.Name);
if (!combo)
return;
}
const string dragDropLabel = "DesignDragDrop";
using (var target = ImRaii.DragDropTarget())
{
if (target.Success && ImGuiUtil.IsDropping(dragDropLabel))
{
if (_dragIndex >= 0)
{
var idx = _dragIndex;
_endAction = () => _manager.MoveDesign(set, idx, index);
}
private void DrawJobGroupCombo(AutoDesignSet set, AutoDesign design, int autoDesignIndex)
{
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X);
using var combo = ImRaii.Combo("##JobGroups", design.Jobs.Name);
if (!combo)
return;
_dragIndex = -1;
}
}
using (var source = ImRaii.DragDropSource())
{
if (source.Success && ImGui.SetDragDropPayload(dragDropLabel, nint.Zero, 0))
{
_dragIndex = index;
ImGui.TextUnformatted($"Moving design #{index + 1:D2}...");
}
}
}
private void DrawApplicationTypeBoxes(AutoDesignSet set, AutoDesign design, int autoDesignIndex)
{
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, 2 * ImGuiHelpers.GlobalScale);
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(2 * ImGuiHelpers.GlobalScale));
var newType = design.ApplicationType;
foreach (var (type, description) in Types)
{
@ -114,7 +162,10 @@ public class SetPanel
if (ImGui.Checkbox($"##{(byte)type}", ref value))
newType = value ? newType | type : newType & ~type;
ImGuiUtil.HoverTooltip(description);
ImGui.SameLine();
}
_manager.ChangeApplicationType(set, autoDesignIndex, newType);
}
private static readonly IReadOnlyList<(AutoDesign.Type, string)> Types = new[]
@ -126,4 +177,64 @@ public class SetPanel
(AutoDesign.Type.Stains, "Apply all dye changes that are enabled in this design."),
(AutoDesign.Type.Weapons, "Apply all weapon changes that are enabled in this design and that are valid with the current weapon worn."),
};
private sealed class JobGroupCombo : FilterComboCache<JobGroup>
{
private readonly AutoDesignManager _manager;
private readonly JobService _jobs;
public JobGroupCombo(AutoDesignManager manager, JobService jobs)
: base(() => jobs.JobGroups.Values.ToList())
{
_manager = manager;
_jobs = jobs;
}
public void Draw(AutoDesignSet set, AutoDesign design, int autoDesignIndex)
{
CurrentSelection = design.Jobs;
CurrentSelectionIdx = _jobs.JobGroups.Values.IndexOf(j => j.Id == design.Jobs.Id);
if (Draw("##JobGroups", design.Jobs.Name,
"Select for which job groups this design should be applied.\nControl + Right-Click to set to all classes.",
ImGui.GetContentRegionAvail().X, ImGui.GetTextLineHeight())
&& CurrentSelectionIdx >= 0)
_manager.ChangeJobCondition(set, autoDesignIndex, CurrentSelection);
else if (ImGui.GetIO().KeyCtrl && ImGui.IsItemClicked(ImGuiMouseButton.Right))
_manager.ChangeJobCondition(set, autoDesignIndex, _jobs.JobGroups[1]);
}
protected override string ToString(JobGroup obj)
=> obj.Name;
}
private sealed class DesignCombo : FilterComboCache<Design>
{
private readonly AutoDesignManager _manager;
private readonly DesignManager _designs;
public DesignCombo(AutoDesignManager manager, DesignManager designs)
: base(() => designs.Designs.OrderBy(d => d.Name).ToList())
{
_designs = designs;
_manager = manager;
}
public void Draw(AutoDesignSet set, AutoDesign? design, int autoDesignIndex)
{
CurrentSelection = design?.Design ?? (Items.Count > 0 ? Items[0] : null);
CurrentSelectionIdx = design?.Design.Index ?? (Items.Count > 0 ? 0 : -1);
if (Draw("##design", CurrentSelection?.Name.Text ?? string.Empty, string.Empty, 220 * ImGuiHelpers.GlobalScale,
ImGui.GetTextLineHeight())
&& CurrentSelection != null)
{
if (autoDesignIndex >= 0)
_manager.ChangeDesign(set, autoDesignIndex, CurrentSelection);
else
_manager.AddDesign(set, CurrentSelection);
}
}
protected override string ToString(Design obj)
=> obj.Name.Text;
}
}

View file

@ -1,31 +1,44 @@
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Linq;
using System.Text.RegularExpressions;
using Dalamud.Interface;
using Glamourer.Automation;
using Glamourer.Events;
using Glamourer.Interop;
using Glamourer.Services;
using ImGuiNET;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using Penumbra.String;
using Vector2 = FFXIVClientStructs.FFXIV.Common.Math.Vector2;
namespace Glamourer.Gui.Tabs.AutomationTab;
public class SetSelector : IDisposable
{
private readonly AutoDesignManager _manager;
private readonly AutomationChanged _event;
public AutoDesignSet? Selection { get; private set; }
public int SelectionIndex = -1;
private bool IncognitoMode;
private readonly Configuration _config;
private readonly AutoDesignManager _manager;
private readonly AutomationChanged _event;
private readonly ActorService _actors;
private readonly ObjectManager _objects;
private readonly List<AutoDesignSet> _list = new();
public SetSelector(AutoDesignManager manager, AutomationChanged @event)
public AutoDesignSet? Selection { get; private set; }
public int SelectionIndex { get; private set; } = -1;
private bool IncognitoMode;
private int _dragIndex = -1;
private Action? _endAction;
public SetSelector(AutoDesignManager manager, AutomationChanged @event, Configuration config, ActorService actors, ObjectManager objects)
{
_manager = manager;
_event = @event;
_config = config;
_actors = actors;
_objects = objects;
_event.Subscribe(OnAutomationChanged, AutomationChanged.Priority.SetSelector);
}
@ -41,13 +54,17 @@ public class SetSelector : IDisposable
case AutomationChanged.Type.DeletedSet:
if (set == Selection)
{
Selection = null;
SelectionIndex = -1;
SelectionIndex = _manager.Count == 0 ? -1 : SelectionIndex == 0 ? 0 : SelectionIndex - 1;
Selection = SelectionIndex >= 0 ? _manager[SelectionIndex] : null;
}
_dirty = true;
break;
case AutomationChanged.Type.AddedSet:
SelectionIndex = (((int, string))data!).Item1;
Selection = set!;
_dirty = true;
break;
case AutomationChanged.Type.RenamedSet:
case AutomationChanged.Type.MovedSet:
case AutomationChanged.Type.ChangeIdentifier:
@ -109,6 +126,7 @@ public class SetSelector : IDisposable
_dirty = true;
ImGui.SameLine();
var f = _enabledFilter;
if (ImGui.CheckboxFlags("##enabledFilter", ref f, 3))
{
_enabledFilter = _enabledFilter switch
@ -120,6 +138,11 @@ public class SetSelector : IDisposable
_dirty = true;
}
var pos = ImGui.GetItemRectMin();
pos.X -= ImGuiHelpers.GlobalScale;
ImGui.GetWindowDrawList().AddLine(pos, pos with { Y = ImGui.GetItemRectMax().Y }, ImGui.GetColorU32(ImGuiCol.Border),
ImGuiHelpers.GlobalScale);
ImGuiUtil.HoverTooltip("Filter to show only enabled or disabled sets.");
DrawSelector();
@ -135,7 +158,10 @@ public class SetSelector : IDisposable
UpdateList();
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, _defaultItemSpacing);
_selectableSize = new Vector2(0, 2 * ImGui.GetTextLineHeight() + ImGui.GetStyle().ItemSpacing.Y);
_objects.Update();
ImGuiClip.ClippedDraw(_list, DrawSetSelectable, _selectableSize.Y + 2 * ImGui.GetStyle().ItemSpacing.Y);
_endAction?.Invoke();
_endAction = null;
}
private void DrawSetSelectable(AutoDesignSet set, int index)
@ -150,22 +176,84 @@ public class SetSelector : IDisposable
}
}
DrawDragDrop(set, index);
var text = set.Identifier.ToString();
if (IncognitoMode)
text = set.Identifier.Incognito(text);
var textSize = ImGui.CalcTextSize(text);
var textSize = ImGui.CalcTextSize(text);
var textColor = _objects.ContainsKey(set.Identifier) ? ColorId.AutomationActorAvailable : ColorId.AutomationActorUnavailable;
ImGui.SetCursorPos(new Vector2(ImGui.GetContentRegionAvail().X - textSize.X,
ImGui.GetCursorPosY() - ImGui.GetTextLineHeightWithSpacing()));
ImGui.TextUnformatted(text);
ImGuiUtil.TextColored(textColor.Value(), text);
}
private void DrawSelectionButtons()
{
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
var buttonWidth = new Vector2(_width / 1, 0);
// TODO
ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.UserCircle.ToIconString(), buttonWidth
, "Select the local player character.", true, true);
var buttonWidth = new Vector2(_width / 3, 0);
NewSetButton(buttonWidth);
ImGui.SameLine();
DuplicateSetButton(buttonWidth);
ImGui.SameLine();
DeleteSetButton(buttonWidth);
}
private void NewSetButton(Vector2 size)
{
var id = _actors.AwaitedService.GetCurrentPlayer();
if (!id.IsValid)
id = _actors.AwaitedService.CreatePlayer(ByteString.FromSpanUnsafe("New Design"u8, true, false, true), ushort.MaxValue);
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), size,
$"Create a new Automatic Design Set for {id}. The associated player can be changed later.", !id.IsValid, true))
_manager.AddDesignSet("New Design", id);
}
private void DuplicateSetButton(Vector2 size)
{
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clone.ToIconString(), size, "Duplicate the current Automatic Design Set.",
Selection == null, true))
_manager.DuplicateDesignSet(Selection!);
}
private void DeleteSetButton(Vector2 size)
{
var keyValid = _config.DeleteDesignModifier.IsActive();
var (disabled, tt) = HasSelection
? keyValid
? (false, "Delete the currently selected design set.")
: (true, $"Delete the currently selected design set.\n{_config.DeleteDesignModifier.ToString()}")
: (true, "No Automatic Design Set selected.");
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), size, tt, disabled, true))
_manager.DeleteDesignSet(SelectionIndex);
}
private void DrawDragDrop(AutoDesignSet set, int index)
{
const string dragDropLabel = "DesignSetDragDrop";
using (var target = ImRaii.DragDropTarget())
{
if (target.Success && ImGuiUtil.IsDropping(dragDropLabel))
{
if (_dragIndex >= 0)
{
var idx = _dragIndex;
_endAction = () => _manager.MoveSet(idx, index);
}
_dragIndex = -1;
}
}
using (var source = ImRaii.DragDropSource())
{
if (source.Success && ImGui.SetDragDropPayload(dragDropLabel, nint.Zero, 0))
{
_dragIndex = index;
ImGui.TextUnformatted($"Moving design set {set.Name} from position {index + 1}...");
}
}
}
}

View file

@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Dalamud.Game;
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Objects;
@ -133,8 +134,11 @@ public class ObjectManager : IReadOnlyDictionary<ActorIdentifier, ActorData>
public int Count
=> Identifiers.Count;
/// <summary> Also (inefficiently) handles All Worlds players. </summary>
public bool ContainsKey(ActorIdentifier key)
=> Identifiers.ContainsKey(key);
=> Identifiers.ContainsKey(key)
|| key.HomeWorld == ushort.MaxValue
&& Identifiers.Keys.FirstOrDefault(i => i.Type is IdentifierType.Player && i.PlayerName == key.PlayerName).IsValid;
public bool TryGetValue(ActorIdentifier key, out ActorData value)
=> Identifiers.TryGetValue(key, out value);

View file

@ -67,6 +67,9 @@ public readonly unsafe struct Actor : IEquatable<Actor>
public Model Model
=> Valid ? AsObject->DrawObject : null;
public byte Job
=> IsCharacter ? AsCharacter->CharacterData.ClassJob : (byte)0;
public static implicit operator bool(Actor actor)
=> actor.Address != nint.Zero;

View file

@ -29,6 +29,9 @@ public class ActorState
/// <summary> This should be the desired state of the draw object. </summary>
public DesignData ModelData;
/// <summary> The last seen job. </summary>
public byte LastJob;
/// <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
.Repeat(StateChanged.Source.Game, EquipFlagExtensions.NumEquipFlags + CustomizationExtensions.NumIndices + 5).ToArray();

View file

@ -68,7 +68,7 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
=> GetOrCreate(actor.GetIdentifier(_actors.AwaitedService), actor, out state);
/// <summary> Try to obtain or create a new state for an existing actor. Returns false if no state could be created. </summary>
public bool GetOrCreate(ActorIdentifier identifier, Actor actor, [NotNullWhen(true)] out ActorState? state)
public unsafe bool GetOrCreate(ActorIdentifier identifier, Actor actor, [NotNullWhen(true)] out ActorState? state)
{
if (TryGetValue(identifier, out state))
return true;
@ -81,6 +81,7 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
{
ModelData = FromActor(actor, true),
BaseData = FromActor(actor, false),
LastJob = (byte) (actor.IsCharacter ? actor.AsCharacter->CharacterData.ClassJob : 0),
};
// state.Identifier is owned.
_states.Add(state.Identifier, state);