mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2026-02-20 14:37:46 +01:00
Remove GlamourerOld.
This commit is contained in:
parent
d621369094
commit
c505286220
75 changed files with 384 additions and 8734 deletions
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}.");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}...");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue